HarperFast / HarperFast/prerender-plugin
Resource cache stores no first-party assets — the blocker is `Set-Cookie` on every asset, not `Vary: Origin`
- Lingua principale
- JavaScript
- Stelle
- 0
- Fork
- 0
- Merge medio
- 9h 39m
- PR unite (30g)
- 39
Descrizione
## Measured 2026-09-16: the blocker is `Set-Cookie`, not `Vary`
Re-measured against the live storefront with the deployed fleet config, counting every first-party
script/stylesheet response and the reason the cache would refuse each one:
| page | first-party JS/CSS | bytes | refused for `Set-Cookie` | refused for `Vary` | cacheable today |
| --- | ---: | ---: | ---: | ---: | ---: |
| home (mobile) | 53 | 5.34 MB | **51** | **0** | 1 |
| product (mobile) | 81 | 5.61 MB | **81** | **0** | 0 |
The only `Vary` values present on first-party assets are `""` and `"Accept-Encoding"` — **both already
accepted**. Not one response carries `Vary: Origin`.
What refuses them is the CDN stamping cookies on static asset responses:
```
AKA_GEO on 81 of 81 responses
AKA_SNB_STP on 81 of 81
vpusq on 47 of 81
ksa-app-measurement-beta on 7 of 81
```
and `getCachePolicy` refuses any response with `Set-Cookie`, before it ever looks at `Vary`:
```js
if (headers['set-cookie']) return { cacheable: false, ttlMs: 0 };
```
**So the fix this issue proposed — allow `origin` in the Vary allowlist, and key the entry by the
request's `Origin` — would cache one additional 0.06 MB file on the home page and nothing at all on a
product page.** The original diagnosis does not hold on this deployment today.
This also confirms what `c515d76`'s commit message reported in passing and this issue previously
argued against: *"same-origin assets set cookies and are therefore never cached, so only third-party
CDN responses are exposed."* That is exactly what the cache holds — see #108, measured the same day:
69 entries, 100% third-party, zero first-party.
## What the real lever is, and what it is worth
If first-party bundles are to be cached, the thing to change is the `Set-Cookie` rule, not the `Vary`
allowlist. That rule is a correctness rule — a response that sets cookies cannot be shared between
renders — so it cannot simply be dropped. The defensible shape is an allowlist of cookie names known
to carry no per-render state (`AKA_GEO` and `AKA_SNB_STP` are edge geo/routing cookies stamped on
every response, identical for every render from a given pod), with the cookie stripped from the
stored copy.
**Sizing, and the caveat that decides whether it is worth doing:** ~53–81 requests and ~5.3–5.6 MB per
render. But **76 of 81 of those responses are edge HITs** (`server-timing: cdn-cache; desc=HIT`), so
they are served by the CDN, not by the origin. Caching them locally would cut **CDN egress and render-
pod network**, not origin load — which means this is a cost/bandwidth lever, not a lever on the
origin-load goal it has previously been grouped with.
The cheaper fix may not be ours at all: asking the CDN to stop setting cookies on static asset
responses removes the blocker without any code, and is worth pricing against the allowlist.
## Still true, and worth keeping
**The `Vary` parser has a real bug even though it is not the blocker here.** A response that sends
`Vary` twice — as two header lines, semantically identical to one comma-joined header — reaches us as
the two values joined with a **newline**, so splitting on `,` alone leaves `"accept-encoding\norigin"`
as a single unrecognised token. `vary === '*'` is an exact comparison that a newline-joined value
slips past for the same reason; `vary.includes('*')` is the safer test.
That newline-join has now been hit three times in production, twice on the replay path rather than the
policy path (`9a401f8`, `c515d76` — both v1.24.0, both silent failures). Whoever touches this code
should treat the `\n`-joined form as the normal case, not an edge case.
## Why the original measurement said otherwise
Left here so the discrepancy is not re-investigated: this issue's first measurement reported 117
first-party responses admitted once the split was `/[,\s]+/` (against 62 before), which cannot be
reconciled with 81 of 81 now carrying `Set-Cookie`. Either the site began setting these cookies on
asset responses between 2026-08-18 and now, or the original count was taken over a different host set.
The current numbers are reproducible on both page types and are the ones to build against.
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Start by locating getCachePolicy and tracing how repeated Vary headers and Set-Cookie responses are handled. Reproduce the newline-joined Vary cases described here, then determine the intended policy for safe cookies and static assets; done should include coverage for the parsing and cacheability behavior without weakening cookie-safety guarantees.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- javascript
- Ambito
- backend, performance
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Attiva
- Chiarezza
- Da chiarire
- Idoneità per principianti
- 42/100