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