fix: preserve multiple Set-Cookie headers through the runtime - #16
Open
jonasnobile wants to merge 3 commits into
Open
fix: preserve multiple Set-Cookie headers through the runtime#16jonasnobile wants to merge 3 commits into
jonasnobile wants to merge 3 commits into
Conversation
Headers.forEach folds same-name headers into one comma-joined value, so a worker response carrying several Set-Cookie cookies (e.g. an auth library's session token + cached session) collapsed to a single corrupted cookie and the others were dropped. This broke cookie-based auth under `pletivo dev`/lopata (workerd-backed `LOPATA=0` was unaffected). Collect cookies via Headers.getSetCookie() and emit each one separately in the three places that serialize a Response: - vite-plugin writeResponse (Node res.writeHead) - worker-thread serializeResponse (entry.ts) - worker-thread serialize (rpc-shared.ts) Adds an e2e regression test (set-cookie-worker fixture) asserting both cookies survive end-to-end. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XntvTQmXo7hrNv3UBqN3s3
Collapse the byte-identical Set-Cookie serialization blocks in serializeResponse (entry.ts) and dispatchRpcFetch (rpc-shared.ts) into a single serializeResponseHeaders() helper in serialize.ts, alongside the existing request/response serialization primitives. Behavior unchanged; future header/cookie fixes now live in one place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017pcBc1XDGY1f9ZoribTzLv
jonasnobile
force-pushed
the
fix/preserve-multiple-set-cookie
branch
from
July 1, 2026 08:11
ed25093 to
899b221
Compare
…eHeaders Review follow-up extending the Set-Cookie fix to the paths PR #16 missed: - DO fetch responses (do-worker-entry) and worker-loader responses now use serializeResponseHeaders() instead of folding forEach/entries() loops - vite-plugin writeResponse delegates to the helper and groups repeated keys generically, so the Set-Cookie invariant lives in one place - tracing headersToRecord captures Set-Cookie as string[] instead of a folded value - drop the dead getSetCookie?.() guard — Bun always implements it, and the fallback would have silently dropped cookies instead of failing loudly - e2e test: two Set-Cookie headers on a DO response survive the bridge Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0143RmhobMFnePrzRm8RLqq6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Headers.forEachfolds same-name headers into a single comma-joined value. So when a worker response carries severalSet-Cookieheaders — the shape every cookie-based auth library produces (e.g. better-auth'ssession_token+ cachedsession_data) — they collapsed into one corrupted cookie and the rest were silently dropped.Effect: cookie-based auth is broken under
pletivo dev/ lopata (the docker dev path). The workerd-backedLOPATA=0path was unaffected, which is why it went unnoticed.Fix
Collect cookies via
Headers.getSetCookie()and emit each one separately in the three places that serialize aResponse:vite-pluginwriteResponse(Noderes.writeHead— array value ⇒ one header per cookie)worker-threadserializeResponse(entry.ts)worker-threadserialize (rpc-shared.ts)The deserialize side (
makeResponse) already rebuilds vianew Response(body, { headers })from the[k,v][]array, which appends each pair — so multiple['set-cookie', …]pairs round-trip correctly.Test
Adds
tests/set-cookie-e2e.test.ts+ aset-cookie-workerfixture that returns twoSet-Cookieheaders and asserts both survive end-to-end through the running runtime.🤖 Generated with Claude Code
https://claude.ai/code/session_01XntvTQmXo7hrNv3UBqN3s3