-
Notifications
You must be signed in to change notification settings - Fork 287
bug: Set-Cookie headers flattened in prod-server.ts response merging #295
Description
Problem
In prod-server.ts around line 944-945, middleware headers are merged into the final response using a Record<string, string> pattern:
const responseHeaders: Record<string, string> = { ...middlewareHeaders };
response.headers.forEach((v, k) => { responseHeaders[k] = v; });Headers.forEach() iterates Set-Cookie values as combined comma-separated strings (via Headers.get() semantics), or as individual entries depending on the runtime. Either way, the Record<string, string> target loses multiple Set-Cookie values:
- If
forEachyields per-entry, the last Set-Cookie wins (previous ones overwritten) - If
forEachyields the comma-joined string, the result is a single corrupted Set-Cookie (cookie values withExpires=dates contain commas, so comma-joining breaks parsing)
The resulting sendCompressed call passes this flattened object to writeHead, which can't reconstruct the original multiple Set-Cookie headers.
Context
This is a pre-existing bug, surfaced during review of #281 (which correctly uses responseHeaders.append("set-cookie", ...) in renderPage). Now that gSSP can set cookies via res.setHeader("set-cookie", ...), this flattening in prod-server.ts becomes more likely to hit in practice.
Fix
Use Headers.getSetCookie() (available in Node 20+, Cloudflare Workers, Deno) to preserve array-valued Set-Cookie headers, or switch responseHeaders to use the Headers API throughout instead of a plain object.
Discovered by
Flagged by bigbonk in #281 (comment)