1- # -*- coding: utf-8 -*-
21"""
32hpack/hpack
43~~~~~~~~~~~
54
65Implements the HPACK header compression algorithm as detailed by the IETF.
76"""
87import logging
8+ from typing import Any , Generator , Union
99
1010from .table import HeaderTable , table_entry_size
1111from .exceptions import (
2929# as prefix numbers are not zero indexed.
3030_PREFIX_BIT_MAX_NUMBERS = [(2 ** i ) - 1 for i in range (9 )]
3131
32- try : # pragma: no cover
33- basestring = basestring
34- except NameError : # pragma: no cover
35- basestring = (str , bytes )
36-
37-
3832# We default the maximum header list we're willing to accept to 64kB. That's a
3933# lot of headers, but if applications want to raise it they can do.
4034DEFAULT_MAX_HEADER_LIST_SIZE = 2 ** 16
4135
4236
43- def _unicode_if_needed (header , raw ) :
37+ def _unicode_if_needed (header : HeaderTuple , raw : bool ) -> HeaderTuple :
4438 """
4539 Provides a header as a unicode string if raw is False, otherwise returns
4640 it as a bytestring.
4741 """
48- name = bytes (header [0 ])
49- value = bytes (header [1 ])
42+ name = bytes (header [0 ]) # type: ignore
43+ value = bytes (header [1 ]) # type: ignore
5044 if not raw :
51- name = name .decode ('utf-8' )
52- value = value . decode ( 'utf-8' )
53- return header .__class__ (name , value )
45+ return header . __class__ ( name .decode ('utf-8' ), value . decode ( 'utf-8' ) )
46+ else :
47+ return header .__class__ (name , value )
5448
5549
56- def encode_integer (integer , prefix_bits ) :
50+ def encode_integer (integer : int , prefix_bits : int ) -> bytearray :
5751 """
5852 This encodes an integer according to the wacky integer encoding rules
5953 defined in the HPACK spec.
@@ -87,7 +81,7 @@ def encode_integer(integer, prefix_bits):
8781 return bytearray (elements )
8882
8983
90- def decode_integer (data , prefix_bits ) :
84+ def decode_integer (data : bytes , prefix_bits : int ) -> tuple [ int , int ] :
9185 """
9286 This decodes an integer according to the wacky integer encoding rules
9387 defined in the HPACK spec. Returns a tuple of the decoded integer and the
@@ -128,7 +122,8 @@ def decode_integer(data, prefix_bits):
128122 return number , index
129123
130124
131- def _dict_to_iterable (header_dict ):
125+ def _dict_to_iterable (header_dict : dict [Union [bytes , str ], Union [bytes , str ]]) \
126+ -> Generator [tuple [Union [bytes , str ], Union [bytes , str ]], None , None ]:
132127 """
133128 This converts a dictionary to an iterable of two-tuples. This is a
134129 HPACK-specific function because it pulls "special-headers" out first and
@@ -143,7 +138,7 @@ def _dict_to_iterable(header_dict):
143138 yield key , header_dict [key ]
144139
145140
146- def _to_bytes (value ) :
141+ def _to_bytes (value : Union [ bytes , str , Any ]) -> bytes :
147142 """
148143 Convert anything to bytes through a UTF-8 encoded string
149144 """
@@ -161,27 +156,29 @@ class Encoder:
161156 HTTP/2 header blocks.
162157 """
163158
164- def __init__ (self ):
159+ def __init__ (self ) -> None :
165160 self .header_table = HeaderTable ()
166161 self .huffman_coder = HuffmanEncoder (
167162 REQUEST_CODES , REQUEST_CODES_LENGTH
168163 )
169- self .table_size_changes = []
164+ self .table_size_changes : list [ int ] = []
170165
171166 @property
172- def header_table_size (self ):
167+ def header_table_size (self ) -> int :
173168 """
174169 Controls the size of the HPACK header table.
175170 """
176171 return self .header_table .maxsize
177172
178173 @header_table_size .setter
179- def header_table_size (self , value ) :
174+ def header_table_size (self , value : int ) -> None :
180175 self .header_table .maxsize = value
181176 if self .header_table .resized :
182177 self .table_size_changes .append (value )
183178
184- def encode (self , headers , huffman = True ):
179+ def encode (self ,
180+ headers : list [Union [HeaderTuple , tuple [bytes , bytes ], dict [Any , Any ]]],
181+ huffman : bool = True ) -> bytes :
185182 """
186183 Takes a set of headers and encodes them into a HPACK-encoded header
187184 block.
@@ -256,13 +253,13 @@ def encode(self, headers, huffman=True):
256253 header = (_to_bytes (header [0 ]), _to_bytes (header [1 ]))
257254 header_block .append (self .add (header , sensitive , huffman ))
258255
259- header_block = b'' .join (header_block )
256+ encoded = b'' .join (header_block )
260257
261- log .debug ("Encoded header block to %s" , header_block )
258+ log .debug ("Encoded header block to %s" , encoded )
262259
263- return header_block
260+ return encoded
264261
265- def add (self , to_add , sensitive , huffman = False ):
262+ def add (self , to_add : tuple [ bytes , bytes ], sensitive : bool , huffman : bool = False ) -> bytes :
266263 """
267264 This function takes a header key-value tuple and serializes it.
268265 """
@@ -311,15 +308,15 @@ def add(self, to_add, sensitive, huffman=False):
311308
312309 return encoded
313310
314- def _encode_indexed (self , index ) :
311+ def _encode_indexed (self , index : int ) -> bytes :
315312 """
316313 Encodes a header using the indexed representation.
317314 """
318315 field = encode_integer (index , 7 )
319316 field [0 ] |= 0x80 # we set the top bit
320317 return bytes (field )
321318
322- def _encode_literal (self , name , value , indexbit , huffman = False ):
319+ def _encode_literal (self , name : bytes , value : bytes , indexbit : bytes , huffman : bool = False ) -> bytes :
323320 """
324321 Encodes a header with a literal name and literal value. If ``indexing``
325322 is True, the header will be added to the header table: otherwise it
@@ -340,7 +337,7 @@ def _encode_literal(self, name, value, indexbit, huffman=False):
340337 [indexbit , bytes (name_len ), name , bytes (value_len ), value ]
341338 )
342339
343- def _encode_indexed_literal (self , index , value , indexbit , huffman = False ):
340+ def _encode_indexed_literal (self , index : int , value : bytes , indexbit : bytes , huffman : bool = False ) -> bytes :
344341 """
345342 Encodes a header with an indexed name and a literal value and performs
346343 incremental indexing.
@@ -362,16 +359,16 @@ def _encode_indexed_literal(self, index, value, indexbit, huffman=False):
362359
363360 return b'' .join ([bytes (prefix ), bytes (value_len ), value ])
364361
365- def _encode_table_size_change (self ):
362+ def _encode_table_size_change (self ) -> bytes :
366363 """
367364 Produces the encoded form of all header table size change context
368365 updates.
369366 """
370367 block = b''
371368 for size_bytes in self .table_size_changes :
372- size_bytes = encode_integer (size_bytes , 5 )
373- size_bytes [0 ] |= 0x20
374- block += bytes (size_bytes )
369+ b = encode_integer (size_bytes , 5 )
370+ b [0 ] |= 0x20
371+ block += bytes (b )
375372 self .table_size_changes = []
376373 return block
377374
@@ -397,7 +394,7 @@ class Decoder:
397394 Defaults to 64kB.
398395 :type max_header_list_size: ``int``
399396 """
400- def __init__ (self , max_header_list_size = DEFAULT_MAX_HEADER_LIST_SIZE ):
397+ def __init__ (self , max_header_list_size : int = DEFAULT_MAX_HEADER_LIST_SIZE ) -> None :
401398 self .header_table = HeaderTable ()
402399
403400 #: The maximum decompressed size we will allow for any single header
@@ -426,17 +423,17 @@ def __init__(self, max_header_list_size=DEFAULT_MAX_HEADER_LIST_SIZE):
426423 self .max_allowed_table_size = self .header_table .maxsize
427424
428425 @property
429- def header_table_size (self ):
426+ def header_table_size (self ) -> int :
430427 """
431428 Controls the size of the HPACK header table.
432429 """
433430 return self .header_table .maxsize
434431
435432 @header_table_size .setter
436- def header_table_size (self , value ) :
433+ def header_table_size (self , value : int ) -> None :
437434 self .header_table .maxsize = value
438435
439- def decode (self , data , raw = False ):
436+ def decode (self , data : bytes , raw : bool = False ) -> list [ Union [ HeaderTuple , NeverIndexedHeaderTuple ]] :
440437 """
441438 Takes an HPACK-encoded header block and decodes it into a header set.
442439
@@ -454,7 +451,7 @@ def decode(self, data, raw=False):
454451 log .debug ("Decoding %s" , data )
455452
456453 data_mem = memoryview (data )
457- headers = []
454+ headers : list [ Union [ HeaderTuple , NeverIndexedHeaderTuple ]] = []
458455 data_len = len (data )
459456 inflated_size = 0
460457 current_index = 0
@@ -501,7 +498,7 @@ def decode(self, data, raw=False):
501498
502499 if header :
503500 headers .append (header )
504- inflated_size += table_entry_size (* header )
501+ inflated_size += table_entry_size (header [ 0 ], header [ 1 ] )
505502
506503 if inflated_size > self .max_header_list_size :
507504 raise OversizedHeaderListError (
@@ -521,7 +518,7 @@ def decode(self, data, raw=False):
521518 except UnicodeDecodeError :
522519 raise HPACKDecodingError ("Unable to decode headers as UTF-8." )
523520
524- def _assert_valid_table_size (self ):
521+ def _assert_valid_table_size (self ) -> None :
525522 """
526523 Check that the table size set by the encoder is lower than the maximum
527524 we expect to have.
@@ -531,7 +528,7 @@ def _assert_valid_table_size(self):
531528 "Encoder did not shrink table size to within the max"
532529 )
533530
534- def _update_encoding_context (self , data ) :
531+ def _update_encoding_context (self , data : bytes ) -> int :
535532 """
536533 Handles a byte that updates the encoding context.
537534 """
@@ -544,7 +541,7 @@ def _update_encoding_context(self, data):
544541 self .header_table_size = new_size
545542 return consumed
546543
547- def _decode_indexed (self , data ) :
544+ def _decode_indexed (self , data : bytes ) -> tuple [ HeaderTuple , int ] :
548545 """
549546 Decodes a header represented using the indexed representation.
550547 """
@@ -553,13 +550,13 @@ def _decode_indexed(self, data):
553550 log .debug ("Decoded %s, consumed %d" , header , consumed )
554551 return header , consumed
555552
556- def _decode_literal_no_index (self , data ) :
553+ def _decode_literal_no_index (self , data : bytes ) -> tuple [ HeaderTuple , int ] :
557554 return self ._decode_literal (data , False )
558555
559- def _decode_literal_index (self , data ) :
556+ def _decode_literal_index (self , data : bytes ) -> tuple [ HeaderTuple , int ] :
560557 return self ._decode_literal (data , True )
561558
562- def _decode_literal (self , data , should_index ) :
559+ def _decode_literal (self , data : bytes , should_index : bool ) -> tuple [ HeaderTuple , int ] :
563560 """
564561 Decodes a header represented with a literal.
565562 """
@@ -577,7 +574,7 @@ def _decode_literal(self, data, should_index):
577574 high_byte = data [0 ]
578575 indexed_name = high_byte & 0x0F
579576 name_len = 4
580- not_indexable = high_byte & 0x10
577+ not_indexable = bool ( high_byte & 0x10 )
581578
582579 if indexed_name :
583580 # Indexed header name.
@@ -616,6 +613,7 @@ def _decode_literal(self, data, should_index):
616613
617614 # If we have been told never to index the header field, encode that in
618615 # the tuple we use.
616+ header : HeaderTuple
619617 if not_indexable :
620618 header = NeverIndexedHeaderTuple (name , value )
621619 else :
0 commit comments