HarperFast / HarperFast/prerender-plugin

Resource cache stores no first-party assets — the blocker is `Set-Cookie` on every asset, not `Vary: Origin`

未关闭
#109 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
bug performance
主要语言
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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。