Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/hpack/__init__.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .c_exceptions cimport *
from .c_table cimport *
2 changes: 1 addition & 1 deletion src/hpack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
from __future__ import annotations

from .exceptions import HPACKDecodingError, HPACKError, InvalidTableIndex, InvalidTableIndexError, InvalidTableSizeError, OversizedHeaderListError
from .py_exceptions import HPACKDecodingError, HPACKError, InvalidTableIndex, InvalidTableIndexError, InvalidTableSizeError, OversizedHeaderListError
from .hpack import Decoder, Encoder
from .struct import HeaderTuple, NeverIndexedHeaderTuple

Expand Down
17 changes: 17 additions & 0 deletions src/hpack/c_exceptions.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cdef class HPACKError(Exception):
pass

cdef class HPACKDecodingError(HPACKError):
pass

cdef class InvalidTableIndexError(HPACKDecodingError):
pass

cdef class InvalidTableIndex(InvalidTableIndexError):
pass

cdef class OversizedHeaderListError(HPACKDecodingError):
pass

cdef class InvalidTableSizeError(HPACKDecodingError):
pass
54 changes: 54 additions & 0 deletions src/hpack/c_exceptions.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class HPACKError(Exception):
"""
The base cdef class for all ``hpack`` exceptions.
"""
...


class HPACKDecodingError(HPACKError):
"""
An error has been encountered while performing HPACK decoding.
"""
...


class InvalidTableIndexError(HPACKDecodingError):
"""
An invalid table index was received.

.. versionadded:: 4.1.0
"""
...


class InvalidTableIndex(InvalidTableIndexError):
"""
An invalid table index was received.

.. deprecated:: 4.1.0
Renamed to :class:`InvalidTableIndexError`, use it instead.
"""
...


class OversizedHeaderListError(HPACKDecodingError):
"""
A header list that was larger than we allow has been received. This may be
a DoS attack.

.. versionadded:: 2.3.0
"""
...


class InvalidTableSizeError(HPACKDecodingError):
"""
An attempt was made to change the decoder table size to a value larger than
allowed, or the list was shrunk and the remote peer didn't shrink their
table size.

.. versionadded:: 3.0.0
"""
...


47 changes: 47 additions & 0 deletions src/hpack/c_exceptions.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
cdef class HPACKError(Exception):
"""
The base cdef class for all ``hpack`` exceptions.
"""



cdef class HPACKDecodingError(HPACKError):
"""
An error has been encountered while performing HPACK decoding.
"""



cdef class InvalidTableIndexError(HPACKDecodingError):
"""
An invalid table index was received.

.. versionadded:: 4.1.0
"""

cdef class InvalidTableIndex(InvalidTableIndexError): # noqa: N818
"""
An invalid table index was received.

.. deprecated:: 4.1.0
Renamed to :class:`InvalidTableIndexError`, use it instead.
"""


cdef class OversizedHeaderListError(HPACKDecodingError):
"""
A header list that was larger than we allow has been received. This may be
a DoS attack.

.. versionadded:: 2.3.0
"""


cdef class InvalidTableSizeError(HPACKDecodingError):
"""
An attempt was made to change the decoder table size to a value larger than
allowed, or the list was shrunk and the remote peer didn't shrink their
table size.

.. versionadded:: 3.0.0
"""
12 changes: 12 additions & 0 deletions src/hpack/c_huffman.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@


cdef class HuffmanEncoder:
"""
Encodes a string according to the Huffman encoding table defined in the
HPACK specification.
"""
cdef:
list huffman_code_list
list huffman_code_list_lengths

cpdef bytes encode(self, bytes bytes_to_encode)
63 changes: 63 additions & 0 deletions src/hpack/c_huffman.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

cdef class HuffmanEncoder:
"""
Encodes a string according to the Huffman encoding table defined in the
HPACK specification.
"""

def __init__(self, list huffman_code_list, list huffman_code_list_lengths) -> None:
self.huffman_code_list = huffman_code_list
self.huffman_code_list_lengths = huffman_code_list_lengths

cpdef bytes encode(self, bytes bytes_to_encode):
"""
Given a string of bytes, encodes them according to the HPACK Huffman
specification.
"""
cdef int byte

# If handed the empty string, just immediately return.
if not bytes_to_encode:
return b""

cdef int bin_int_len, bin_int
cdef size_t final_num = 0
cdef size_t final_int_len = 0
cdef size_t bits_to_be_padded, total_bytes
cdef str s

# Turn each byte into its huffman code. These codes aren't necessarily
# octet aligned, so keep track of how far through an octet we are. To
# handle this cleanly, just use a single giant integer.
for byte in bytes_to_encode:
bin_int_len = self.huffman_code_list_lengths[byte]
bin_int = self.huffman_code_list[byte] & (
2 ** (bin_int_len + 1) - 1
)
final_num <<= bin_int_len
final_num |= bin_int
final_int_len += bin_int_len

# Pad out to an octet with ones.
bits_to_be_padded = (8 - (final_int_len % 8)) % 8
final_num <<= bits_to_be_padded
final_num |= (1 << bits_to_be_padded) - 1

# Convert the number to hex and strip off the leading '0x' and the
# trailing 'L', if present.
s = hex(final_num)[2:].rstrip("L")

# If this is odd, prepend a zero.
s = "0" + s if len(s) % 2 != 0 else s

# This number should have twice as many digits as bytes. If not, we're
# missing some leading zeroes. Work out how many bytes we want and how
# many digits we have, then add the missing zero digits to the front.
total_bytes = (final_int_len + bits_to_be_padded) // 8
expected_digits = total_bytes * 2

if len(s) != expected_digits:
missing_digits = expected_digits - len(s)
s = ("0" * missing_digits) + s

return bytes.fromhex(s)
Loading