Skip to content

fix(my_egeria): serve_my_* page URLs follow the browser's address - #419

Merged
dwolfson merged 1 commit into
odpi:mainfrom
dwolfson:fix/serve-public-url-per-request
Oct 3, 2026
Merged

dwolfson merged 1 commit into
odpi:mainfrom
dwolfson:fix/serve-public-url-per-request

Conversation

@dwolfson

@dwolfson dwolfson commented Oct 3, 2026

Copy link
Copy Markdown
Member

Summary

Makes serve_my_profile / serve_my_egeria work from any hostname, so one container serves localhost, the machine's name and a demo site alike.

The problem: textual-serve builds every asset and WebSocket URL in the page from one fixed public_url. The egeria-workspaces portal is configured for https://laz.local:8843/my-egeria. A browser that reached it as https://localhost:8843 was sent to another origin; the page's CSP blocked the script, and My Profile showed only its title.

The fix: a textual_serve.Server subclass whose handle_index computes the base URL per request.

  • Behind a proxy (X-Forwarded-Host or X-Forwarded-For):
    • host: the first valid X-Forwarded-Host entry, else Host;
    • scheme: X-Forwarded-Proto, else the configured public URL's scheme;
    • path: the configured public URL's path (/my-egeria).
  • Direct connection: the request's own scheme and host. Previously textual-serve pointed browsers at 0.0.0.0.
  • Why skip invalid entries: egeria-workspaces' Apache actually sends X-Forwarded-Host: i=99, localhost:8843, from a misconfigured RequestHeader line. That's been reported to that repo.
  • Concurrency: Server.handle_index builds its URLs synchronously, so swapping public_url for the duration of one request can't interleave with another.

Docs: the handoff doc, integration doc and My Profile manual now explain that only the path and scheme come from MY_EGERIA_PUBLIC_URL.

Testing

  • New tests/micro-tests/test_my_egeria_serve.py: serves real textual-serve pages through aiohttp's test server and fetches them as localhost, laz.local, a demo hostname, IPv6, direct connections, and the exact junk header Apache sends. Plain textual-serve fails the localhost case. The full tests/micro-tests suite passes.
  • Live, in the portal's quickstart-my-profile container (with this serve.py): both https://localhost:8843 and https://laz.local:8843 get same-origin URLs, load textual.js, and render My Profile's welcome screen over the WebSocket, with no errors.

🤖 Generated with Claude Code

textual-serve builds every asset and WebSocket URL in the page from one
fixed public_url. With the egeria-workspaces portal configured for
https://laz.local:8843/my-egeria, a browser that reached it as
https://localhost:8843 was pointed at another origin; the page's CSP
blocked the script and My Profile showed only its title. So one container
could only work from one hostname -- not workable for localhost plus a
demo site.

serve_my_profile / serve_my_egeria now use a Server subclass whose
handle_index computes the base URL per request:
- behind a proxy (X-Forwarded-Host/-For): host = first *valid*
  X-Forwarded-Host entry, else Host; scheme = X-Forwarded-Proto, else the
  configured public URL's; path = the configured public URL's (/my-egeria)
- direct connection: the request's own scheme and host (previously
  textual-serve pointed browsers at 0.0.0.0)
Skipping invalid entries matters: egeria-workspaces' Apache sends
"X-Forwarded-Host: i=99, localhost:8843" (a misconfigured RequestHeader,
reported to that repo).

Verified in the live portal container: localhost and laz.local each get
same-origin URLs, load the script and render My Profile over the WebSocket.
Tests run real textual-serve pages through aiohttp's test server; plain
textual-serve fails the localhost case.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
@dwolfson
dwolfson merged commit a1b4b70 into odpi:main Oct 3, 2026
5 checks passed
dwolfson added a commit that referenced this pull request Oct 3, 2026
Release carrying the serve_my_profile / serve_my_egeria fix (#419): page
asset and WebSocket URLs follow the browser's address, so one portal
container works from localhost, the machine name and a demo hostname. Also
picks up the dependency updates merged after 6.1.26 (tornado, pyjwt,
urllib3, notebook).

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
@dwolfson
dwolfson deleted the fix/serve-public-url-per-request branch October 3, 2026 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant