Skip to content

fix(node): read duplicate single-value headers from rawHeaders in get/has#217

Merged
pi0 merged 1 commit into
mainfrom
fix/dup-node-headers
Jul 2, 2026
Merged

fix(node): read duplicate single-value headers from rawHeaders in get/has#217
pi0 merged 1 commit into
mainfrom
fix/dup-node-headers

Conversation

@pi0x

@pi0x pi0x commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Problem

On the Node adapter, NodeRequestHeaders.get() / has() / getSetCookie() had a fast path that read Node's collapsed req.headers object before _headers was materialized. For headers Node treats as single-value (authorization, content-type, …), Node keeps only the first occurrence, whereas the rawHeaders-materialized _headers appends all occurrences, matching WHATWG Headers.

As a result, get('authorization') returned a different value depending on whether the Headers object had been iterated first:

get('authorization') BEFORE iteration = "Bearer AAA"              <- fast path, first only
get('authorization') AFTER  iteration = "Bearer AAA, Bearer BBB"  <- via rebuilt _headers
native Headers.get()                  = "Bearer AAA, Bearer BBB"  <- WHATWG (correct)

This is a spec divergence and a header-confusion primitive: two layers reading the same header can disagree if one reads before iteration and the other after. Reproduced end-to-end against a live Node server over a raw socket (duplicate Authorization / Content-Type lines — a normal fetch client can't send these).

Fix

Route get() / has() / getSetCookie() through the rawHeaders-materialized _headers consistently, dropping the if (this.#headers) fast branches. The result no longer depends on prior iteration order and matches native Headers.

Node adapter only — other adapters (Deno/Bun/Cloudflare/Bunny/generic/AWS-Lambda) use native Request/Headers and are unaffected.

Tests

  • Added a regression test in test/node-headers.test.ts sending duplicate authorization / content-type headers and asserting the joined value both before and after iteration.
  • Full node suite passes (144 passed, 6 skipped); typecheck and lint clean.
  • Post-fix raw-socket repro confirms before and after both return the joined value and match native Headers.

🤖 Generated with Claude Code

…/has

Node collapses headers it treats as single-value (authorization,
content-type, …) to their first occurrence in `req.headers`. The fast
path in `get`/`has`/`getSetCookie` read that collapsed object, so the
return value diverged from WHATWG `Headers` (which joins all
occurrences) until the Headers object was iterated and `_headers` was
materialized from `rawHeaders`.

Route these methods through `_headers` consistently so the result no
longer depends on prior iteration order.

Co-Authored-By: Claude Fable 5 <[email protected]>
@pi0x
pi0x requested a review from pi0 as a code owner July 2, 2026 12:08
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b015b6e9-d1ef-41dd-a2bf-a2d3411166f2

📥 Commits

Reviewing files that changed from the base of the PR and between 57001b6 and 7712ca9.

📒 Files selected for processing (2)
  • src/adapters/_node/headers.ts
  • test/node-headers.test.ts
👮 Files not reviewed due to content moderation or server errors (2)
  • src/adapters/_node/headers.ts
  • test/node-headers.test.ts

📝 Walkthrough

[!WARNING]

Walkthrough skipped

File diffs could not be summarized.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dup-node-headers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/srvx@217

commit: 7712ca9

@pi0
pi0 merged commit 9806bd5 into main Jul 2, 2026
15 checks passed
@pi0
pi0 deleted the fix/dup-node-headers branch July 2, 2026 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants