1#!/usr/bin/env python2.7 2 3# Copyright 2015 gRPC authors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import hashlib 18import itertools 19import collections 20import os 21import sys 22import subprocess 23import re 24import perfection 25 26# Configuration: a list of either strings or 2-tuples of strings or 3-tuples of 27# strings. 28# A single string represents a static grpc_mdstr. 29# A 2-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will 30# also be created). 31# A 3-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will 32# also be created), with the last value equivalent to the mdelem's static hpack 33# table index as defined by RFC 7541 34 35CONFIG = [ 36 # metadata strings 37 'host', 38 'grpc-timeout', 39 'grpc-internal-encoding-request', 40 'grpc-internal-stream-encoding-request', 41 'grpc-payload-bin', 42 ':path', 43 'grpc-encoding', 44 'grpc-accept-encoding', 45 'user-agent', 46 ':authority', 47 'grpc-message', 48 'grpc-status', 49 'grpc-server-stats-bin', 50 'grpc-tags-bin', 51 'grpc-trace-bin', 52 'grpc-previous-rpc-attempts', 53 'grpc-retry-pushback-ms', 54 '1', 55 '2', 56 '3', 57 '4', 58 '', 59 # channel arg keys 60 'grpc.wait_for_ready', 61 'grpc.timeout', 62 'grpc.max_request_message_bytes', 63 'grpc.max_response_message_bytes', 64 # well known method names 65 '/grpc.lb.v1.LoadBalancer/BalanceLoad', 66 # compression algorithm names 67 'deflate', 68 'gzip', 69 'stream/gzip', 70 # metadata elements 71 ('grpc-status', '0'), 72 ('grpc-status', '1'), 73 ('grpc-status', '2'), 74 ('grpc-encoding', 'identity'), 75 ('grpc-encoding', 'gzip'), 76 ('grpc-encoding', 'deflate'), 77 ('te', 'trailers'), 78 ('content-type', 'application/grpc'), 79 (':method', 'POST', 3), 80 (':status', '200', 8), 81 (':status', '404', 13), 82 (':scheme', 'http', 6), 83 (':scheme', 'https', 7), 84 (':scheme', 'grpc', 0), 85 (':authority', '', 1), 86 (':method', 'GET', 2), 87 (':method', 'PUT'), 88 (':path', '/', 4), 89 (':path', '/index.html', 5), 90 (':status', '204', 9), 91 (':status', '206', 10), 92 (':status', '304', 11), 93 (':status', '400', 12), 94 (':status', '500', 14), 95 ('accept-charset', '', 15), 96 ('accept-encoding', ''), 97 ('accept-encoding', 'gzip, deflate', 16), 98 ('accept-language', '', 17), 99 ('accept-ranges', '', 18), 100 ('accept', '', 19), 101 ('access-control-allow-origin', '', 20), 102 ('age', '', 21), 103 ('allow', '', 22), 104 ('authorization', '', 23), 105 ('cache-control', '', 24), 106 ('content-disposition', '', 25), 107 ('content-encoding', 'identity'), 108 ('content-encoding', 'gzip'), 109 ('content-encoding', '', 26), 110 ('content-language', '', 27), 111 ('content-length', '', 28), 112 ('content-location', '', 29), 113 ('content-range', '', 30), 114 ('content-type', '', 31), 115 ('cookie', '', 32), 116 ('date', '', 33), 117 ('etag', '', 34), 118 ('expect', '', 35), 119 ('expires', '', 36), 120 ('from', '', 37), 121 ('host', '', 38), 122 ('if-match', '', 39), 123 ('if-modified-since', '', 40), 124 ('if-none-match', '', 41), 125 ('if-range', '', 42), 126 ('if-unmodified-since', '', 43), 127 ('last-modified', '', 44), 128 ('lb-token', ''), 129 ('lb-cost-bin', ''), 130 ('link', '', 45), 131 ('location', '', 46), 132 ('max-forwards', '', 47), 133 ('proxy-authenticate', '', 48), 134 ('proxy-authorization', '', 49), 135 ('range', '', 50), 136 ('referer', '', 51), 137 ('refresh', '', 52), 138 ('retry-after', '', 53), 139 ('server', '', 54), 140 ('set-cookie', '', 55), 141 ('strict-transport-security', '', 56), 142 ('transfer-encoding', '', 57), 143 ('user-agent', '', 58), 144 ('vary', '', 59), 145 ('via', '', 60), 146 ('www-authenticate', '', 61), 147] 148 149# All entries here are ignored when counting non-default initial metadata that 150# prevents the chttp2 server from sending a Trailers-Only response. 151METADATA_BATCH_CALLOUTS = [ 152 # (name) 153 (':path'), 154 (':method'), 155 (':status'), 156 (':authority'), 157 (':scheme'), 158 ('te'), 159 ('grpc-message'), 160 ('grpc-status'), 161 ('grpc-payload-bin'), 162 ('grpc-encoding'), 163 ('grpc-accept-encoding'), 164 ('grpc-server-stats-bin'), 165 ('grpc-tags-bin'), 166 ('grpc-trace-bin'), 167 ('content-type'), 168 ('content-encoding'), 169 ('accept-encoding'), 170 ('grpc-internal-encoding-request'), 171 ('grpc-internal-stream-encoding-request'), 172 ('user-agent'), 173 ('host'), 174 ('lb-token'), 175 ('grpc-previous-rpc-attempts'), 176 ('grpc-retry-pushback-ms'), 177] 178 179COMPRESSION_ALGORITHMS = [ 180 'identity', 181 'deflate', 182 'gzip', 183] 184 185STREAM_COMPRESSION_ALGORITHMS = [ 186 'identity', 187 'gzip', 188] 189 190 191# utility: mangle the name of a config 192def mangle(elem, name=None): 193 xl = { 194 '-': '_', 195 ':': '', 196 '/': 'slash', 197 '.': 'dot', 198 ',': 'comma', 199 ' ': '_', 200 } 201 202 def m0(x): 203 if not x: 204 return 'empty' 205 r = '' 206 for c in x: 207 put = xl.get(c, c.lower()) 208 if not put: 209 continue 210 last_is_underscore = r[-1] == '_' if r else True 211 if last_is_underscore and put == '_': 212 continue 213 elif len(put) > 1: 214 if not last_is_underscore: 215 r += '_' 216 r += put 217 r += '_' 218 else: 219 r += put 220 if r[-1] == '_': 221 r = r[:-1] 222 return r 223 224 def n(default, name=name): 225 if name is None: 226 return 'grpc_%s_' % default 227 if name == '': 228 return '' 229 return 'grpc_%s_' % name 230 231 if isinstance(elem, tuple): 232 return '%s%s_%s' % (n('mdelem'), m0(elem[0]), m0(elem[1])) 233 else: 234 return '%s%s' % (n('mdstr'), m0(elem)) 235 236 237# utility: generate some hash value for a string 238def fake_hash(elem): 239 return hashlib.md5(elem).hexdigest()[0:8] 240 241 242# utility: print a big comment block into a set of files 243def put_banner(files, banner): 244 for f in files: 245 print >> f, '/*' 246 for line in banner: 247 print >> f, ' * %s' % line 248 print >> f, ' */' 249 print >> f 250 251 252# build a list of all the strings we need 253all_strs = list() 254all_elems = list() 255static_userdata = {} 256# put metadata batch callouts first, to make the check of if a static metadata 257# string is a callout trivial 258for elem in METADATA_BATCH_CALLOUTS: 259 if elem not in all_strs: 260 all_strs.append(elem) 261for elem in CONFIG: 262 if isinstance(elem, tuple): 263 if elem[0] not in all_strs: 264 all_strs.append(elem[0]) 265 if elem[1] not in all_strs: 266 all_strs.append(elem[1]) 267 if elem not in all_elems: 268 all_elems.append(elem) 269 else: 270 if elem not in all_strs: 271 all_strs.append(elem) 272compression_elems = [] 273for mask in range(1, 1 << len(COMPRESSION_ALGORITHMS)): 274 val = ','.join(COMPRESSION_ALGORITHMS[alg] 275 for alg in range(0, len(COMPRESSION_ALGORITHMS)) 276 if (1 << alg) & mask) 277 elem = ('grpc-accept-encoding', val) 278 if val not in all_strs: 279 all_strs.append(val) 280 if elem not in all_elems: 281 all_elems.append(elem) 282 compression_elems.append(elem) 283 static_userdata[elem] = 1 + (mask | 1) 284stream_compression_elems = [] 285for mask in range(1, 1 << len(STREAM_COMPRESSION_ALGORITHMS)): 286 val = ','.join(STREAM_COMPRESSION_ALGORITHMS[alg] 287 for alg in range(0, len(STREAM_COMPRESSION_ALGORITHMS)) 288 if (1 << alg) & mask) 289 elem = ('accept-encoding', val) 290 if val not in all_strs: 291 all_strs.append(val) 292 if elem not in all_elems: 293 all_elems.append(elem) 294 stream_compression_elems.append(elem) 295 static_userdata[elem] = 1 + (mask | 1) 296 297# output configuration 298args = sys.argv[1:] 299H = None 300C = None 301D = None 302if args: 303 if 'header' in args: 304 H = sys.stdout 305 else: 306 H = open('/dev/null', 'w') 307 if 'source' in args: 308 C = sys.stdout 309 else: 310 C = open('/dev/null', 'w') 311 if 'dictionary' in args: 312 D = sys.stdout 313 else: 314 D = open('/dev/null', 'w') 315else: 316 H = open( 317 os.path.join( 318 os.path.dirname(sys.argv[0]), 319 '../../../src/core/lib/transport/static_metadata.h'), 'w') 320 C = open( 321 os.path.join( 322 os.path.dirname(sys.argv[0]), 323 '../../../src/core/lib/transport/static_metadata.cc'), 'w') 324 D = open( 325 os.path.join( 326 os.path.dirname(sys.argv[0]), 327 '../../../test/core/end2end/fuzzers/hpack.dictionary'), 'w') 328 329HPACK_H = open( 330 os.path.join( 331 os.path.dirname(sys.argv[0]), 332 '../../../src/core/ext/transport/chttp2/transport/hpack_mapping.h'), 333 'w') 334HPACK_C = open( 335 os.path.join( 336 os.path.dirname(sys.argv[0]), 337 '../../../src/core/ext/transport/chttp2/transport/hpack_mapping.cc'), 338 'w') 339 340# copy-paste copyright notice from this file 341with open(sys.argv[0]) as my_source: 342 copyright = [] 343 for line in my_source: 344 if line[0] != '#': 345 break 346 for line in my_source: 347 if line[0] == '#': 348 copyright.append(line) 349 break 350 for line in my_source: 351 if line[0] != '#': 352 break 353 copyright.append(line) 354 put_banner([H, C, HPACK_H, HPACK_C], 355 [line[2:].rstrip() for line in copyright]) 356 357hex_bytes = [ord(c) for c in 'abcdefABCDEF0123456789'] 358 359 360def esc_dict(line): 361 out = "\"" 362 for c in line: 363 if 32 <= c < 127: 364 if c != ord('"'): 365 out += chr(c) 366 else: 367 out += "\\\"" 368 else: 369 out += '\\x%02X' % c 370 return out + "\"" 371 372 373put_banner([H, C], """WARNING: Auto-generated code. 374 375To make changes to this file, change 376tools/codegen/core/gen_static_metadata.py, and then re-run it. 377 378See metadata.h for an explanation of the interface here, and metadata.cc for 379an explanation of what's going on. 380""".splitlines()) 381 382put_banner([HPACK_H, HPACK_C], """WARNING: Auto-generated code. 383 384To make changes to this file, change 385tools/codegen/core/gen_static_metadata.py, and then re-run it. 386 387This file contains the mapping from the index of each metadata element in the 388grpc static metadata table to the index of that element in the hpack static 389metadata table. If the element is not contained in the static hpack table, then 390the returned index is 0. 391""".splitlines()) 392 393print >> H, '#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H' 394print >> H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H' 395print >> H 396print >> H, '#include <grpc/support/port_platform.h>' 397print >> H 398print >> H, '#include "src/core/lib/transport/metadata.h"' 399print >> H 400print >> C, '#include <grpc/support/port_platform.h>' 401print >> C 402print >> C, '#include "src/core/lib/transport/static_metadata.h"' 403print >> C 404print >> C, '#include "src/core/lib/slice/slice_internal.h"' 405print >> C 406print >> HPACK_H, ('#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_' 407 'MAPPING_H') 408print >> HPACK_H, ('#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_' 409 'MAPPING_H') 410print >> HPACK_H 411print >> HPACK_H, '#include <grpc/support/port_platform.h>' 412print >> HPACK_H 413print >> HPACK_H, '#include "src/core/lib/transport/static_metadata.h"' 414print >> HPACK_H 415print >> HPACK_C, '#include <grpc/support/port_platform.h>' 416print >> HPACK_C 417print >> HPACK_C, ('#include ' 418 '"src/core/ext/transport/chttp2/transport/hpack_mapping.h"') 419print >> HPACK_C 420 421str_ofs = 0 422id2strofs = {} 423for i, elem in enumerate(all_strs): 424 id2strofs[i] = str_ofs 425 str_ofs += len(elem) 426 427 428def slice_def(i): 429 return ('{&grpc_static_metadata_refcounts[%d],' 430 ' {{g_bytes+%d, %d}}}') % (i, id2strofs[i], len(all_strs[i])) 431 432 433# validate configuration 434for elem in METADATA_BATCH_CALLOUTS: 435 assert elem in all_strs 436 437print >> H, '#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs) 438print >> H, ('extern const grpc_slice ' 439 'grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];') 440for i, elem in enumerate(all_strs): 441 print >> H, '/* "%s" */' % elem 442 print >> H, '#define %s (grpc_static_slice_table[%d])' % ( 443 mangle(elem).upper(), i) 444print >> H 445print >> C, 'static uint8_t g_bytes[] = {%s};' % (','.join( 446 '%d' % ord(c) for c in ''.join(all_strs))) 447print >> C 448print >> C, 'static void static_ref(void *unused) {}' 449print >> C, 'static void static_unref(void *unused) {}' 450print >> C, ('static const grpc_slice_refcount_vtable static_sub_vtable = ' 451 '{static_ref, static_unref, grpc_slice_default_eq_impl, ' 452 'grpc_slice_default_hash_impl};') 453print >> H, ('extern const grpc_slice_refcount_vtable ' 454 'grpc_static_metadata_vtable;') 455print >> C, ('const grpc_slice_refcount_vtable grpc_static_metadata_vtable = ' 456 '{static_ref, static_unref, grpc_static_slice_eq, ' 457 'grpc_static_slice_hash};') 458print >> C, ('static grpc_slice_refcount static_sub_refcnt = ' 459 '{&static_sub_vtable, &static_sub_refcnt};') 460print >> H, ('extern grpc_slice_refcount ' 461 'grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT];') 462print >> C, ('grpc_slice_refcount ' 463 'grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {') 464for i, elem in enumerate(all_strs): 465 print >> C, ' {&grpc_static_metadata_vtable, &static_sub_refcnt},' 466print >> C, '};' 467print >> C 468print >> H, '#define GRPC_IS_STATIC_METADATA_STRING(slice) \\' 469print >> H, (' ((slice).refcount != NULL && (slice).refcount->vtable == ' 470 '&grpc_static_metadata_vtable)') 471print >> H 472print >> C, ('const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT]' 473 ' = {') 474for i, elem in enumerate(all_strs): 475 print >> C, slice_def(i) + ',' 476print >> C, '};' 477print >> C 478print >> H, '#define GRPC_STATIC_METADATA_INDEX(static_slice) \\' 479print >> H, (' ((int)((static_slice).refcount - ' 480 'grpc_static_metadata_refcounts))') 481print >> H 482 483print >> D, '# hpack fuzzing dictionary' 484for i, elem in enumerate(all_strs): 485 print >> D, '%s' % (esc_dict([len(elem)] + [ord(c) for c in elem])) 486for i, elem in enumerate(all_elems): 487 print >> D, '%s' % (esc_dict([0, len(elem[0])] + [ord(c) for c in elem[0]] + 488 [len(elem[1])] + [ord(c) for c in elem[1]])) 489 490print >> H, '#define GRPC_STATIC_MDELEM_COUNT %d' % len(all_elems) 491print >> H, ('extern grpc_mdelem_data ' 492 'grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];') 493print >> H, ('extern uintptr_t ' 494 'grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];') 495for i, elem in enumerate(all_elems): 496 print >> H, '/* "%s": "%s" */' % (elem[0], elem[1]) 497 print >> H, ('#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d], ' 498 'GRPC_MDELEM_STORAGE_STATIC))') % (mangle(elem).upper(), i) 499print >> H 500 501# Print out the chttp2 mapping between static mdelem index and the hpack static 502# table index 503print >> HPACK_H, ('extern const uint8_t grpc_hpack_static_mdelem_indices[' 504 'GRPC_STATIC_MDELEM_COUNT];') 505print >> HPACK_H 506print >> HPACK_C, ('const uint8_t grpc_hpack_static_mdelem_indices[' 507 'GRPC_STATIC_MDELEM_COUNT] = {') 508indices = '' 509for elem in all_elems: 510 index = 0 511 if len(elem) == 3: 512 index = elem[2] 513 indices += '%d,' % index 514print >> HPACK_C, ' %s' % indices 515print >> HPACK_C, '};' 516print >> HPACK_C 517 518print >> C, ('uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] ' 519 '= {') 520print >> C, ' %s' % ','.join( 521 '%d' % static_userdata.get(elem, 0) for elem in all_elems) 522print >> C, '};' 523print >> C 524 525 526def str_idx(s): 527 for i, s2 in enumerate(all_strs): 528 if s == s2: 529 return i 530 531 532def md_idx(m): 533 for i, m2 in enumerate(all_elems): 534 if m == m2: 535 return i 536 537 538def offset_trials(mink): 539 yield 0 540 for i in range(1, 100): 541 for mul in [-1, 1]: 542 yield mul * i 543 544 545def perfect_hash(keys, name): 546 p = perfection.hash_parameters(keys) 547 548 def f(i, p=p): 549 i += p.offset 550 x = i % p.t 551 y = i / p.t 552 return x + p.r[y] 553 554 return { 555 'PHASHRANGE': p.t - 1 + max(p.r), 556 'PHASHNKEYS': len(p.slots), 557 'pyfunc': f, 558 'code': """ 559static const int8_t %(name)s_r[] = {%(r)s}; 560static uint32_t %(name)s_phash(uint32_t i) { 561 i %(offset_sign)s= %(offset)d; 562 uint32_t x = i %% %(t)d; 563 uint32_t y = i / %(t)d; 564 uint32_t h = x; 565 if (y < GPR_ARRAY_SIZE(%(name)s_r)) { 566 uint32_t delta = (uint32_t)%(name)s_r[y]; 567 h += delta; 568 } 569 return h; 570} 571 """ % { 572 'name': name, 573 'r': ','.join('%d' % (r if r is not None else 0) for r in p.r), 574 't': p.t, 575 'offset': abs(p.offset), 576 'offset_sign': '+' if p.offset > 0 else '-' 577 } 578 } 579 580 581elem_keys = [ 582 str_idx(elem[0]) * len(all_strs) + str_idx(elem[1]) for elem in all_elems 583] 584elem_hash = perfect_hash(elem_keys, 'elems') 585print >> C, elem_hash['code'] 586 587keys = [0] * int(elem_hash['PHASHRANGE']) 588idxs = [255] * int(elem_hash['PHASHNKEYS']) 589for i, k in enumerate(elem_keys): 590 h = elem_hash['pyfunc'](k) 591 assert keys[h] == 0 592 keys[h] = k 593 idxs[h] = i 594print >> C, 'static const uint16_t elem_keys[] = {%s};' % ','.join( 595 '%d' % k for k in keys) 596print >> C, 'static const uint8_t elem_idxs[] = {%s};' % ','.join( 597 '%d' % i for i in idxs) 598print >> C 599 600print >> H, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);' 601print >> C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {' 602print >> C, ' if (a == -1 || b == -1) return GRPC_MDNULL;' 603print >> C, ' uint32_t k = (uint32_t)(a * %d + b);' % len(all_strs) 604print >> C, ' uint32_t h = elems_phash(k);' 605print >> C, ' return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k && elem_idxs[h] != 255 ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]], GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL;' 606print >> C, '}' 607print >> C 608 609print >> C, 'grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {' 610for elem in all_elems: 611 print >> C, '{%s,%s},' % (slice_def(str_idx(elem[0])), 612 slice_def(str_idx(elem[1]))) 613print >> C, '};' 614 615print >> H, 'typedef enum {' 616for elem in METADATA_BATCH_CALLOUTS: 617 print >> H, ' %s,' % mangle(elem, 'batch').upper() 618print >> H, ' GRPC_BATCH_CALLOUTS_COUNT' 619print >> H, '} grpc_metadata_batch_callouts_index;' 620print >> H 621print >> H, 'typedef union {' 622print >> H, ' struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];' 623print >> H, ' struct {' 624for elem in METADATA_BATCH_CALLOUTS: 625 print >> H, ' struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower() 626print >> H, ' } named;' 627print >> H, '} grpc_metadata_batch_callouts;' 628print >> H 629print >> H, '#define GRPC_BATCH_INDEX_OF(slice) \\' 630print >> H, ' (GRPC_IS_STATIC_METADATA_STRING((slice)) ? (grpc_metadata_batch_callouts_index)GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)' 631print >> H 632 633print >> H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % ( 634 1 << len(COMPRESSION_ALGORITHMS)) 635print >> C, 'const uint8_t grpc_static_accept_encoding_metadata[%d] = {' % ( 636 1 << len(COMPRESSION_ALGORITHMS)) 637print >> C, '0,%s' % ','.join('%d' % md_idx(elem) for elem in compression_elems) 638print >> C, '};' 639print >> C 640 641print >> H, '#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], GRPC_MDELEM_STORAGE_STATIC))' 642print >> H 643 644print >> H, 'extern const uint8_t grpc_static_accept_stream_encoding_metadata[%d];' % ( 645 1 << len(STREAM_COMPRESSION_ALGORITHMS)) 646print >> C, 'const uint8_t grpc_static_accept_stream_encoding_metadata[%d] = {' % ( 647 1 << len(STREAM_COMPRESSION_ALGORITHMS)) 648print >> C, '0,%s' % ','.join( 649 '%d' % md_idx(elem) for elem in stream_compression_elems) 650print >> C, '};' 651 652print >> H, '#define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_stream_encoding_metadata[(algs)]], GRPC_MDELEM_STORAGE_STATIC))' 653 654print >> H, '#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */' 655 656print >> HPACK_H, ('#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_' 657 'MAPPING_H */') 658 659H.close() 660C.close() 661