Skip to content

Drop Content-Length when HTTP1xCodec sends Transfer-Encoding: chunked - #662

Open
ziyziy89 wants to merge 1 commit into
meta:mainfrom
ziyziy89:http1x-te-cl-egress
Open

ziyziy89 wants to merge 1 commit into
meta:mainfrom
ziyziy89:http1x-te-cl-egress

Conversation

@ziyziy89

@ziyziy89 ziyziy89 commented Nov 3, 2026

Copy link
Copy Markdown

HTTP1xCodec::generateHeader writes every header it is given and appends the deferred Content-Length last, so a message carrying both Transfer-Encoding: chunked and Content-Length goes out with both while generateBody chunk-encodes the body. Ingress hands applications exactly such a message: http_parser frames TE+CL by the chunking, and HTTPTransaction only checks that the dechunked body adds up to the Content-Length. A relay that forwards it without calling stripPerHopHeaders (the bundled sample proxy is one) sends both headers upstream, and since egress re-chunks every body piece, the forwarded Content-Length no longer matches the bytes on the wire. A backend that frames by Content-Length (TE.CL desync, CWE-444) then parses the tail of the client's body as its own request. Example: 50 one-byte chunks followed by an fe chunk holding GET /admin HTTP/1.1 ..., sent with Content-Length: 304 (the dechunked size). proxygen forwards Content-Length: 304, the 304th forwarded body byte is the end of fe\r\n, and the backend's next request is GET /admin. Responses relayed to a client take the same path.

Skip the deferred Content-Length once Transfer-Encoding: chunked has actually been written. RFC 9112 section 6.1 says a sender MUST NOT send Content-Length in a message that has Transfer-Encoding, and doing it in the serializer covers relays and application-built messages alike; the HTTP/1.0 dechunk path is unchanged because no Transfer-Encoding is written there. HttpShortContentLength built its TE+CL request through the client codec, so it now writes those bytes directly and keeps covering the server-side Content-Length/body mismatch check. The two new HTTP1xCodecTest cases fail before the change and pass after it, and the full ctest run (1820 tests) passes.

generateHeader appended the deferred Content-Length even after writing
Transfer-Encoding: chunked, so a relayed message that arrived with both
went out with both while generateBody re-chunked the body. A peer that
frames by Content-Length then reads the chunk framing as body and parses
the rest as another message. RFC 9112 section 6.1 forbids sending the
two together.

HttpShortContentLength built its TE+CL request through the client codec;
write the raw bytes instead so it keeps covering the server-side check.
@meta-cla meta-cla Bot added the CLA Signed label Nov 3, 2026
@meta-codesync

meta-codesync Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

@afrind has imported this pull request. If you are a Meta employee, you can view this in D129465359.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant