|  | @@ -86,6 +86,7 @@ typedef struct {
 | 
	
		
			
				|  |  |    grpc_transport_one_way_stats *stats;
 | 
	
		
			
				|  |  |    /* maximum size of a frame */
 | 
	
		
			
				|  |  |    size_t max_frame_size;
 | 
	
		
			
				|  |  | +  bool use_true_binary_metadata;
 | 
	
		
			
				|  |  |  } framer_state;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* fills p (which is expected to be 9 bytes long) with a data frame header */
 | 
	
	
		
			
				|  | @@ -290,86 +291,113 @@ static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
 | 
	
		
			
				|  |  |                             len);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static grpc_slice get_wire_value(grpc_mdelem elem, uint8_t *huffman_prefix) {
 | 
	
		
			
				|  |  | +typedef struct {
 | 
	
		
			
				|  |  | +  grpc_slice data;
 | 
	
		
			
				|  |  | +  uint8_t huffman_prefix;
 | 
	
		
			
				|  |  | +  bool insert_null_before_wire_value;
 | 
	
		
			
				|  |  | +} wire_value;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static wire_value get_wire_value(grpc_mdelem elem, bool true_binary_enabled) {
 | 
	
		
			
				|  |  |    if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
 | 
	
		
			
				|  |  | -    *huffman_prefix = 0x80;
 | 
	
		
			
				|  |  | -    return grpc_chttp2_base64_encode_and_huffman_compress(GRPC_MDVALUE(elem));
 | 
	
		
			
				|  |  | +    if (true_binary_enabled) {
 | 
	
		
			
				|  |  | +      return (wire_value){
 | 
	
		
			
				|  |  | +          .huffman_prefix = 0x00,
 | 
	
		
			
				|  |  | +          .insert_null_before_wire_value = true,
 | 
	
		
			
				|  |  | +          .data = grpc_slice_ref_internal(GRPC_MDVALUE(elem)),
 | 
	
		
			
				|  |  | +      };
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      return (wire_value){
 | 
	
		
			
				|  |  | +          .huffman_prefix = 0x80,
 | 
	
		
			
				|  |  | +          .insert_null_before_wire_value = false,
 | 
	
		
			
				|  |  | +          .data = grpc_chttp2_base64_encode_and_huffman_compress(
 | 
	
		
			
				|  |  | +              GRPC_MDVALUE(elem)),
 | 
	
		
			
				|  |  | +      };
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    /* TODO(ctiller): opportunistically compress non-binary headers */
 | 
	
		
			
				|  |  | +    return (wire_value){
 | 
	
		
			
				|  |  | +        .huffman_prefix = 0x00,
 | 
	
		
			
				|  |  | +        .insert_null_before_wire_value = false,
 | 
	
		
			
				|  |  | +        .data = grpc_slice_ref_internal(GRPC_MDVALUE(elem)),
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  /* TODO(ctiller): opportunistically compress non-binary headers */
 | 
	
		
			
				|  |  | -  *huffman_prefix = 0x00;
 | 
	
		
			
				|  |  | -  return grpc_slice_ref_internal(GRPC_MDVALUE(elem));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static size_t wire_value_length(wire_value v) {
 | 
	
		
			
				|  |  | +  return GPR_SLICE_LENGTH(v.data) + v.insert_null_before_wire_value;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void add_wire_value(framer_state *st, wire_value v) {
 | 
	
		
			
				|  |  | +  if (v.insert_null_before_wire_value) *add_tiny_header_data(st, 1) = 0;
 | 
	
		
			
				|  |  | +  add_header_data(st, v.data);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
 | 
	
		
			
				|  |  |                                 uint32_t key_index, grpc_mdelem elem,
 | 
	
		
			
				|  |  |                                 framer_state *st) {
 | 
	
		
			
				|  |  |    uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
 | 
	
		
			
				|  |  | -  uint8_t huffman_prefix;
 | 
	
		
			
				|  |  | -  grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
 | 
	
		
			
				|  |  | -  size_t len_val = GRPC_SLICE_LENGTH(value_slice);
 | 
	
		
			
				|  |  | +  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
 | 
	
		
			
				|  |  | +  size_t len_val = wire_value_length(value);
 | 
	
		
			
				|  |  |    uint32_t len_val_len;
 | 
	
		
			
				|  |  |    GPR_ASSERT(len_val <= UINT32_MAX);
 | 
	
		
			
				|  |  |    len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40,
 | 
	
		
			
				|  |  |                             add_tiny_header_data(st, len_pfx), len_pfx);
 | 
	
		
			
				|  |  | -  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
 | 
	
		
			
				|  |  | +  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, value.huffman_prefix,
 | 
	
		
			
				|  |  |                             add_tiny_header_data(st, len_val_len), len_val_len);
 | 
	
		
			
				|  |  | -  add_header_data(st, value_slice);
 | 
	
		
			
				|  |  | +  add_wire_value(st, value);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
 | 
	
		
			
				|  |  |                                uint32_t key_index, grpc_mdelem elem,
 | 
	
		
			
				|  |  |                                framer_state *st) {
 | 
	
		
			
				|  |  |    uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
 | 
	
		
			
				|  |  | -  uint8_t huffman_prefix;
 | 
	
		
			
				|  |  | -  grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
 | 
	
		
			
				|  |  | -  size_t len_val = GRPC_SLICE_LENGTH(value_slice);
 | 
	
		
			
				|  |  | +  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
 | 
	
		
			
				|  |  | +  size_t len_val = wire_value_length(value);
 | 
	
		
			
				|  |  |    uint32_t len_val_len;
 | 
	
		
			
				|  |  |    GPR_ASSERT(len_val <= UINT32_MAX);
 | 
	
		
			
				|  |  |    len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00,
 | 
	
		
			
				|  |  |                             add_tiny_header_data(st, len_pfx), len_pfx);
 | 
	
		
			
				|  |  | -  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
 | 
	
		
			
				|  |  | +  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, value.huffman_prefix,
 | 
	
		
			
				|  |  |                             add_tiny_header_data(st, len_val_len), len_val_len);
 | 
	
		
			
				|  |  | -  add_header_data(st, value_slice);
 | 
	
		
			
				|  |  | +  add_wire_value(st, value);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
 | 
	
		
			
				|  |  |                                   grpc_mdelem elem, framer_state *st) {
 | 
	
		
			
				|  |  |    uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
 | 
	
		
			
				|  |  | -  uint8_t huffman_prefix;
 | 
	
		
			
				|  |  | -  grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
 | 
	
		
			
				|  |  | -  uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
 | 
	
		
			
				|  |  | +  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
 | 
	
		
			
				|  |  | +  uint32_t len_val = (uint32_t)wire_value_length(value);
 | 
	
		
			
				|  |  |    uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
 | 
	
		
			
				|  |  |    uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
 | 
	
		
			
				|  |  |    GPR_ASSERT(len_key <= UINT32_MAX);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(GRPC_SLICE_LENGTH(value_slice) <= UINT32_MAX);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(wire_value_length(value) <= UINT32_MAX);
 | 
	
		
			
				|  |  |    *add_tiny_header_data(st, 1) = 0x40;
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
 | 
	
		
			
				|  |  |                             add_tiny_header_data(st, len_key_len), len_key_len);
 | 
	
		
			
				|  |  |    add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem)));
 | 
	
		
			
				|  |  | -  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
 | 
	
		
			
				|  |  | +  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, value.huffman_prefix,
 | 
	
		
			
				|  |  |                             add_tiny_header_data(st, len_val_len), len_val_len);
 | 
	
		
			
				|  |  | -  add_header_data(st, value_slice);
 | 
	
		
			
				|  |  | +  add_wire_value(st, value);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
 | 
	
		
			
				|  |  |                                  grpc_mdelem elem, framer_state *st) {
 | 
	
		
			
				|  |  |    uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
 | 
	
		
			
				|  |  | -  uint8_t huffman_prefix;
 | 
	
		
			
				|  |  | -  grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
 | 
	
		
			
				|  |  | -  uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
 | 
	
		
			
				|  |  | +  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
 | 
	
		
			
				|  |  | +  uint32_t len_val = (uint32_t)wire_value_length(value);
 | 
	
		
			
				|  |  |    uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
 | 
	
		
			
				|  |  |    uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
 | 
	
		
			
				|  |  |    GPR_ASSERT(len_key <= UINT32_MAX);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(GRPC_SLICE_LENGTH(value_slice) <= UINT32_MAX);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(wire_value_length(value) <= UINT32_MAX);
 | 
	
		
			
				|  |  |    *add_tiny_header_data(st, 1) = 0x00;
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
 | 
	
		
			
				|  |  |                             add_tiny_header_data(st, len_key_len), len_key_len);
 | 
	
		
			
				|  |  |    add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem)));
 | 
	
		
			
				|  |  | -  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
 | 
	
		
			
				|  |  | +  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, value.huffman_prefix,
 | 
	
		
			
				|  |  |                             add_tiny_header_data(st, len_val_len), len_val_len);
 | 
	
		
			
				|  |  | -  add_header_data(st, value_slice);
 | 
	
		
			
				|  |  | +  add_wire_value(st, value);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
 | 
	
	
		
			
				|  | @@ -610,6 +638,7 @@ void grpc_chttp2_encode_header(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    st.is_first_frame = 1;
 | 
	
		
			
				|  |  |    st.stats = options->stats;
 | 
	
		
			
				|  |  |    st.max_frame_size = options->max_frame_size;
 | 
	
		
			
				|  |  | +  st.use_true_binary_metadata = options->use_true_binary_metadata;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Encode a metadata batch; store the returned values, representing
 | 
	
		
			
				|  |  |       a metadata element that needs to be unreffed back into the metadata
 |