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 17 import hashlib 18 import itertools 19 import collections 20 import os 21 import sys 22 import subprocess 23 import re 24 import 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 35 CONFIG = [ 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. 151 METADATA_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 179 COMPRESSION_ALGORITHMS = [ 180 'identity', 181 'deflate', 182 'gzip', 183 ] 184 185 STREAM_COMPRESSION_ALGORITHMS = [ 186 'identity', 187 'gzip', 188 ] 189 190 191 # utility: mangle the name of a config 192 def 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 238 def 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 243 def 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 253 all_strs = list() 254 all_elems = list() 255 static_userdata = {} 256 # put metadata batch callouts first, to make the check of if a static metadata 257 # string is a callout trivial 258 for elem in METADATA_BATCH_CALLOUTS: 259 if elem not in all_strs: 260 all_strs.append(elem) 261 for 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) 272 compression_elems = [] 273 for 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) 284 stream_compression_elems = [] 285 for 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 298 args = sys.argv[1:] 299 H = None 300 C = None 301 D = None 302 if 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') 315 else: 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 329 HPACK_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') 334 HPACK_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 341 with 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 357 hex_bytes = [ord(c) for c in 'abcdefABCDEF0123456789'] 358 359 360 def 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 373 put_banner([H, C], """WARNING: Auto-generated code. 374 375 To make changes to this file, change 376 tools/codegen/core/gen_static_metadata.py, and then re-run it. 377 378 See metadata.h for an explanation of the interface here, and metadata.cc for 379 an explanation of what's going on. 380 """.splitlines()) 381 382 put_banner([HPACK_H, HPACK_C], """WARNING: Auto-generated code. 383 384 To make changes to this file, change 385 tools/codegen/core/gen_static_metadata.py, and then re-run it. 386 387 This file contains the mapping from the index of each metadata element in the 388 grpc static metadata table to the index of that element in the hpack static 389 metadata table. If the element is not contained in the static hpack table, then 390 the returned index is 0. 391 """.splitlines()) 392 393 print >> H, '#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H' 394 print >> H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H' 395 print >> H 396 print >> H, '#include <grpc/support/port_platform.h>' 397 print >> H 398 print >> H, '#include "src/core/lib/transport/metadata.h"' 399 print >> H 400 print >> C, '#include <grpc/support/port_platform.h>' 401 print >> C 402 print >> C, '#include "src/core/lib/transport/static_metadata.h"' 403 print >> C 404 print >> C, '#include "src/core/lib/slice/slice_internal.h"' 405 print >> C 406 print >> HPACK_H, ('#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_' 407 'MAPPING_H') 408 print >> HPACK_H, ('#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_' 409 'MAPPING_H') 410 print >> HPACK_H 411 print >> HPACK_H, '#include <grpc/support/port_platform.h>' 412 print >> HPACK_H 413 print >> HPACK_H, '#include "src/core/lib/transport/static_metadata.h"' 414 print >> HPACK_H 415 print >> HPACK_C, '#include <grpc/support/port_platform.h>' 416 print >> HPACK_C 417 print >> HPACK_C, ('#include ' 418 '"src/core/ext/transport/chttp2/transport/hpack_mapping.h"') 419 print >> HPACK_C 420 421 str_ofs = 0 422 id2strofs = {} 423 for i, elem in enumerate(all_strs): 424 id2strofs[i] = str_ofs 425 str_ofs += len(elem) 426 427 428 def 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 434 for elem in METADATA_BATCH_CALLOUTS: 435 assert elem in all_strs 436 437 print >> H, '#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs) 438 print >> H, ('extern const grpc_slice ' 439 'grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];') 440 for 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) 444 print >> H 445 print >> C, 'static uint8_t g_bytes[] = {%s};' % (','.join( 446 '%d' % ord(c) for c in ''.join(all_strs))) 447 print >> C 448 print >> C, 'static void static_ref(void *unused) {}' 449 print >> C, 'static void static_unref(void *unused) {}' 450 print >> 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};') 453 print >> H, ('extern const grpc_slice_refcount_vtable ' 454 'grpc_static_metadata_vtable;') 455 print >> C, ('const grpc_slice_refcount_vtable grpc_static_metadata_vtable = ' 456 '{static_ref, static_unref, grpc_static_slice_eq, ' 457 'grpc_static_slice_hash};') 458 print >> C, ('static grpc_slice_refcount static_sub_refcnt = ' 459 '{&static_sub_vtable, &static_sub_refcnt};') 460 print >> H, ('extern grpc_slice_refcount ' 461 'grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT];') 462 print >> C, ('grpc_slice_refcount ' 463 'grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {') 464 for i, elem in enumerate(all_strs): 465 print >> C, ' {&grpc_static_metadata_vtable, &static_sub_refcnt},' 466 print >> C, '};' 467 print >> C 468 print >> H, '#define GRPC_IS_STATIC_METADATA_STRING(slice) \\' 469 print >> H, (' ((slice).refcount != NULL && (slice).refcount->vtable == ' 470 '&grpc_static_metadata_vtable)') 471 print >> H 472 print >> C, ('const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT]' 473 ' = {') 474 for i, elem in enumerate(all_strs): 475 print >> C, slice_def(i) + ',' 476 print >> C, '};' 477 print >> C 478 print >> H, '#define GRPC_STATIC_METADATA_INDEX(static_slice) \\' 479 print >> H, (' ((int)((static_slice).refcount - ' 480 'grpc_static_metadata_refcounts))') 481 print >> H 482 483 print >> D, '# hpack fuzzing dictionary' 484 for i, elem in enumerate(all_strs): 485 print >> D, '%s' % (esc_dict([len(elem)] + [ord(c) for c in elem])) 486 for 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 490 print >> H, '#define GRPC_STATIC_MDELEM_COUNT %d' % len(all_elems) 491 print >> H, ('extern grpc_mdelem_data ' 492 'grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];') 493 print >> H, ('extern uintptr_t ' 494 'grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];') 495 for 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) 499 print >> H 500 501 # Print out the chttp2 mapping between static mdelem index and the hpack static 502 # table index 503 print >> HPACK_H, ('extern const uint8_t grpc_hpack_static_mdelem_indices[' 504 'GRPC_STATIC_MDELEM_COUNT];') 505 print >> HPACK_H 506 print >> HPACK_C, ('const uint8_t grpc_hpack_static_mdelem_indices[' 507 'GRPC_STATIC_MDELEM_COUNT] = {') 508 indices = '' 509 for elem in all_elems: 510 index = 0 511 if len(elem) == 3: 512 index = elem[2] 513 indices += '%d,' % index 514 print >> HPACK_C, ' %s' % indices 515 print >> HPACK_C, '};' 516 print >> HPACK_C 517 518 print >> C, ('uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] ' 519 '= {') 520 print >> C, ' %s' % ','.join( 521 '%d' % static_userdata.get(elem, 0) for elem in all_elems) 522 print >> C, '};' 523 print >> C 524 525 526 def str_idx(s): 527 for i, s2 in enumerate(all_strs): 528 if s == s2: 529 return i 530 531 532 def md_idx(m): 533 for i, m2 in enumerate(all_elems): 534 if m == m2: 535 return i 536 537 538 def 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 545 def 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': """ 559 static const int8_t %(name)s_r[] = {%(r)s}; 560 static 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 581 elem_keys = [ 582 str_idx(elem[0]) * len(all_strs) + str_idx(elem[1]) for elem in all_elems 583 ] 584 elem_hash = perfect_hash(elem_keys, 'elems') 585 print >> C, elem_hash['code'] 586 587 keys = [0] * int(elem_hash['PHASHRANGE']) 588 idxs = [255] * int(elem_hash['PHASHNKEYS']) 589 for 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 594 print >> C, 'static const uint16_t elem_keys[] = {%s};' % ','.join( 595 '%d' % k for k in keys) 596 print >> C, 'static const uint8_t elem_idxs[] = {%s};' % ','.join( 597 '%d' % i for i in idxs) 598 print >> C 599 600 print >> H, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);' 601 print >> C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {' 602 print >> C, ' if (a == -1 || b == -1) return GRPC_MDNULL;' 603 print >> C, ' uint32_t k = (uint32_t)(a * %d + b);' % len(all_strs) 604 print >> C, ' uint32_t h = elems_phash(k);' 605 print >> 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;' 606 print >> C, '}' 607 print >> C 608 609 print >> C, 'grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {' 610 for elem in all_elems: 611 print >> C, '{%s,%s},' % (slice_def(str_idx(elem[0])), 612 slice_def(str_idx(elem[1]))) 613 print >> C, '};' 614 615 print >> H, 'typedef enum {' 616 for elem in METADATA_BATCH_CALLOUTS: 617 print >> H, ' %s,' % mangle(elem, 'batch').upper() 618 print >> H, ' GRPC_BATCH_CALLOUTS_COUNT' 619 print >> H, '} grpc_metadata_batch_callouts_index;' 620 print >> H 621 print >> H, 'typedef union {' 622 print >> H, ' struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];' 623 print >> H, ' struct {' 624 for elem in METADATA_BATCH_CALLOUTS: 625 print >> H, ' struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower() 626 print >> H, ' } named;' 627 print >> H, '} grpc_metadata_batch_callouts;' 628 print >> H 629 print >> H, '#define GRPC_BATCH_INDEX_OF(slice) \\' 630 print >> 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)' 631 print >> H 632 633 print >> H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % ( 634 1 << len(COMPRESSION_ALGORITHMS)) 635 print >> C, 'const uint8_t grpc_static_accept_encoding_metadata[%d] = {' % ( 636 1 << len(COMPRESSION_ALGORITHMS)) 637 print >> C, '0,%s' % ','.join('%d' % md_idx(elem) for elem in compression_elems) 638 print >> C, '};' 639 print >> C 640 641 print >> 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))' 642 print >> H 643 644 print >> H, 'extern const uint8_t grpc_static_accept_stream_encoding_metadata[%d];' % ( 645 1 << len(STREAM_COMPRESSION_ALGORITHMS)) 646 print >> C, 'const uint8_t grpc_static_accept_stream_encoding_metadata[%d] = {' % ( 647 1 << len(STREAM_COMPRESSION_ALGORITHMS)) 648 print >> C, '0,%s' % ','.join( 649 '%d' % md_idx(elem) for elem in stream_compression_elems) 650 print >> C, '};' 651 652 print >> 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 654 print >> H, '#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */' 655 656 print >> HPACK_H, ('#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_' 657 'MAPPING_H */') 658 659 H.close() 660 C.close() 661