HarperFast / HarperFast/prerender-plugin
Resource cache stores no first-party assets — the blocker is `Set-Cookie` on every asset, not `Vary: Origin`
- 主要语言
- JavaScript
- 星标
- 0
- 派生
- 0
- 平均合并
- 8 小时 54 分钟
- 30 天内合并 PR
- 50
描述
## 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.
贡献指南
调研方向
首先定位 getCachePolicy,并追踪重复的 Vary 标头和 Set-Cookie 响应是如何处理的。复现此处描述的以换行符连接的 Vary 情况,然后确定针对安全 cookie 和静态资源的预期策略;完成内容应包括对解析和可缓存性行为的覆盖,同时不得削弱 cookie 安全性保证。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- javascript
- 领域
- backend, performance
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 活跃
- 描述清晰度
- 需要澄清
- 新手友好度
- 42/100