Codebase list python-hpack / c614532
Merge pull request #31 from Stranger6667/optimizations Some PEP8 & simplifications Cory Benfield 8 years ago
9 changed file(s) with 46 addition(s) and 42 deletion(s). Raw diff Collapse all Expand all
3030
3131 max_number = (2 ** prefix_bits) - 1
3232
33 if (integer < max_number):
33 if integer < max_number:
3434 return bytearray([integer]) # Seriously?
3535 else:
3636 elements = [max_number]
37 integer = integer - max_number
37 integer -= max_number
3838
3939 while integer >= 128:
4040 elements.append((integer % 128) + 128)
41 integer = integer // 128 # We need integer division
41 integer //= 128 # We need integer division
4242
4343 elements.append(integer)
4444
6060 try:
6161 number = to_byte(data[index]) & mask
6262
63 if (number == max_number):
63 if number == max_number:
6464
6565 while True:
6666 index += 1
7878
7979 log.debug("Decoded %d, consumed %d bytes", number, index + 1)
8080
81 return (number, index + 1)
81 return number, index + 1
8282
8383
8484 def _to_bytes(string):
219219 Encodes a header using the indexed representation.
220220 """
221221 field = encode_integer(index, 7)
222 field[0] = field[0] | 0x80 # we set the top bit
222 field[0] |= 0x80 # we set the top bit
223223 return bytes(field)
224224
225225 def _encode_literal(self, name, value, indexbit, huffman=False):
115115 # Pad out to an octet with ones.
116116 bits_to_be_padded = (8 - (final_int_len % 8)) % 8
117117 final_num <<= bits_to_be_padded
118 final_num |= (1 << (bits_to_be_padded)) - 1
118 final_num |= (1 << bits_to_be_padded) - 1
119119
120120 # Convert the number to hex and strip off the leading '0x' and the
121121 # trailing 'L', if present.
0 # -*- coding: utf-8 -*-
01 from collections import deque
12 import logging
23
1112
1213 This size is mostly irrelevant to us and defined
1314 specifically to accommodate memory management for
14 lower level implementions. The 32 extra bytes are
15 lower level implementations. The 32 extra bytes are
1516 considered the "maximum" overhead that would be
1617 required to represent each entry in the table.
1718
163164 for (i, (n, v)) in enumerate(HeaderTable.STATIC_TABLE):
164165 if n == name:
165166 if v == value:
166 return (i + 1, n, v)
167 return i + 1, n, v
167168 elif partial is None:
168169 partial = (i + 1, n, None)
169170 for (i, (n, v)) in enumerate(self.dynamic_entries):
170171 if n == name:
171172 if v == value:
172 return (i + offset + 1, n, v)
173 return i + offset + 1, n, v
173174 elif partial is None:
174175 partial = (i + offset + 1, n, None)
175176 return partial
0 # -*- coding: utf-8 -*-
01 import json
12 import os
23
34 from binascii import hexlify
45 from invoke import task
56 from hyper.http20.hpack import Encoder
7
68
79 @task
810 def hpack():
3133 # For each file, build our output.
3234 for source, outname in raw_story_files:
3335 with open(source, 'rb') as f:
34 indata = json.loads(f.read())
36 indata = json.load(f)
3537
3638 # Prepare the output and the encoder.
3739 output = {
4143 e = Encoder()
4244
4345 for case in indata['cases']:
44 outcase = {'header_table_size': e.header_table_size}
45 outcase['headers'] = case['headers']
46 outcase = {
47 'header_table_size': e.header_table_size,
48 'headers': case['headers'],
49 }
4650 headers = []
4751
4852 for header in case['headers']:
2121 for name in os.listdir('test/test_fixtures/raw-data')
2222 )
2323
24 @pytest.fixture(scope="class",
25 params=story_files)
24
25 @pytest.fixture(scope='class', params=story_files)
2626 def story(request):
2727 """
2828 Provides a detailed HPACK story to test with.
2929 """
30 path = request.param
31 with open(path, 'r', encoding='utf-8') as f:
32 details = json.loads(f.read())
30 with open(request.param, 'r', encoding='utf-8') as f:
31 return json.load(f)
3332
34 return details
3533
36 @pytest.fixture(scope="class", params=raw_story_files)
34 @pytest.fixture(scope='class', params=raw_story_files)
3735 def raw_story(request):
3836 """
3937 Provides a detailed HPACK story to test the encoder with.
4038 """
41 path = request.param
42 with open(path, 'r', encoding='utf-8') as f:
43 details = json.loads(f.read())
44
45 return details
39 with open(request.param, 'r', encoding='utf-8') as f:
40 return json.load(f)
4343 header_set = [
4444 (':method', 'GET', True),
4545 (':path', '/jimiscool/', True),
46 ('customkey','sensitiveinfo',True)
46 ('customkey', 'sensitiveinfo', True)
4747 ]
4848 assert e.encode(header_set, huffman=True) == result
4949
403403 (':path', '/',),
404404 (':authority', 'www.example.com'),
405405 ]
406 first_header_table = first_header_set[::-1]
407406 first_data = (
408407 b'\x82\x86\x84\x01\x8c\xf1\xe3\xc2\xe5\xf2:k\xa0\xab\x90\xf4\xff'
409408 )
66 from hpack.hpack import Decoder, Encoder
77 from binascii import unhexlify
88 from pytest import skip
9
910
1011 class TestHPACKDecoderIntegration(object):
1112 def test_can_decode_a_story(self, story):
0 # -*- coding: utf-8 -*-
01 from hpack.huffman import HuffmanDecoder, HuffmanEncoder
12 from hpack.huffman_constants import REQUEST_CODES, REQUEST_CODES_LENGTH
23
34
45 class TestHuffman(object):
6
57 def test_request_huffman_decoder(self):
6 decoder = HuffmanDecoder(REQUEST_CODES,REQUEST_CODES_LENGTH)
8 decoder = HuffmanDecoder(REQUEST_CODES, REQUEST_CODES_LENGTH)
79 assert decoder.decode(b'\xf1\xe3\xc2\xe5\xf2:k\xa0\xab\x90\xf4\xff') == b"www.example.com"
810 assert decoder.decode(b'\xa8\xeb\x10d\x9c\xbf') == b"no-cache"
911 assert decoder.decode(b'%\xa8I\xe9[\xa9}\x7f') == b"custom-key"
1113
1214 def test_request_huffman_encode(self):
1315 encoder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH)
14 assert encoder.encode(b"www.example.com") == (b'\xf1\xe3\xc2\xe5\xf2:k\xa0\xab\x90\xf4\xff')
15 assert encoder.encode(b"no-cache") == (b'\xa8\xeb\x10d\x9c\xbf')
16 assert encoder.encode(b"custom-key") == (b'%\xa8I\xe9[\xa9}\x7f')
17 assert encoder.encode(b"custom-value") == (b'%\xa8I\xe9[\xb8\xe8\xb4\xbf')
16 assert encoder.encode(b"www.example.com") == b'\xf1\xe3\xc2\xe5\xf2:k\xa0\xab\x90\xf4\xff'
17 assert encoder.encode(b"no-cache") == b'\xa8\xeb\x10d\x9c\xbf'
18 assert encoder.encode(b"custom-key") == b'%\xa8I\xe9[\xa9}\x7f'
19 assert encoder.encode(b"custom-value") == b'%\xa8I\xe9[\xb8\xe8\xb4\xbf'
1820
1921 def test_eos_terminates_decode_request(self):
20 decoder = HuffmanDecoder(REQUEST_CODES,REQUEST_CODES_LENGTH)
22 decoder = HuffmanDecoder(REQUEST_CODES, REQUEST_CODES_LENGTH)
2123 assert decoder.decode(b'\xff\xff\xff\xfc') == b''
0 # -*- coding: utf-8 -*-
01 from hpack.table import HeaderTable, table_entry_size
12 from hpack.exceptions import InvalidTableIndex
23 import pytest
56 is_py2 = _ver[0] == 2
67 is_py3 = _ver[0] == 3
78
9
810 class TestPackageFunctions(object):
911 def test_table_entry_size(self):
1012 res = table_entry_size(b'TestValue', b'TestName')
1113 assert res == 49
14
1215
1316 class TestHeaderTable(object):
1417 def test_get_by_index_dynamic_table(self):
3235 def test_get_by_index_zero_index(self):
3336 tbl = HeaderTable()
3437 with pytest.raises(InvalidTableIndex):
35 res = tbl.get_by_index(0)
38 tbl.get_by_index(0)
3639
3740 def test_get_by_index_out_of_range(self):
3841 tbl = HeaderTable()
3942 off = len(HeaderTable.STATIC_TABLE)
4043 tbl.add(b'TestName', b'TestValue')
4144 with pytest.raises(InvalidTableIndex):
42 res = tbl.get_by_index(off+2)
45 tbl.get_by_index(off + 2)
4346
4447 def test_repr(self):
4548 tbl = HeaderTable()
4851 tbl.add(b'TestName2', b'TestValue2')
4952 # Meh, I hate that I have to do this to test
5053 # repr
51 if(is_py3):
54 if is_py3:
5255 exp = ("HeaderTable(4096, False, deque([" +
5356 "(b'TestName2', b'TestValue2'), " +
5457 "(b'TestName2', b'TestValue2'), " +
8891 tbl = HeaderTable()
8992 idx = len(HeaderTable.STATIC_TABLE) + 1
9093 tbl.add(b'TestName', b'TestValue')
91 exp = (idx , b'TestName', b'TestValue')
94 exp = (idx, b'TestName', b'TestValue')
9295 res = tbl.search(b'TestName', b'TestValue')
9396 assert res == exp
9497
9699 tbl = HeaderTable()
97100 idx = len(HeaderTable.STATIC_TABLE) + 1
98101 tbl.add(b'TestName', b'TestValue')
99 exp = (idx , b'TestName', None)
102 exp = (idx, b'TestName', None)
100103 res = tbl.search(b'TestName', b'NotInTable')
101104 assert res == exp
102105
103106 def test_search_no_match(self):
104107 tbl = HeaderTable()
105 idx = len(HeaderTable.STATIC_TABLE)
106108 tbl.add(b'TestName', b'TestValue')
107109 res = tbl.search(b'NotInTable', b'NotInTable')
108110 assert res is None
115117 tbl = HeaderTable()
116118 exp = int(HeaderTable.DEFAULT_SIZE / 2)
117119 tbl.maxsize = exp
118 assert tbl.resized == True
120 assert tbl.resized is True
119121 assert tbl.maxsize == exp
120122 tbl.resized = False
121123 tbl.maxsize = exp
122 assert tbl.resized == False
124 assert tbl.resized is False
123125 assert tbl.maxsize == exp
124126
125127 def test_size(self):
131133
132134 def test_shrink_maxsize_is_zero(self):
133135 tbl = HeaderTable()
134 tbl.add(b'TestName',b'TestValue')
136 tbl.add(b'TestName', b'TestValue')
135137 assert len(tbl.dynamic_entries) == 1
136138 tbl.maxsize = 0
137139 assert len(tbl.dynamic_entries) == 0