From 8d8c17c999e532eededd1d535344b3f48030c01f Mon Sep 17 00:00:00 2001 From: "Codex (AI agent)" Date: Sat, 17 Oct 2026 04:18:16 +0530 Subject: [PATCH] Preserve bytes subclasses when encoding headers --- src/hpack/hpack.py | 6 +++--- tests/test_hpack.py | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/hpack/hpack.py b/src/hpack/hpack.py index 1aff8ab..e5ce1bf 100644 --- a/src/hpack/hpack.py +++ b/src/hpack/hpack.py @@ -152,11 +152,11 @@ def _to_bytes(value: bytes | str | Any) -> bytes: Convert anything to bytes through a UTF-8 encoded string """ t = type(value) - if t is bytes: - return value # type: ignore + if isinstance(value, bytes): + return value if t is not str: value = str(value) - return value.encode("utf-8") # type: ignore + return value.encode("utf-8") class Encoder: diff --git a/tests/test_hpack.py b/tests/test_hpack.py index e9c170c..a7d42d6 100644 --- a/tests/test_hpack.py +++ b/tests/test_hpack.py @@ -17,6 +17,15 @@ from hpack.hpack import _dict_to_iterable, _to_bytes +class BytesSubclass(bytes): + pass + + +@pytest.mark.parametrize('value', [b'', b'foobar', b'\x00\xff']) +def test_to_bytes_preserves_bytes_subclasses(value): + assert _to_bytes(BytesSubclass(value)) == value + + def test_to_bytes(): assert _to_bytes(b"foobar") == b"foobar" assert _to_bytes("foobar") == b"foobar" @@ -26,6 +35,23 @@ def test_to_bytes(): class TestHPACKEncoder: + @pytest.mark.parametrize('huffman', [False, True]) + @pytest.mark.parametrize('as_dict', [False, True]) + def test_bytes_subclass_headers(self, huffman, as_dict): + headers = [ + (BytesSubclass(b':method'), BytesSubclass(b'GET')), + (BytesSubclass(b'custom-key'), BytesSubclass(b'\x00\xff')), + ] + expected = [(b':method', b'GET'), (b'custom-key', b'\x00\xff')] + if as_dict: + # Dictionary pseudo-headers must move ahead of ordinary headers. + headers = dict(reversed(headers)) + + encoded = Encoder().encode(headers, huffman=huffman) + + assert encoded == Encoder().encode(expected, huffman=huffman) + assert Decoder().decode(encoded, raw=True) == expected + # These tests are stolen entirely from the IETF specification examples. def test_literal_header_field_with_indexing(self): """