imroc / imroc/req

Upstream Sync Report 2026-09-16: RFC 9112 §6.3 Transfer-Encoding / Content-Length framing rewrite

Open
#540 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement modified-stdlib priority:low
Dominant language
Go
Stars
4.9k
Forks
409
Avg merge
6h 47m
Merged PRs (30d)
7

Description

Upstream Changes

Go stdlib net/http rewrote the message-framing (body length determination) logic in src/net/http/transfer.go, restructuring it to follow the numbered algorithm of RFC 9112 §6.3:

  • Commit: db450d3 (2026-09-14, CL 818663)
  • parseTransferEncoding + fixLength + the HEAD special-case in readTransfer are replaced by a single transferReader.determineBodyLength(isResponse) that walks the RFC items in order
  • transferReader gains a RealBodyLength field, separating the actual body length (0 for HEAD/bodyless) from the reported ContentLength
  • New sentinel errors: errTooManyTransferEncodings, errUnsupportedTransferEncoding, errTooManyContentLengths
  • parseContentLength now returns (string, int64, error) — the trimmed header value alongside the parsed length

Behavior differences vs req's copy

req's inlined transfer.go still carries the pre-rewrite logic (readTransferparseTransferEncodingfixLength), so porting changes behavior in these edge cases:

Case req today After sync
HTTP/1.0 response with Transfer-Encoding TE silently ignored; connection reuse decided by shouldClose Framing treated as faulty per RFC 9112 §6.1: TE dropped, Close = true
2xx response to CONNECT No special case: body framed by Content-Length if present, otherwise unbounded Explicit tunnel semantics: body unbounded, Content-Length ignored, Close = true
Multiple differing Content-Length values Error message echoes the values (got %q) Sentinel error without values
Multiple/oddly-formed TE values Error messages echo raw values Sentinel errors without values
Content-Length header map entry Deduplicated in place when multiple; left as-is otherwise Deleted up front, re-set (trimmed, single value) only in branches that actually use it

The HEAD / 1xx / 204 / 304 / chunked / plain-CL / unbounded-response paths keep their net semantics; the rewrite mainly makes the decision table explicit and consistent.

Impact on req

  • req inlines transfer.go (root, modified stdlib). Only the read side is affected — readTransfer in req's copy handles *http.Response only (requests go through transferWriter), so the RFC table applies to response framing.
  • The 2xx CONNECT change is the one visible to users doing CONNECT tunneling: today a tunnel response carrying Content-Length gets a CL-framed body, which is wrong for a tunnel (the body is the raw tunnel stream until close). Aligning would make tunnel framing correct.
  • The HTTP/1.0+TE hardening is a strictness improvement on a request-smuggling-adjacent surface; for a client library it mostly affects responses from non-conforming servers (connection now closed instead of reused).
  • No security advisory is attached to this change; it is a correctness/alignment refactor.

Suggested sync

Port db450d3 into transfer.go (merge upstream net/http: <date>(<hash>) style). Port notes:

  • req's readTransfer has local deviations to preserve: no maxTrailerHeaders parameter (req's body struct and fixTrailer signature differ), header is http.Header from net/http rather than stdlib's own Header type, and the httplaxContentLength godebug var is locally renamed.
  • parseContentLength's new 3-value signature has call sites in readTransfer (HEAD case) that must be adapted.
  • The *Request branch of stdlib's determineBodyLength (RFC item 7) is dead code for req since readTransfer only accepts *http.Response; keep the response-side cases.
  • No public API change; req's Response.ContentLength / TransferEncoding outputs keep their meaning.

Not security-related, no workaround needed — behavior alignment, low priority.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in req's root transfer.go, especially readTransfer, and compare it with upstream commit db450d3. Account for req's local body, trailer, Header, and godebug differences while porting the response-side framing logic. Done means the RFC 9112 response cases and CONNECT behavior are aligned without changing the public response fields.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
networking
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.