Skip to content

fix(headers): strip internal dev request ID headers#2260

Merged
james-elicx merged 2 commits into
cloudflare:mainfrom
ponharu:fix/strip-dev-request-id-headers
Jun 22, 2026
Merged

fix(headers): strip internal dev request ID headers#2260
james-elicx merged 2 commits into
cloudflare:mainfrom
ponharu:fix/strip-dev-request-id-headers

Conversation

@ponharu

@ponharu ponharu commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Close #1934

Summary

Verification

  • pnpm test tests/shims.test.ts -t "headers\\(\\) strips internal flight and dev request-id headers"
  • pnpm test tests/shims.test.ts -t "next/headers shim"
  • pnpm exec vp fmt --check packages/vinext/src/server/headers.ts packages/vinext/src/shims/headers.ts tests/shims.test.ts

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: LGTM

This is a clean, well-scoped fix that faithfully mirrors the upstream Next.js change in vercel/next.js#94703.

What I verified

  • Constant values match upstream exactly. NEXT_REQUEST_ID_HEADER (x-nextjs-request-id) and NEXT_HTML_REQUEST_ID_HEADER (x-nextjs-html-request-id) match the values in packages/next/src/client/components/app-router-headers.ts.
  • Correct chokepoint. _getReadonlyHeaders is the single source for the headers() userland view across both routers (it's the only caller of _sealHeaders for request headers), so stripping here covers all paths. Pages and App Router both flow through it.
  • Raw headers preserved. The fix copies into a fresh new Headers(ctx.headers) before deleting, so ctx.headers stays intact for internal reads — the test asserts this, matching the upstream comment that "the server reads them from the raw request headers, not from here."
  • Cache invalidation is safe. applyMiddlewareRequestHeaders nulls ctx.readonlyHeaders on a middleware override (headers.ts:540), so the stripped copy is rebuilt correctly after NextResponse.next({ request: { headers } }).
  • Tests pass. Ran vp test run tests/shims.test.ts -t "next/headers shim" (33 passed) and the new regression test in isolation (passes).

Note (non-blocking)

The PR title/description frame this as stripping only the dev request-id headers, but the change also now strips FLIGHT_HEADERS (rsc, next-router-state-tree, etc.) from the userland headers() view — and the test asserts that (expect(h.get("rsc")).toBeNull()). This is the correct behavior and matches upstream's getHeaders in request-store.ts, and flight headers are already stripped at the middleware boundary via requestWithoutFlightHeaders in server/app-middleware.ts, so this is sound defense-in-depth. Just worth noting the diff does slightly more than the title suggests.

No changes requested.

@ask-bonk

ask-bonk Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review posted. Summary of my findings on PR #2260:

Verdict: LGTM (approved)

The PR is a clean, well-scoped fix that faithfully mirrors upstream Next.js #94703.

What I verified:

  • Constant values match upstream exactlyx-nextjs-request-id and x-nextjs-html-request-id match Next.js's app-router-headers.ts.
  • Correct single chokepoint_getReadonlyHeaders is the only place that builds the userland headers() view (via _sealHeaders), covering both Pages and App Router.
  • Raw headers preserved — the fix copies into a fresh Headers before deleting, so internal code can still read the values (test asserts this).
  • Cache invalidation is safeapplyMiddlewareRequestHeaders nulls readonlyHeaders on middleware overrides, so the stripped copy rebuilds correctly.
  • Tests pass — ran the full next/headers shim suite (33 passed) plus the new regression test.

One non-blocking note flagged: the diff also strips FLIGHT_HEADERS (rsc, next-router-state-tree, etc.) from the userland view, which goes slightly beyond the PR title's framing, but this is correct and matches upstream's getHeaders in request-store.ts. No changes requested.

github run

@pkg-pr-new

pkg-pr-new Bot commented Jun 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@2260
npm i https://pkg.pr.new/vinext@2260

commit: 22044b5

@github-actions

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared 22044b5 against base 95b320f using alternating same-runner rounds. Next.js was unchanged and skipped.

1 improved · 0 regressed · 5 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 132.8 KB 132.8 KB ⚫ +0.0%
Client entry size (gzip) vinext 118.7 KB 118.7 KB ⚫ +0.0%
Dev server cold start vinext 1.96 s 1.91 s 🟢 -2.6%
Production build time vinext 2.26 s 2.25 s ⚫ -0.3%
RSC entry closure size (gzip) vinext 91.0 KB 91.0 KB ⚫ +0.0%
Server bundle size (gzip) vinext 161.7 KB 161.7 KB ⚫ +0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

@james-elicx james-elicx merged commit 7c932f3 into cloudflare:main Jun 22, 2026
47 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.

Strip internal dev request-id headers (x-nextjs-request-id, x-nextjs-html-request-id) from userland headers()

2 participants