Repository navigation
Stop the fetch cache option from overriding the origin's Cache-Control - #7749
Merged
Merged
Conversation
Contributor
|
Since last review: 0 resolved, 0 still open, 1 new. The cache-option compat flag now preserves origin cache-control behavior and tests both flag states. Other findings
Reviewed commit: 59a83298 · github run |
danlapid
force-pushed
the
dlapid/cache-no-cache-spec
branch
from
October 14, 2026 21:34
264bcb4 to
eff62aa
Compare
jasnell
approved these changes
Oct 14, 2026
Per the Fetch spec, a request's cache mode describes how the cache may use a stored response: "no-cache" means revalidate it with the origin, "no-store" means act as if there is no cache. Neither says anything about how the response may be cached. serializeCfBlobJson() currently also synthesizes `cf.cacheControl: "no-cache"` / `"no-store"` from `cache: 'no-cache'` / `cache: 'no-store'`, which overrides the origin's response Cache-Control. An origin `no-store` gets cached as `no-cache`, which breaks customers who only want forced revalidation. The new `cache_option_preserves_cache_control` compat flag (default on 2026-11-17) stops the cache option from synthesizing cacheControl. `cache: 'no-cache'` still sets cacheForceRevalidate; `cache: 'no-store'` still sets cacheTtl -1 and cacheLevel bypass. cacheControl synthesized from cf.cacheTtl is unchanged, since cacheTtl is meant to override the origin's response. Overriding the origin's Cache-Control stays available through `cf.cacheControl`. Compatibility: changes behavior of an existing API, so it is gated behind a compat flag. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
danlapid
force-pushed
the
dlapid/cache-no-cache-spec
branch
from
October 14, 2026 22:16
eff62aa to
59a8329
Compare
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.
Per the Fetch spec, a request's cache mode describes how the cache may use a stored response:
no-cachemeans revalidate it with the origin,no-storemeans act as if there is no cache. Neither says anything about how the response may be cached. TodayserializeCfBlobJson()also synthesizescf.cacheControlfrom the cache option:RequestInit.cacheno-cachecacheForceRevalidate: true,cacheControl: "no-cache"cacheForceRevalidate: trueno-storecacheTtl: -1,cacheLevel: "bypass",cacheControl: "no-store"cacheTtl: -1,cacheLevel: "bypass"The synthesized
cacheControloverrides the origin's response Cache-Control. An originno-storegets cached asno-cache, which breaks customers who only want forced revalidation.This adds the
cache_option_preserves_cache_controlcompat flag (disable flagcache_option_overrides_cache_control, default on 2026-11-17). When it's on, the cache option no longer synthesizescacheControl.cacheControlsynthesized fromcf.cacheTtlis unchanged, sincecacheTtlis meant to override the origin's response. Overriding the origin's Cache-Control stays available throughcf.cacheControl.The synthesis predates
cf.cacheControl(dd099be), so changing it requires a compat flag.Questions for reviewers
cf.cacheControlwith the cache option.RequestInitializerDict::validate()still rejects using both together. With this flag, they are separate controls, so we may want to allow the pair when the flag is on. I left that out of this PR.cache: 'no-store'andcacheTtl: -1. With the flag,no-storestill setscacheTtl: -1along withcacheLevel: bypass. If downstream readscacheTtl: -1as an override of the origin's response,no-storeshould probably set only the cache level. Please flag it if so.Testing
cf-cache-control-testnow has a service binding that echoes therequest.cfit receives. Two services pin the flag on and off, and the test checks the serialized blob forcache: 'no-cache',cache: 'no-store'andcf.cacheTtl. All three variants ofcf-cache-control-testpass, as dohttp-test@andhttp-test@all-compat-flags.🤖 Generated with Claude Code