1#!/usr/bin/env python3 2# 3# This script reads input headers from json file given in the 4# command-line (each file must be written in the format described in 5# https://github.com/Jxck/hpack-test-case but we require only 6# 'headers' data). Then it encodes input header set and write the 7# encoded header block in the same format. The output files are 8# created under 'out' directory in the current directory. It must 9# exist, otherwise the script will fail. The output filename is the 10# same as the input filename. 11# 12import sys, base64, json, os.path, os, argparse, errno 13from binascii import b2a_hex 14import nghttp2 15 16def testsuite(testdata, filename, outdir, table_size, deflate_table_size, 17 simulate_table_size_change): 18 res = { 19 'description': '''\ 20Encoded by nghttp2. The basic encoding strategy is described in \ 21http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html \ 22We use huffman encoding only if it produces strictly shorter byte string than \ 23original. We make some headers not indexing at all, but this does not always \ 24result in less bits on the wire.''' 25 } 26 cases = [] 27 deflater = nghttp2.HDDeflater(deflate_table_size) 28 29 if table_size != nghttp2.DEFAULT_HEADER_TABLE_SIZE: 30 deflater.change_table_size(table_size) 31 32 num_item = len(testdata['cases']) 33 34 change_points = {} 35 if simulate_table_size_change and num_item > 1: 36 change_points[num_item * 2 // 3] = table_size * 2 // 3 37 change_points[num_item // 3] = table_size // 3 38 39 for casenum, item in enumerate(testdata['cases']): 40 outitem = { 41 'seqno': casenum, 42 'headers': item['headers'] 43 } 44 45 if casenum in change_points: 46 new_table_size = change_points[casenum] 47 deflater.change_table_size(new_table_size) 48 outitem['header_table_size'] = new_table_size 49 50 casenum += 1 51 hdrs = [(list(x.keys())[0].encode('utf-8'), 52 list(x.values())[0].encode('utf-8')) \ 53 for x in item['headers']] 54 outitem['wire'] = b2a_hex(deflater.deflate(hdrs)).decode('utf-8') 55 cases.append(outitem) 56 57 if cases and table_size != nghttp2.DEFAULT_HEADER_TABLE_SIZE: 58 cases[0]['header_table_size'] = table_size 59 60 res['cases'] = cases 61 jsonstr = json.dumps(res, indent=2) 62 with open(os.path.join(outdir, filename), 'w') as f: 63 f.write(jsonstr) 64 65if __name__ == '__main__': 66 ap = argparse.ArgumentParser(description='HPACK test case generator') 67 ap.add_argument('-d', '--dir', help='output directory', default='out') 68 ap.add_argument('-s', '--table-size', help='max header table size', 69 type=int, default=nghttp2.DEFAULT_HEADER_TABLE_SIZE) 70 ap.add_argument('-S', '--deflate-table-size', 71 help='max header table size for deflater', 72 type=int, default=nghttp2.DEFLATE_MAX_HEADER_TABLE_SIZE) 73 ap.add_argument('-c', '--simulate-table-size-change', 74 help='simulate table size change scenario', 75 action='store_true') 76 77 ap.add_argument('file', nargs='*', help='input file') 78 args = ap.parse_args() 79 try: 80 os.mkdir(args.dir) 81 except OSError as e: 82 if e.errno != errno.EEXIST: 83 raise e 84 for filename in args.file: 85 sys.stderr.write('{}\n'.format(filename)) 86 with open(filename) as f: 87 input = f.read() 88 testsuite(json.loads(input), os.path.basename(filename), 89 args.dir, args.table_size, args.deflate_table_size, 90 args.simulate_table_size_change) 91