def get_encoder(self): """ Returns a HPACK encoder set up for responses. """ e = Encoder() e.huffman_coder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH) return e
def build_headers_frame(headers, encoder=None): f = HeadersFrame(1) e = encoder if e is None: e = Encoder() e.huffman_coder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH) f.data = e.encode(headers) f.flags.add('END_HEADERS') return f
def test_request_huffman_encode(self): encoder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH) assert encoder.encode(b"www.example.com") == ( b'\xf1\xe3\xc2\xe5\xf2:k\xa0\xab\x90\xf4\xff') assert encoder.encode(b"no-cache") == (b'\xa8\xeb\x10d\x9c\xbf') assert encoder.encode(b"custom-key") == (b'%\xa8I\xe9[\xa9}\x7f') assert encoder.encode(b"custom-value") == ( b'%\xa8I\xe9[\xb8\xe8\xb4\xbf')
def _load_pattern(self, verbose): ''' Get query compressed size pattern. ''' patterns = None encoder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH) def __get_patterns(string): ''' Get possible size patterns of a query string. Considering counter parameter if any exist. ''' size_sequences = [[] for _ in range(8)] # Initial bits number from 1 to 8 (+2 octets) init_bytes = [ b'AA0', b'AAA', b'AAB', b'AAX', b'XX0', b'XXA', b'XXB', b'XXX' ] query_bytes = b'' ct = self.website.ct_start # Keep track of how far through an octet we are for char in string: if char == '\'' and self.website.encode_apost: query_bytes += b'%27' elif char == ' ' and self.website.encode_space: query_bytes += b'%20' else: query_bytes += bytes(char, encoding='utf8') if char == '\'': if self.website.ct_type == 'cp': ct += 1 continue if char == ' ' and self.website.trim_space: if self.website.ct_type == 'cp': ct += 1 continue if self.website.ct_type == 'no': encode_bytes = query_bytes else: ct_bytes = bytes(str(ct), encoding='utf8') encode_bytes = query_bytes + ct_bytes for i in range(len(init_bytes)): size_sequences[i].append( len(encoder.encode(init_bytes[i] + encode_bytes))) ct += 1 return [np.diff(x).tolist() for x in size_sequences] # Compressed pattern is valid only for HTTP/2 requests without changing bytes if self.website.http_version == 2 and self.website.change_byte == 0: if verbose: print('Loading query patterns') if self.chinese: patterns = self.__load_matedata('pattern_zh_%s.pkl' % self.website) if patterns is None: tqdm.pandas(desc='pinyin') string = self.queries['query'].progress_apply( lambda x: '\''.join(py.get_pinyin(x).split('-'))) tqdm.pandas(desc='patterns') patterns = string.progress_apply(__get_patterns) self.__save_matedata(patterns, 'pattern_zh_%s.pkl' % self.website) else: patterns = self.__load_matedata('pattern_en_%s.pkl' % self.website) if patterns is None: tqdm.pandas(desc='patterns') patterns = self.queries['query'].progress_apply( __get_patterns) self.__save_matedata(patterns, 'pattern_en_%s.pkl' % self.website) elif verbose: if self.website.http_version == 1.1: print('Compressed pattern is ignored for HTTP/1.1') else: print( 'Compressed pattern is invalid for changing byte parameters' ) return patterns
def test_request_huffman_encode(self): encoder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH) assert encoder.encode(b"www.example.com") == (b'\xf1\xe3\xc2\xe5\xf2:k\xa0\xab\x90\xf4\xff') assert encoder.encode(b"no-cache") == (b'\xa8\xeb\x10d\x9c\xbf') assert encoder.encode(b"custom-key") == (b'%\xa8I\xe9[\xa9}\x7f') assert encoder.encode(b"custom-value") == (b'%\xa8I\xe9[\xb8\xe8\xb4\xbf')