fix(app-router): validate RSC cache-busting params#991
Draft
NathanDrake2406 wants to merge 3 commits intocloudflare:mainfrom
Draft
fix(app-router): validate RSC cache-busting params#991NathanDrake2406 wants to merge 3 commits intocloudflare:mainfrom
NathanDrake2406 wants to merge 3 commits intocloudflare:mainfrom
Conversation
App Router RSC responses could vary by request headers while client fetches and server validation still relied on Vary-aware caches. CDNs that key only by URL could reuse a mounted-slot or interception-context RSC payload for a different request. Next.js validates a cache-busting _rsc search param against the RSC request headers and redirects malformed requests to the canonical URL. Vinext now applies the same invariant to its .rsc request model, centralizes the RSC Vary header set in normal server modules, and de-duplicates middleware Vary additions. Tests cover missing and stale _rsc values, variant-header hashes, generated-entry delegation, browser RSC request markers, response Vary propagation, and App Router RSC integration.
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Adds a shared App Router RSC cache-busting helper and wires generated RSC entries to reject malformed RSC requests by redirecting them to the canonical
_rscURL. Client-side RSC fetches now sendRSC: 1plus a cache-busting_rscsearch param derived from the request headers that can change the RSC payload.The shared helper also centralizes the App Router RSC
Varyheader set and includes both Next-compatible headers and Vinext-specific variant headers:RSCAcceptNext-Router-State-TreeNext-Router-PrefetchNext-Router-Segment-PrefetchNext-UrlX-Vinext-Interception-ContextX-Vinext-Mounted-SlotsFixes #988.
Why
Next.js now treats the URL as the defensive cache key for RSC requests because some CDNs do not respect
Vary. The relevant upstream behavior is:RSC: 1on Flight fetches: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/router-reducer/fetch-server-response.ts#L147-L155_rscsearch param before fetching: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/router-reducer/fetch-server-response.ts#L532-L537Vary, withNext-Urladded for interception-sensitive routes: https://github.com/vercel/next.js/blob/canary/packages/next/src/server/base-server.ts#L2003-L2023 and https://github.com/vercel/next.js/blob/canary/packages/next/src/server/route-modules/app-page/module.ts#L188-L195Vinext uses
.rscURLs rather than the exact same visible URL for HTML and RSC, so the HTML-vs-RSC variant is already separated by pathname. The gap is still real because Vinext's.rscresponse can vary by request headers such as mounted slots and interception context. A CDN that keys only by URL could serve the wrong RSC payload for another slot or interception context.Approach
server/app-rsc-cache-busting.tsas the normal module that owns request headers,_rschashing, canonical redirect validation, and the shared RSCVaryvalue.entries/app-rsc-entry.tsas app-shape codegen: it imports the helper, computesisRscRequest, and delegates validation.Varyvalue.Varytokens when merging middleware headers, so middleware can add its own Vary values without duplicating the base App Router set.Validation
vp checkvp run knip --no-progressvp test run tests/app-rsc-cache-busting.test.ts tests/app-browser-entry.test.ts tests/prefetch-cache.test.ts tests/entry-templates.test.tsvp test run tests/app-rsc-cache-busting.test.ts tests/app-browser-entry.test.ts tests/app-page-cache.test.ts tests/app-page-response.test.ts tests/app-page-boundary-render.test.ts tests/app-page-stream.test.ts tests/app-server-action-execution.test.ts tests/entry-templates.test.tsvp test run tests/app-router.test.ts -t "RSC"Risks / follow-ups
This intentionally adapts the Next.js invariant to Vinext's current
.rscURL model instead of switching Vinext to same-URL Flight fetches. The hash includes Next-compatible RSC variant headers for forward compatibility and the Vinext-specific headers that currently affect payload shape.