Conversation
Coverage Report for CI Build 0Coverage increased (+0.04%) to 90.547%Details
Uncovered Changes
Coverage Regressions5 previously-covered lines in 3 files lost coverage.
Coverage Stats
馃挍 - Coveralls |
A Transfer-Encoding value with a parameter, such as
"custom; level=1, chunked", failed with {:invalid_token_list, value}
because the value was parsed as a plain list of tokens. RFC 9110 10.1.4
allows parameters on a transfer coding, as a token or a quoted string.
Transfer-Encoding values are now parsed with their parameters and only
the coding names are kept, so the final coding of a response still
decides between chunked framing and reading until close. The chunked
coding defines no parameters and RFC 9112 7.1 says their presence
should be treated as an error, so chunked with parameters is still
rejected.
The same parser checks the Transfer-Encoding headers passed to request/5
with a streamed body and no Content-Length, so a value such as
"gzip;q=1" is accepted there. The fields are combined with ", " into
one value before parsing (RFC 9110 5.3). If chunked or identity is among
the codings the headers are sent unchanged, as before. Otherwise chunked
is appended to the last field, so it ends up as the final coding once.
A Transfer-Encoding field with no list elements, such as an empty value
or ",", failed the response with :empty_token_list and closed the
connection. For a response to HEAD this happened before the rule that
such a response has no body, and a comma-only field between two
nonempty Transfer-Encoding fields failed the response instead of being
ignored.
RFC 9110 5.6.1 allows a #transfer-coding list with zero elements, so
such a field now adds no transfer coding when the framing is chosen. A
response with only an empty Transfer-Encoding and no Content-Length has
no framing, so its body is read until the connection closes (RFC 9112
6.3). The field still counts as present: with Content-Length it's an
error, and it makes an HTTP/1.0 response, including a 1xx one, close
the connection (RFC 9112 6.1).
Transfer-Encoding values are parsed only where they decide the framing,
combined into one value as on the request side, so a malformed value no
longer fails a response to HEAD, a 204 or 304 response, or a 2xx
response to CONNECT, whose Transfer-Encoding RFC 9110 9.3.6 says to
ignore. Where it does fail, the error comes after the :headers event
(with :stream_headers the field itself can be emitted first) and not
while the header section is incomplete, other header errors in the same
section are reported instead of it, and with Content-Length the error is
:transfer_encoding_and_content_length instead of {:invalid_token_list,
value}.
On the request side, a Transfer-Encoding field with no codings passed to
request/5 with a streamed body counts as no codings: when chunked is
appended to such a last field it replaces the empty value.
The response fields of a request were reset after an informational response so the final response could be parsed, and that dropped the Connection options of the 1xx response. A "close" option in a 1xx response was ignored, and the connection stayed open for the requests pipelined behind it. RFC 9112 9.6 has a client that receives "close" close the connection after reading the response containing it. A 1xx isn't the complete response, so Mint now keeps the option and closes the connection after the final response, handling it as if the final response carried it: the connection is closed after the final response, including a 101 or an HTTP/1.0 keep-alive one, and queued requests fail with :unprocessed. A 2xx response to CONNECT still keeps the connection open for the tunnel. Other Connection options of a 1xx response, such as keep-alive, don't apply to the final response.
The comment on message_body/1 quoted RFC 7230 3.3.3, which RFC 9112 6.3 replaces. It now summarises the RFC 9112 6.3 rules the function applies, starting with the responses that have no body, and the comment on the Transfer-Encoding clause uses the same section's wording.
After a 101 response the connection stayed open with the queued requests in place, so bytes arriving later, which belong to the protocol the server switched to (RFC 9110 15.2.2), were parsed as HTTP/1 responses to those requests. Queued requests now fail with the new :connection_upgraded error when the 101 response completes. Bytes arriving later are unexpected data as long as no new request is made on the connection. A failed request that was streaming its body can't stream the rest of it. :unprocessed isn't used because the pipelined request bytes reached the server as part of the new protocol, so the request might have been processed. The bytes after the 101 response in the same packet are still delivered as data for the upgrade request.
ericmj
force-pushed
the
http1-followups
branch
from
September 28, 2026 14:55
7f422d7 to
defd0a8
Compare
ericmj
marked this pull request as ready for review
September 28, 2026 16:23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five fixes to HTTP/1 response handling, one commit each, meant to be rebase-merged rather than squashed.
custom; level=1, chunked, are accepted (RFC 9110 10.1.4). Chunked with parameters is still an error (RFC 9112 7.1). Multiple Transfer-Encoding fields are combined before parsing. Request headers passed with a streamed body and no Content-Length go through the same parser, and chunked is appended after the last coding unless chunked or identity is already there.Connection: closein a 1xx response closes the connection after the final response, as if the final response carried it. Before, it was dropped when the 1xx was reset. Queued requests fail with:unprocessed, also when the final response is a 101.message_body/1cites RFC 9112 6.3 instead of RFC 7230.:connection_upgradederror, since later bytes belong to the new protocol.:unprocessedisn't used because the server may have received the request bytes as part of that protocol.