Skip to content

bug: Set-Cookie headers flattened in prod-server.ts response merging #295

@southpolesteve

Description

@southpolesteve

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 forEach yields per-entry, the last Set-Cookie wins (previous ones overwritten)
  • If forEach yields the comma-joined string, the result is a single corrupted Set-Cookie (cookie values with Expires= 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions