Skip to content

Stop the frontend from naming the address it is served from - #43

Merged
antoinevalentinHA merged 2 commits into
antoinevalentinHA:masterfrom
lgnap:feat/relative-frontend-addresses
Sep 5, 2026
Merged

Stop the frontend from naming the address it is served from#43
antoinevalentinHA merged 2 commits into
antoinevalentinHA:masterfrom
lgnap:feat/relative-frontend-addresses

Conversation

@lgnap

@lgnap lgnap commented Sep 5, 2026

Copy link
Copy Markdown

Hello — first contribution here, so please tell me if any of this cuts across how you want the project to go.

This removes the twenty places where the frontend writes http://localhost:8080 and makes them relative, so the web UI addresses whatever origin served it instead of a host and port baked into the bundle.

It touches one paragraph of your reasoning, which is why I am asking rather than just proposing.

What is in it

  • The three service modules, the i18n load path and the favicon in index.html become relative.
  • The event bus cannot. sockjs-client validates its URL and rejects one with no host and no protocol, so '/eventbus' throws at construction; it derives an absolute URL from window.location.origin instead. Worth noting the existing tests would not have caught that — eventBusChannel.test.js drives a fake transport, not the real client.
  • proxy in package.json plus a .env.development keep yarn start working: the CRA dev server serves from :3000, cannot proxy the SockJS connection, and would otherwise break the dev loop. Neither file affects a packaged build.

The paragraph I had to rewrite, and the question

MainVerticle.listenHost() argues:

Nothing is lost by restricting it, because remote use was never possible. The web UI [...] addresses it as http://localhost:8080, hardcoded throughout the frontend, so a browser on another machine would receive the page and then send every request to its own loopback.

That was exactly right, and this change makes it false — the frontend no longer hardcodes anything, so remote use would work if the socket bound wider. You anticipated this:

the day remote access is genuinely wanted it will mean changing the frontend's addresses too — which is when this decision should be revisited, not before.

I have rewritten the paragraph to state the current facts while keeping your conclusion: the loopback stays, and the reason becomes the plainer one — the API has no authentication, so a wider binding hands it to anyone on the segment. I deliberately did not change the binding itself. Please rewrite that javadoc however you prefer; I was trying not to leave a comment in the tree that says something untrue, not to argue the point through it.

The question: would you be open to a follow-up making the listen address configurable — something like -Dstudio.host / -Dstudio.port, defaulting to the loopback exactly as now?

I had written that (with tests) before seeing your fix, and dropped it in favour of yours, which I think is the right call for this PR. But the capability argument against it was the frontend, and that is what this removes. If your answer is "not until the API authenticates", that is a good answer and I will drop it for good rather than keep proposing it — I would just rather ask than assume.

Checks

284 Java tests and 57 JavaScript tests pass on this branch, on Temurin 11 and Node 12 — the versions your CI uses. No test is added: what changes is the address a request goes to, which the existing suites already exercise against a running server. mvn package builds the bundle.

Not verified: Windows, which I have no machine for. Your CI covers it.

Attribution

The relative addressing comes from @kairoh's fork, commit 74f53cc (April 2022, before that fork moved to Quarkus, so it applied to this same Vert.x code). Both projects are MPL-2.0. I have added a "Code from other forks" section to the README recording what is and is not taken from it — happy to move or drop that section if you would rather record it elsewhere.

Unrelated, take it or leave it

mvn package rewrites the tracked yarn.lock on every run. The yarn-update-browserslist execution runs npx browserslist@latest --update-db, which by design removes and reinstalls caniuse-lite. It also means a packaging build fetches @latest of a tool from npm. Your git diff --exit-code step cannot see it, since the job that runs it skips the frontend goals. Not part of this PR, just something I tripped over.

lgnap and others added 2 commits September 5, 2026 23:30
Every call was written against `http://localhost:8080` -- twenty places across
the three service modules, the i18n load path, the favicon in index.html and the
event bus. They are relative now, so the web UI addresses whatever origin served
it rather than a host and port compiled into the bundle.

The event bus is the one exception. sockjs-client validates its URL and rejects
one with no host and no protocol, so '/eventbus' throws at construction; it
derives an absolute URL from the page's own origin instead. The existing tests
would not have caught that -- eventBusChannel.test.js drives a fake transport,
not the real client.

