gen_header_frame.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #!/usr/bin/env python3
  2. # Copyright 2015 gRPC authors.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. """Read from stdin a set of colon separated http headers:
  16. :path: /foo/bar
  17. content-type: application/grpc
  18. Write a set of strings containing a hpack encoded http2 frame that
  19. represents said headers."""
  20. import argparse
  21. import json
  22. import sys
  23. def append_never_indexed(payload_line, n, count, key, value):
  24. payload_line.append(0x10)
  25. assert (len(key) <= 126)
  26. payload_line.append(len(key))
  27. payload_line.extend(ord(c) for c in key)
  28. assert (len(value) <= 126)
  29. payload_line.append(len(value))
  30. payload_line.extend(ord(c) for c in value)
  31. def append_inc_indexed(payload_line, n, count, key, value):
  32. payload_line.append(0x40)
  33. assert (len(key) <= 126)
  34. payload_line.append(len(key))
  35. payload_line.extend(ord(c) for c in key)
  36. assert (len(value) <= 126)
  37. payload_line.append(len(value))
  38. payload_line.extend(ord(c) for c in value)
  39. def append_pre_indexed(payload_line, n, count, key, value):
  40. payload_line.append(0x80 + 61 + count - n)
  41. _COMPRESSORS = {
  42. 'never': append_never_indexed,
  43. 'inc': append_inc_indexed,
  44. 'pre': append_pre_indexed,
  45. }
  46. argp = argparse.ArgumentParser('Generate header frames')
  47. argp.add_argument('--set_end_stream',
  48. default=False,
  49. action='store_const',
  50. const=True)
  51. argp.add_argument('--no_framing',
  52. default=False,
  53. action='store_const',
  54. const=True)
  55. argp.add_argument('--compression',
  56. choices=sorted(_COMPRESSORS.keys()),
  57. default='never')
  58. argp.add_argument('--hex', default=False, action='store_const', const=True)
  59. args = argp.parse_args()
  60. # parse input, fill in vals
  61. vals = []
  62. for line in sys.stdin:
  63. line = line.strip()
  64. if line == '':
  65. continue
  66. if line[0] == '#':
  67. continue
  68. key_tail, value = line[1:].split(':')
  69. key = (line[0] + key_tail).strip()
  70. value = value.strip()
  71. vals.append((key, value))
  72. # generate frame payload binary data
  73. payload_bytes = []
  74. if not args.no_framing:
  75. payload_bytes.append([]) # reserve space for header
  76. payload_len = 0
  77. n = 0
  78. for key, value in vals:
  79. payload_line = []
  80. _COMPRESSORS[args.compression](payload_line, n, len(vals), key, value)
  81. n += 1
  82. payload_len += len(payload_line)
  83. payload_bytes.append(payload_line)
  84. # fill in header
  85. if not args.no_framing:
  86. flags = 0x04 # END_HEADERS
  87. if args.set_end_stream:
  88. flags |= 0x01 # END_STREAM
  89. payload_bytes[0].extend([
  90. (payload_len >> 16) & 0xff,
  91. (payload_len >> 8) & 0xff,
  92. (payload_len) & 0xff,
  93. # header frame
  94. 0x01,
  95. # flags
  96. flags,
  97. # stream id
  98. 0x00,
  99. 0x00,
  100. 0x00,
  101. 0x01
  102. ])
  103. hex_bytes = [ord(c) for c in "abcdefABCDEF0123456789"]
  104. def esc_c(line):
  105. out = "\""
  106. last_was_hex = False
  107. for c in line:
  108. if 32 <= c < 127:
  109. if c in hex_bytes and last_was_hex:
  110. out += "\"\""
  111. if c != ord('"'):
  112. out += chr(c)
  113. else:
  114. out += "\\\""
  115. last_was_hex = False
  116. else:
  117. out += "\\x%02x" % c
  118. last_was_hex = True
  119. return out + "\""
  120. # dump bytes
  121. if args.hex:
  122. all_bytes = []
  123. for line in payload_bytes:
  124. all_bytes.extend(line)
  125. print(('{%s}' % ', '.join('0x%02x' % c for c in all_bytes)))
  126. else:
  127. for line in payload_bytes:
  128. print((esc_c(line)))