trillium-http-v1.3.2
·
61 commits
to main
since this release
Changed
- All protocol versions: Previously, when upgrading on the client or server, outbound bodies were intentionally dropped. As of this release, content-length is stripped and any body that has been set is sent off before transitioning to upgrade.
Fixed
- HTTP/2 server: a bidirectional or upgraded stream (such as a gRPC streaming RPC or a WebSocket-over-HTTP/2 connection) was torn down as soon as the client half-closed its request side, even while the server was still streaming the response. The rest of the response and any trailers were dropped, surfacing to the client as a stream reset or broken-pipe error. The server now keeps its response side open until the response completes. Relatedly, a handler's writes to a stream the client had reset mid-flight were silently discarded; they now report a broken-pipe error so the handler can stop.
- HTTP/3: reading a body (request bodies in the server role, response bodies in the client role) could hang or fail with a spurious
UnexpectedEofwhen the body's first DATA frame had been buffered alongside the headers and was then read with a buffer smaller than a frame header — as happens reading a body one byte at a time. Bodies read with a larger buffer, or whose body arrived separately from the headers, were unaffected. These now decode correctly. - HTTP/2 server: an idle extended-CONNECT (RFC 8441) upgrade — or any response whose body source is not yet ready to produce data — could busy-spin the connection, burning CPU and flooding logs with
drivetrace lines while waiting for the next write. The connection now sleeps until there is work to do. - HTTP/2 client: a request could hang forever when the connection closed without delivering a response — a graceful
GOAWAY, a peer FIN, or an I/O error — unless the server had explicitly reset that stream. In-flight requests (awaiting response headers, reading a response body, or writing to an upgraded stream) now surface a connection-aborted / broken-pipe error instead of hanging.
Security
- HTTP/2 server: a peer could exhaust server memory by opening a header block (a
HEADERSframe withoutEND_HEADERS) and then sending an unbounded stream ofCONTINUATIONframes without ever ending it — the "CONTINUATION flood" (CVE-2024-27316 class). The cumulative compressed header block is now bounded by the advertisedSETTINGS_MAX_HEADER_LIST_SIZE(HttpConfig::max_header_list_size, default 32 KiB); a block exceeding it closes the connection withGOAWAY(ENHANCE_YOUR_CALM)before decoding. - HTTP/2: a message whose
content-lengthheader disagreed with the actual length of its body was accepted rather than rejected — on the server for request bodies, and on the client for response bodies. A body longer than declared was silently truncated at the declared length; a shorter one was only caught if the body happened to be read to its end. The gap between a declared and actual body length is a request/response-smuggling / desync primitive, most concretely when the message is forwarded to an HTTP/1 peer whose parser trustscontent-length. Both directions are now rejected with a stream error: a body that overruns its declared length the moment it does so, and a short one when the stream ends.