def test_request_examples_with_huffman(self): """ This section shows the same examples as the previous section, but using Huffman encoding for the literal values. """ d = Decoder() # Patch the decoder to use the Request Huffman tables, not the Response # ones. d.huffman_coder = HuffmanDecoder(REQUEST_CODES, REQUEST_CODES_LENGTH) first_header_set = [(":method", "GET"), (":scheme", "http"), (":path", "/"), (":authority", "www.example.com")] first_header_table = first_header_set[::-1] first_data = b"\x82\x87\x86\x04\x8b\xdb\x6d\x88\x3e\x68\xd1\xcb\x12\x25\xba\x7f" assert d.decode(first_data) == set(first_header_set) assert list(d.header_table) == [(n.encode("utf-8"), v.encode("utf-8")) for n, v in first_header_table] # This request takes advantage of the differential encoding of header # sets. second_header_set = [ (":method", "GET"), (":scheme", "http"), (":path", "/"), (":authority", "www.example.com"), ("cache-control", "no-cache"), ] second_header_table = second_header_set[::-1] second_data = b"\x1b\x86\x63\x65\x4a\x13\x98\xff" assert d.decode(second_data) == set(second_header_set) assert list(d.header_table) == [(n.encode("utf-8"), v.encode("utf-8")) for n, v in second_header_table] # This request has not enough headers in common with the previous # request to take advantage of the differential encoding. Therefore, # the reference set is emptied before encoding the header fields. third_header_set = [ (":method", "GET"), (":scheme", "https"), (":path", "/index.html"), (":authority", "www.example.com"), ("custom-key", "custom-value"), ] third_data = ( b"\x80\x85\x8c\x8b\x84\x00\x88\x4e\xb0\x8b\x74\x97\x90\xfa\x7f\x89" b"\x4e\xb0\x8b\x74\x97\x9a\x17\xa8\xff" ) assert d.decode(third_data) == set(third_header_set) # Don't check the header table here, it's just too complex to be # reliable. Check its length though. assert len(d.header_table) == 8
def test_can_decode_a_story(self, story): d = Decoder() # We support draft 5 of the HPACK spec. assert story['draft'] == 5 if story['context'] == 'request': d.huffman_coder = HuffmanDecoder(REQUEST_CODES, REQUEST_CODES_LENGTH) for case in story['cases']: d.header_table_size = case['header_table_size'] decoded_headers = d.decode(unhexlify(case['wire'])) # The correct headers are a list of dicts, which is annoying. correct_headers = {(item[0], item[1]) for header in case['headers'] for item in header.items()} assert correct_headers == decoded_headers
def test_can_encode_a_story_with_huffman(self, raw_story): d = Decoder() e = Encoder() if raw_story['context'] == 'request': d.huffman_coder = HuffmanDecoder(REQUEST_CODES, REQUEST_CODES_LENGTH) else: e.huffman_coder = HuffmanEncoder(RESPONSE_CODES, RESPONSE_CODES_LENGTH) for case in raw_story['cases']: # The input headers are a list of dicts, which is annoying. input_headers = {(item[0], item[1]) for header in case['headers'] for item in header.items()} encoded = e.encode(input_headers, huffman=True) decoded_headers = d.decode(encoded) assert input_headers == decoded_headers
def test_request_examples_with_huffman(self): """ This section shows the same examples as the previous section, but using Huffman encoding for the literal values. """ d = Decoder() # Patch the decoder to use the Request Huffman tables, not the Response # ones. d.huffman_coder = HuffmanDecoder(REQUEST_CODES, REQUEST_CODES_LENGTH) first_header_set = [ ( ':method', 'GET', ), ( ':scheme', 'http', ), ( ':path', '/', ), (':authority', 'www.example.com'), ] first_header_table = first_header_set[::-1] first_data = ( b'\x82\x87\x86\x04\x8b\xdb\x6d\x88\x3e\x68\xd1\xcb\x12\x25\xba\x7f' ) assert d.decode(first_data) == set(first_header_set) assert list(d.header_table) == [(n.encode('utf-8'), v.encode('utf-8')) for n, v in first_header_table] # This request takes advantage of the differential encoding of header # sets. second_header_set = [ ( ':method', 'GET', ), ( ':scheme', 'http', ), ( ':path', '/', ), ( ':authority', 'www.example.com', ), ('cache-control', 'no-cache'), ] second_header_table = second_header_set[::-1] second_data = b'\x1b\x86\x63\x65\x4a\x13\x98\xff' assert d.decode(second_data) == set(second_header_set) assert list(d.header_table) == [(n.encode('utf-8'), v.encode('utf-8')) for n, v in second_header_table] # This request has not enough headers in common with the previous # request to take advantage of the differential encoding. Therefore, # the reference set is emptied before encoding the header fields. third_header_set = [ ( ':method', 'GET', ), ( ':scheme', 'https', ), ( ':path', '/index.html', ), ( ':authority', 'www.example.com', ), ('custom-key', 'custom-value'), ] third_data = ( b'\x80\x85\x8c\x8b\x84\x00\x88\x4e\xb0\x8b\x74\x97\x90\xfa\x7f\x89' b'\x4e\xb0\x8b\x74\x97\x9a\x17\xa8\xff') assert d.decode(third_data) == set(third_header_set) # Don't check the header table here, it's just too complex to be # reliable. Check its length though. assert len(d.header_table) == 8