Skip to content

fix(qemu/http): avoid duplicate Content-Length for buffered bodies - #135

Open
geminixiang wants to merge 6 commits into
earendil-works:mainfrom
geminixiang:fix/buffered-body-content-length-node-24-17
Open

fix(qemu/http): avoid duplicate Content-Length for buffered bodies#135
geminixiang wants to merge 6 commits into
earendil-works:mainfrom
geminixiang:fix/buffered-body-content-length-node-24-17

Conversation

@geminixiang

@geminixiang geminixiang commented Jul 15, 2026

Copy link
Copy Markdown

Fixes #134.

Problem

I found this while running git clone inside a Gondolin VM. On Node.js >= 24.17, guest requests with a buffered body fail with HTTP 502 through the QEMU HTTP bridge. Small POST requests and git clone over smart HTTP are affected, while GET and streamed bodies still work.

I traced the error to content-length. The bridge sets it from the buffered body, then npm undici 6 appends another derived value before dispatching through Node's built-in undici Agent. Built-in undici 7.28 rejects the duplicated value ("181, 181") with invalid content-length header. More details and the Node.js version bisection are in #134.

What I changed

I pass a copy of currentRequest.headers to fetch() and remove content-length from that copy only for buffered bodies, so undici derives it once from the body.

Streamed bodies keep their explicit length. The original currentRequest.headers is not changed, so redirects and response hooks still receive the measured length.

Verification

I verified the change on Node.js 24.18.0 with the QEMU backend:

  • A buffered POST returns HTTP 200 instead of 502.
  • git clone --depth 1 exits successfully instead of returning 502.
  • Raw-wire checks with npm undici 6.23, 6.27, 7.28, and 8.5 produce exactly one Content-Length for buffered and streamed bodies.
  • All 97 tests in host/test/qemu-net.test.ts pass on Node.js 24.13 and 24.18.
  • TypeScript type checking and Prettier checks pass.

Contribution Agreement

By submitting this pull request, I confirm the following:

I understand that the entity Earendil Inc. (incorporated in the state of Delaware in 2025) needs some rights from me in order to utilize my contributions in this PR. As a contributor I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Earendil Inc. can use, modify, copy, and redistribute my contributions, under Earendil Inc.'s choice of terms.

@geminixiang
geminixiang marked this pull request as draft July 15, 2026 17:44
Keep Content-Length and Transfer-Encoding out of canonical request headers so hook rewrites and redirects cannot leave stale framing behind. Buffered and empty bodies leave framing to fetch; streams carry one trusted byte length for outbound serialization.

Also reject ambiguous inbound framing and malformed chunk sizes, and cover buffered, streaming, hook, redirect, policy, and raw-wire behavior with regression tests.
@geminixiang
geminixiang force-pushed the fix/buffered-body-content-length-node-24-17 branch from 7e8bf2d to 8ef0130 Compare July 15, 2026 18:17
@geminixiang geminixiang changed the title fix(qemu/http): drop content-length for buffered bodies before fetch fix(qemu/http): derive request framing from body state Jul 15, 2026
Keep this PR focused on the buffered Content-Length regression. Restore the existing request model, hook, redirect, and ingress parsing behavior while retaining the fetch-boundary header copy and focused regression test.
@geminixiang geminixiang changed the title fix(qemu/http): derive request framing from body state fix(qemu/http): drop content-length for buffered bodies before fetch Jul 15, 2026
@geminixiang geminixiang changed the title fix(qemu/http): drop content-length for buffered bodies before fetch fix(qemu/http): avoid duplicate Content-Length for buffered bodies Jul 15, 2026
@geminixiang
geminixiang marked this pull request as ready for review July 15, 2026 18:56
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.

Bug: QEMU HTTP bridge returns 502 for buffered request bodies on Node.js >= 24.17 (invalid content-length header)

1 participant