Skip to content

Commit

Permalink
Merge pull request #1259 from Kriechi/reject-empty-header-names
Browse files Browse the repository at this point in the history
reject empty header names
  • Loading branch information
Kriechi committed Sep 9, 2021
2 parents 13589e3 + 1140e3b commit 48bfc00
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
16 changes: 16 additions & 0 deletions src/h2/utilities.py
Expand Up @@ -206,6 +206,9 @@ def validate_headers(headers, hdr_validation_flags):
# For example, we avoid tuple unpacking in loops because it represents a
# fixed cost that we don't want to spend, instead indexing into the header
# tuples.
headers = _reject_empty_header_names(
headers, hdr_validation_flags
)
headers = _reject_uppercase_header_fields(
headers, hdr_validation_flags
)
Expand All @@ -229,6 +232,19 @@ def validate_headers(headers, hdr_validation_flags):
return headers


def _reject_empty_header_names(headers, hdr_validation_flags):
"""
Raises a ProtocolError if any header names are empty (length 0).
While hpack decodes such headers without errors, they are semantically
forbidden in HTTP, see RFC 7230, stating that they must be at least one
character long.
"""
for header in headers:
if len(header[0]) == 0:
raise ProtocolError("Received header name with zero length.")
yield header


def _reject_uppercase_header_fields(headers, hdr_validation_flags):
"""
Raises a ProtocolError if any uppercase character is found in a header
Expand Down
18 changes: 18 additions & 0 deletions test/test_invalid_headers.py
Expand Up @@ -688,6 +688,24 @@ def test_inbound_resp_header_extra_pseudo_headers(self,
with pytest.raises(h2.exceptions.ProtocolError):
list(h2.utilities.validate_headers(headers, hdr_validation_flags))

@pytest.mark.parametrize('hdr_validation_flags', hdr_validation_combos)
def test_inbound_header_name_length(self, hdr_validation_flags):
with pytest.raises(h2.exceptions.ProtocolError):
list(h2.utilities.validate_headers([(b'', b'foobar')], hdr_validation_flags))

def test_inbound_header_name_length_full_frame_decode(self, frame_factory):
f = frame_factory.build_headers_frame([])
f.data = b"\x00\x00\x05\x00\x00\x00\x00\x04"
data = f.serialize()

c = h2.connection.H2Connection(config=h2.config.H2Configuration(client_side=False))
c.initiate_connection()
c.receive_data(frame_factory.preamble())
c.clear_outbound_data_buffer()

with pytest.raises(h2.exceptions.ProtocolError, match="Received header name with zero length."):
c.receive_data(data)


class TestOversizedHeaders(object):
"""
Expand Down

0 comments on commit 48bfc00

Please sign in to comment.