Skip to content

fix(response): strip HEAD body when merging prepared headers into a mutable Response#1490

Merged
pi0 merged 2 commits into
h3js:mainfrom
n0liu:fix/head-body-inplace-merge
Jul 22, 2026
Merged

fix(response): strip HEAD body when merging prepared headers into a mutable Response#1490
pi0 merged 2 commits into
h3js:mainfrom
n0liu:fix/head-body-inplace-merge

Conversation

@n0liu

@n0liu n0liu commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Addresses the "HEAD body stripping misses the in-place merge path" item from #1482.

prepareResponse strips the body of a HEAD (or otherwise null-body) response on the fast path (!preparedHeaders) and on the immutable-headers catch path, but the in-place header merge path returned the mutable Response with its body intact. So when prepared headers are merged into a mutable 2xx Response under a HEAD request, app.fetch / web-mode / service-worker consumers received a HEAD response carrying a body. Node strips it at the socket, so it only surfaced off-Node.

This merges the prepared headers first, then strips the HEAD body in a single place that also covers the in-place merge path, deduping the HEAD handling that was previously split across two branches. Bundle size is unchanged (the guards in test/bench/bundle.test.ts still pass).

Added a regression test in test/app.test.ts: it sets a prepared header via event.res.headers, returns a mutable Response with a body under a HEAD request, and asserts the merged headers are present while the body is empty. It fails on the web matrix mode before this change and passes after; the node mode passes either way since the runtime strips the body at the socket.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed HEAD responses so the body is reliably empty in all cases, while response headers remain intact.
    • Improved header handling by correctly merging headers set during request handling with headers from the returned response.
    • Added safer handling for immutable headers during response preparation.
  • Tests
    • Added coverage to verify that HEAD responses include the merged headers but an empty response body.

…utable Response

prepareResponse stripped the body of a HEAD (and other null-body) response on the fast path and the immutable-headers catch path, but the in-place header merge path returned the mutable Response with its body intact. app.fetch / web-mode / service-worker consumers then saw a HEAD response carrying a body (Node strips it at the socket, so it only surfaced off-Node).

Merge the prepared headers first, then strip the HEAD body in a single place that also covers the in-place merge path. This dedupes the HEAD handling and keeps the bundle size unchanged.

Ref h3js#1482
@n0liu
n0liu requested a review from pi0 as a code owner July 19, 2026 01:56
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

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: b03ba593-7f10-4ca4-93df-92ff101f0c3c

📥 Commits

Reviewing files that changed from the base of the PR and between 3814601 and 2d18dd8.

📒 Files selected for processing (1)
  • src/response.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/response.ts

📝 Walkthrough

Walkthrough

prepareResponse now merges eligible prepared headers, handles merge failures, and strips bodies from HEAD responses. A new test verifies merged headers and an empty response body.

Changes

HEAD response behavior

Layer / File(s) Summary
Merge headers and strip HEAD bodies
src/response.ts, test/app.test.ts
prepareResponse merges eligible headers, handles merge failures, and strips non-null bodies for HEAD requests. The test verifies both header sources and an empty body.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • h3js/h3#1486: Also updates prepareResponse header merging and related application tests.

Suggested reviewers: pi0

Poem

I’m a bunny with headers tucked tight,
Merging them neatly for HEAD in the night.
The body hops out, leaving nothing to read,
While two little headers stay just as agreed.
Test green, ears high—what a wonderful deed!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: stripping HEAD bodies while merging prepared headers into mutable responses.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/response.ts`:
- Around line 155-164: Update the successful in-place merge return path around
the HEAD-specific body stripping to use the existing nullBody logic, so 204,
304, HEAD, and all other null-body statuses consistently return a null body.
Preserve the current response metadata and return behavior for statuses that
allow bodies.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e03ce510-508d-4326-846c-c1a38c99a7e3

📥 Commits

Reviewing files that changed from the base of the PR and between 374e4d4 and 3814601.

📒 Files selected for processing (2)
  • src/response.ts
  • test/app.test.ts

Comment thread src/response.ts
@pi0
pi0 merged commit 8dc8a28 into h3js:main Jul 22, 2026
7 checks passed
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