Skip to content

Commit

Permalink
reject empty header names
Browse files Browse the repository at this point in the history
fixes #1257
  • Loading branch information
Kriechi committed Sep 7, 2021
1 parent 13589e3 commit 1140e3b
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 1140e3b

Please sign in to comment.