fix(vite-plugin): preserve the request authority under HTTP/2 - #15533
fix(vite-plugin): preserve the request authority under HTTP/2#15533vahidshaik1901 wants to merge 1 commit into
Conversation
Browsers negotiate HTTP/2 whenever `server.https` is enabled, and HTTP/2 carries the authority in the `:authority` pseudo-header rather than in `Host`. `createHeaders()` from `@remix-run/node-fetch-server` skips every `:`-prefixed pseudo-header, so `Host` was absent from the parsed headers and `createRequestForIncomingMessage()` fell through to the literal `"localhost"`, dropping both the host and the port. A Worker served from `vite dev --https` on port 5173 therefore saw `https://localhost/` rather than `https://localhost:5173/`. `toMiniflareRequest()` read the same missing `Host` header, so `X-Forwarded-Host` was never set either. Auth libraries that rebuild redirect URLs from `request.url` or the forwarded headers, such as Clerk's handshake flow, redirected to the wrong origin and looped. Resolve the authority from `Host` first and `:authority` second via a new `getRequestHost()` helper, mirroring the existing `getForwardedProto()`, and fall back to the host of the already-resolved request URL when setting `X-Forwarded-Host`. Covered by tests against a cleartext HTTP/2 server, which exercises the same code path without requiring TLS. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018W34ieE3NNGaRQBxj5CKkH
🦋 Changeset detectedLatest commit: b520dbb The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
@cloudflare/autoconfig
@cloudflare/build-output-utils
@cloudflare/codemods
@cloudflare/config
create-cloudflare
@cloudflare/deploy-helpers
@cloudflare/kv-asset-handler
miniflare
@cloudflare/pages-functions
@cloudflare/pages-shared
@cloudflare/unenv-preset
@cloudflare/vite-plugin
@cloudflare/vitest-plugin
@cloudflare/workers-auth
@cloudflare/workers-editor-shared
@cloudflare/workers-utils
wrangler
commit: |
|
Three checks are red and I do not believe any of them relate to this change — details below so a reviewer does not have to dig. Happy to rebase if you would rather just see a clean run. This PR touches three files, all within
Vite Plugin Playground (ubuntu-latest, vite-8) — the suite never ran. The No assertion failed; Tests (Windows, packages-and-tools) — a miniflare test, in a package this PR does not touch: That looks like a tail-event forwarding race rather than anything host-related. Tests (Windows, fixtures) — Locally, all 199 tests across the 21 unit test files in |
|
Flagging an overlap I should have caught before opening this: #15519 fixes the same issue The two take different routes. #15519 extracts I have no attachment to which one lands. #15519 got there first and is the broader change; |
|
Correction to the note above: #15519 was not the first PR for #14931. #14933 (@intrdx) has been open since 2026-07-30 and has had a maintainer approval since 2026-08-03, and #15237 is open for the same issue as well. I missed both when I checked, which is on me. @intrdx has offered on #14933 to fold the |
Adopt createRequestForIncomingMessage host resolution and toMiniflareRequest URL-host fallback from cloudflare#15533, replacing the outer Host force-set. Cover the :authority path with cleartext HTTP/2 tests. Co-authored-by: SHAIK VAHID <38548782+vahidshaik1901@users.noreply.github.com>
Fixes #14931.
Browsers negotiate HTTP/2 whenever
server.httpsis enabled, and HTTP/2 carries the authority in the:authoritypseudo-header rather than inHost.createHeaders()from@remix-run/node-fetch-serverskips every:-prefixed pseudo-header:So
Hostwas absent from the parsed headers andcreateRequestForIncomingMessage()fell through to the literal"localhost", dropping both the host and the port. A Worker served fromvite dev --httpson port 5173 sawhttps://localhost/instead ofhttps://localhost:5173/.toMiniflareRequest()read that same missingHostheader, soX-Forwarded-Hostwas never set either. Auth libraries that rebuild redirect URLs fromrequest.urlor the forwarded headers — Clerk's handshake flow in the linked issue — redirected to the wrong origin and looped.Changes
getRequestHost(), which resolves the authority fromHostfirst and:authoritysecond, mirroring the existinggetForwardedProto()helper. It returnsundefinedwhen neither is present so the caller keeps its own"localhost"fallback.createRequestForIncomingMessage()now resolves the host through that helper. HTTP/1.1 behaviour is unchanged, sinceHostis still preferred.toMiniflareRequest()falls back to the host of the already-resolved request URL when there is noHostheader, soX-Forwarded-Hostis set under HTTP/2.Testing
Added two tests driving a cleartext (h2c) HTTP/2 server, which exercises the same code path without requiring TLS certificates, following the existing
createRequestHandlertest pattern. Before the change they fail with:All 199 tests across the 21 unit test files in
packages/vite-plugin-cloudflarepass with the change.check:typeandoxlint --deny-warningsare clean.request.urlandX-Forwarded-Hostunder HTTPS; no public API changes.