Under `yarn start` the CRA dev server serves from :3000 while the backend
listens on :8080, and it cannot proxy the SockJS connection. `proxy` in
package.json forwards /api and /locales; .env.development points the event bus
at the backend directly. Neither is used by a packaged build.

This falsifies one paragraph of the javadoc on listenHost(), which argued that
nothing was lost by binding narrowly because the frontend hardcoded localhost,
so a browser elsewhere would talk to its own loopback and remote use never
worked. That is no longer true. The paragraph is rewritten rather than left
standing, and the conclusion is deliberately kept: remote use would now work if
the socket bound wider, and the reason to stay on the loopback becomes the
plainer one -- the API has no authentication. See the discussion in the pull
request for whether that should change.

Credit for the relative addressing goes to kairoh's fork, commit 74f53cc,
recorded under "Code from other forks" in the README with what is and is not
taken from it.

284 Java tests and 57 JavaScript tests on this tree, unchanged from master:
this adds no test. The behaviour it changes is the address a request is sent
to, which the existing suites exercise against a running server.

Co-authored-by: kairoh <3878594+kairoh@users.noreply.github.com>
Restores ServerBindingTest, which had been dropped as a duplicate of
HttpServerBindingTest. It is not one. That test starts a bare server on
listenHost() and proves the operating system honours the address; this one
deploys the real MainVerticle and proves start() actually uses it. A bare
server bound correctly says nothing about what the application does.

The two cases that made no sense after the design settled are gone: they
asserted studio.port and studio.host, which do not exist. What is left is the
loopback answering and every other address of this machine refusing, against
the deployed verticle.

The cost is that the real verticle binds the fixed LISTEN_PORT and cannot be
pointed elsewhere -- deliberately, since a test-only seam to vary it would be
the same override under another name. So both cases skip when that port is
already taken, which on a developer's machine means a running STUdio. On a
runner it is free and they execute. HttpServerBindingTest stays precisely
because it covers the address unconditionally.

Verified both ways rather than assumed: with 8080 held they skip, with it free
they run and pass.

One observation recorded in the javadoc: LISTEN_PORT is a static final int, so
javac inlines it into this test -- the same trap that made listenHost() a
method rather than a field. Milder here, since a stale copy makes the test
connect to the wrong port and go red rather than silently agree with itself,
but the same shape of problem.

286 Java tests, 0 failures, 39 skipped on Linux.
@antoinevalentinHA

Copy link
Copy Markdown
Owner

The answer to your question is no, and it is the answer you offered: not until the API authenticates.

Nothing about -Dstudio.host is wrong in itself, and your implementation was fine. The objection is that STUdio has no authentication at all, so a supported way to widen the socket is a supported way to hand an unauthenticated API to a network. If authentication ever lands, the setting becomes reasonable the same day and I will say so. Until then, please do drop it — and thank you for asking instead of assuming.

On the rest: the javadoc rewrite is right, and keeping the old reason as history was the correct call. I would not have thought to phrase it that way.

You were also right where I was wrong about the tests. I said yours was the one I would keep. Keeping both, for the reason you put in TESTING.md, is better: yours proves start() actually uses the address, mine runs unconditionally because it does not bind the fixed port. That distinction is worth more than either test alone.

The attribution section reads well, and I am glad it says what is not taken from that commit as clearly as what is.

Two things before this can go in, neither of them about your code:

  • I need to approve the workflow run again. The checks that passed were on 25d99e9; the run for a5f7bc2 is still gated, since a first-time contributor's every push re-opens that gate. So the current head is unverified, including on Windows.
  • Then a manual run of the packaged bundle here. No automated test exercises the real service addresses — addFromLibrary mocks, eventBusChannel drives a fake transport, packs is pure functions — so nothing in the suite would catch a broken URL. That is a gap in my project, not something your PR should have to close.

Your "unrelated, take it or leave it" note is worth taking separately. yarn-update-browserslist runs npx browserslist@latest --update-db, mvn package runs it, and the nightly build that produces the published archive runs mvn package. So the build that makes the release fetches an unpinned @latest from npm, and the job carrying git diff --exit-code skips the frontend goals and cannot see it. That is a supply-chain question on the release path. I have opened it separately.

@antoinevalentinHA
antoinevalentinHA merged commit b1af634 into antoinevalentinHA:master Sep 5, 2026
3 checks passed
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.

2 participants