Repository navigation
Conversation
While waiting for CONTINUATION frames, the client compared the size of the buffered compressed header block with its advertised SETTINGS_MAX_HEADER_LIST_SIZE, assuming a compressed block is never larger than the header list it decodes to. Huffman coding can make a string longer than its octets (RFC 7541 5.2), so a valid block whose decoded list is under the limit could exceed it on the wire. With a limit of 1,000 bytes, a 475-byte header list that encodes to 1,307 bytes was accepted in a single HEADERS frame and closed the connection with PROTOCOL_ERROR when split over HEADERS and CONTINUATION. The limit is enforced on the decoded header list, and the fragments buffered before END_HEADERS are bounded by an upper bound on the encoded size of a header list within the limit, assuming minimal integer representations (RFC 7541 5.1) and at most two dynamic table size updates (RFC 7541 4.2). HPACK decoders accept redundant zero continuation bytes in integers and any number of size updates, so no finite bound covers every block that decodes to such a list. The fragment that carries END_HEADERS isn't counted, and the complete block is then judged by its decoded size. A Huffman-coded octet takes at most 30 bits (RFC 7541 Appendix B). A minimal integer below 2^32 takes at most 6 bytes, so a field has at most 13 bytes of prefixes and integers (a representation byte, the name length and the value length) and less than 2 bytes of Huffman padding, 15 bytes in total. That's less than the 120 bytes its 32-byte overhead (RFC 9113 6.5.2) contributes at the 30/8 ratio. The two size updates take at most 6 bytes each. The bound is max_header_list_size * 30 / 8 + 12 bytes, and a peer that buffers more than that gets a connection error.
ericmj
added this pull request to stack #537
October 16, 2026 13:04
Coverage Report for CI Build 81963866Coverage increased (+0.02%) to 90.527%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions1 previously-covered line in 1 file lost coverage.
Coverage Stats
馃挍 - Coveralls |
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.
While waiting for CONTINUATION frames, the client compared the size of the buffered compressed header block with its advertised SETTINGS_MAX_HEADER_LIST_SIZE, assuming a compressed block is never larger than the header list it decodes to. Huffman coding can make a string longer than its octets (RFC 7541 5.2), so a valid block whose decoded list is under the limit could exceed it on the wire. With a limit of 1,000 bytes, a 475-byte header list that encodes to 1,307 bytes was accepted in a single HEADERS frame and closed the connection with PROTOCOL_ERROR when split over HEADERS and CONTINUATION.
The limit is enforced on the decoded header list, and the fragments buffered before END_HEADERS are bounded by an upper bound on the encoded size of a header list within the limit, assuming minimal integer representations (RFC 7541 5.1) and at most two dynamic table size updates (RFC 7541 4.2). HPACK decoders accept redundant zero continuation bytes in integers and any number of size updates, so no finite bound covers every block that decodes to such a list. The fragment that carries END_HEADERS isn't counted, and the complete block is then judged by its decoded size.
A Huffman-coded octet takes at most 30 bits (RFC 7541 Appendix B). A minimal integer below 2^32 takes at most 6 bytes, so a field has at most 13 bytes of prefixes and integers (a representation byte, the name length and the value length) and less than 2 bytes of Huffman padding, 15 bytes in total. That's less than the 120 bytes its 32-byte overhead (RFC 9113 6.5.2) contributes at the 30/8 ratio. The two size updates take at most 6 bytes each. The bound is
max_header_list_size * 30 / 8 + 12bytes, and a peer that buffers more than that gets a connection error.