next.js
4286a42e - Encode the cache item name built by `unstable_cache` (#96937)

Commit
6 days ago
Encode the cache item name built by `unstable_cache` (#96937) A cache implementation may serialize cache metadata into HTTP request headers, whose values are limited to Latin-1. `unstable_cache` assembles a cache item name from the request URL and the name of the cached callback, and neither part was encoded. When that name holds a character above U+00FF the conversion throws before the request is dispatched, so the read never reaches the cache and the write that follows it fails the same way. Nothing is stored, nothing is found, and the entry falls back to the origin on every render. The name is built by `getFetchUrlPrefix`, which reads the pathname and the search parameters out of the request URL. The pathname stays percent-encoded, but `URLSearchParams` returns decoded keys and values, so a non-ASCII query parameter is the reachable case: it applies to any dynamic route that calls `unstable_cache`, whether or not the route reads `searchParams`, and therefore also to a parameter a caller appends. A callback whose name holds such a character is affected too, though a production build usually renames the binding. This change encodes the assembled name with `encodeHeaderSafe`. That helper only replaces characters outside the class Node accepts in a header value, so the separating spaces and the URL punctuation are preserved and the name keeps its documented shape. Every name that is representable today is returned unchanged, so this is inert for existing entries. The item name is a label: it is not the cache key, which is derived separately from the callback's key parts and arguments, and the Suspense Cache API neither parses nor matches on it. The test covers the two parts of the name on separate routes so a failure names the part it comes from, and asserts the constraint rather than either input, since which inputs are live depends on the bundler and on minification. A deployment checks it through the real cache handler implementation, where the failure shows up as an entry that is recomputed on every request. fixes #76286
Author
Parents
Loading