|  | @@ -43,10 +43,15 @@ void **to_delete = NULL;
 | 
	
		
			
				|  |  |  size_t num_to_delete = 0;
 | 
	
		
			
				|  |  |  size_t cap_to_delete = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +typedef struct {
 | 
	
		
			
				|  |  | +  bool eof;
 | 
	
		
			
				|  |  | +  bool use_true_binary_metadata;
 | 
	
		
			
				|  |  | +  bool only_intern_key;
 | 
	
		
			
				|  |  | +} verify_params;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /* verify that the output generated by encoding the stream matches the
 | 
	
		
			
				|  |  |     hexstring passed in */
 | 
	
		
			
				|  |  | -static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
 | 
	
		
			
				|  |  | -                   bool use_true_binary_metadata, size_t expect_window_used,
 | 
	
		
			
				|  |  | +static void verify(grpc_exec_ctx *exec_ctx, const verify_params params,
 | 
	
		
			
				|  |  |                     const char *expected, size_t nheaders, ...) {
 | 
	
		
			
				|  |  |    grpc_slice_buffer output;
 | 
	
		
			
				|  |  |    grpc_slice merged;
 | 
	
	
		
			
				|  | @@ -66,9 +71,13 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
 | 
	
		
			
				|  |  |        e[i - 1].next = &e[i];
 | 
	
		
			
				|  |  |        e[i].prev = &e[i - 1];
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    grpc_slice value_slice = grpc_slice_from_static_string(value);
 | 
	
		
			
				|  |  | +    if (!params.only_intern_key) {
 | 
	
		
			
				|  |  | +      value_slice = grpc_slice_intern(value_slice);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      e[i].md = grpc_mdelem_from_slices(
 | 
	
		
			
				|  |  |          exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)),
 | 
	
		
			
				|  |  | -        grpc_slice_intern(grpc_slice_from_static_string(value)));
 | 
	
		
			
				|  |  | +        value_slice);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    e[0].prev = NULL;
 | 
	
		
			
				|  |  |    e[nheaders - 1].next = NULL;
 | 
	
	
		
			
				|  | @@ -90,8 +99,8 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
 | 
	
		
			
				|  |  |    memset(&stats, 0, sizeof(stats));
 | 
	
		
			
				|  |  |    grpc_encode_header_options hopt = {
 | 
	
		
			
				|  |  |        .stream_id = 0xdeadbeef,
 | 
	
		
			
				|  |  | -      .is_eof = eof,
 | 
	
		
			
				|  |  | -      .use_true_binary_metadata = use_true_binary_metadata,
 | 
	
		
			
				|  |  | +      .is_eof = params.eof,
 | 
	
		
			
				|  |  | +      .use_true_binary_metadata = params.use_true_binary_metadata,
 | 
	
		
			
				|  |  |        .max_frame_size = 16384,
 | 
	
		
			
				|  |  |        .stats = &stats,
 | 
	
		
			
				|  |  |    };
 | 
	
	
		
			
				|  | @@ -119,28 +128,27 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
 | 
	
		
			
				|  |  |  static void test_basic_headers(grpc_exec_ctx *exec_ctx) {
 | 
	
		
			
				|  |  |    int i;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000005 0104 deadbeef 40 0161 0161", 1,
 | 
	
		
			
				|  |  | -         "a", "a");
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000001 0104 deadbeef be", 1, "a", "a");
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000001 0104 deadbeef be", 1, "a", "a");
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef be 40 0162 0163",
 | 
	
		
			
				|  |  | -         2, "a", "a", "b", "c");
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000002 0104 deadbeef bf be", 2, "a",
 | 
	
		
			
				|  |  | -         "a", "b", "c");
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 7f 00 0164", 1,
 | 
	
		
			
				|  |  | -         "a", "d");
 | 
	
		
			
				|  |  | +  verify_params params = {
 | 
	
		
			
				|  |  | +      .eof = false, .use_true_binary_metadata = false, .only_intern_key = false,
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a");
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000001 0104 deadbeef be", 1, "a", "a");
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000001 0104 deadbeef be", 1, "a", "a");
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a",
 | 
	
		
			
				|  |  | +         "b", "c");
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000002 0104 deadbeef bf be", 2, "a", "a", "b", "c");
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000004 0104 deadbeef 7f 00 0164", 1, "a", "d");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* flush out what's there to make a few values look very popular */
 | 
	
		
			
				|  |  |    for (i = 0; i < 350; i++) {
 | 
	
		
			
				|  |  | -    verify(exec_ctx, 0, false, false, 0, "000003 0104 deadbeef c0 bf be", 3,
 | 
	
		
			
				|  |  | -           "a", "a", "b", "c", "a", "d");
 | 
	
		
			
				|  |  | +    verify(exec_ctx, params, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b",
 | 
	
		
			
				|  |  | +           "c", "a", "d");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef c0 00 016b 0176",
 | 
	
		
			
				|  |  | -         2, "a", "a", "k", "v");
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a",
 | 
	
		
			
				|  |  | +         "k", "v");
 | 
	
		
			
				|  |  |    /* this could be 000004 0104 deadbeef 0f 30 0176 also */
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 0f 2f 0176", 1,
 | 
	
		
			
				|  |  | -         "a", "v");
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void encode_int_to_str(int i, char *p) {
 | 
	
	
		
			
				|  | @@ -156,6 +164,10 @@ static void test_decode_table_overflow(grpc_exec_ctx *exec_ctx) {
 | 
	
		
			
				|  |  |    char key[3], value[3];
 | 
	
		
			
				|  |  |    char *expect;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  verify_params params = {
 | 
	
		
			
				|  |  | +      .eof = false, .use_true_binary_metadata = false, .only_intern_key = false,
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    for (i = 0; i < 114; i++) {
 | 
	
		
			
				|  |  |      encode_int_to_str(i, key);
 | 
	
		
			
				|  |  |      encode_int_to_str(i + 1, value);
 | 
	
	
		
			
				|  | @@ -174,27 +186,28 @@ static void test_decode_table_overflow(grpc_exec_ctx *exec_ctx) {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (i > 0) {
 | 
	
		
			
				|  |  | -      verify(exec_ctx, 0, false, false, 0, expect, 2, "aa", "ba", key, value);
 | 
	
		
			
				|  |  | +      verify(exec_ctx, params, expect, 2, "aa", "ba", key, value);
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  | -      verify(exec_ctx, 0, false, false, 0, expect, 1, key, value);
 | 
	
		
			
				|  |  | +      verify(exec_ctx, params, expect, 1, key, value);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      gpr_free(expect);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* if the above passes, then we must have just knocked this pair out of the
 | 
	
		
			
				|  |  |       decoder stack, and so we'll be forced to re-encode it */
 | 
	
		
			
				|  |  | -  verify(exec_ctx, 0, false, false, 0, "000007 0104 deadbeef 40 026161 026261",
 | 
	
		
			
				|  |  | -         1, "aa", "ba");
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000007 0104 deadbeef 40 026161 026261", 1, "aa",
 | 
	
		
			
				|  |  | +         "ba");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                                       const char *key,
 | 
	
		
			
				|  |  | -                                                     const char *value) {
 | 
	
		
			
				|  |  | +                                                     const char *value,
 | 
	
		
			
				|  |  | +                                                     bool use_true_binary) {
 | 
	
		
			
				|  |  |    grpc_slice_buffer output;
 | 
	
		
			
				|  |  |    grpc_mdelem elem = grpc_mdelem_from_slices(
 | 
	
		
			
				|  |  |        exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)),
 | 
	
		
			
				|  |  |        grpc_slice_intern(grpc_slice_from_static_string(value)));
 | 
	
		
			
				|  |  | -  size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem);
 | 
	
		
			
				|  |  | +  size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, use_true_binary);
 | 
	
		
			
				|  |  |    size_t initial_table_size = g_compressor.table_size;
 | 
	
		
			
				|  |  |    grpc_linked_mdelem *e = gpr_malloc(sizeof(*e));
 | 
	
		
			
				|  |  |    grpc_metadata_batch b;
 | 
	
	
		
			
				|  | @@ -209,11 +222,12 @@ static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_transport_one_way_stats stats;
 | 
	
		
			
				|  |  |    memset(&stats, 0, sizeof(stats));
 | 
	
		
			
				|  |  | -  grpc_encode_header_options hopt = {.stream_id = 0xdeadbeef,
 | 
	
		
			
				|  |  | -                                     .is_eof = false,
 | 
	
		
			
				|  |  | -                                     .use_true_binary_metadata = false,
 | 
	
		
			
				|  |  | -                                     .max_frame_size = 16384,
 | 
	
		
			
				|  |  | -                                     .stats = &stats};
 | 
	
		
			
				|  |  | +  grpc_encode_header_options hopt = {
 | 
	
		
			
				|  |  | +      .stream_id = 0xdeadbeef,
 | 
	
		
			
				|  |  | +      .is_eof = false,
 | 
	
		
			
				|  |  | +      .use_true_binary_metadata = use_true_binary,
 | 
	
		
			
				|  |  | +      .max_frame_size = 16384,
 | 
	
		
			
				|  |  | +      .stats = &stats};
 | 
	
		
			
				|  |  |    grpc_chttp2_encode_header(exec_ctx, &g_compressor, NULL, 0, &b, &hopt,
 | 
	
		
			
				|  |  |                              &output);
 | 
	
		
			
				|  |  |    grpc_slice_buffer_destroy_internal(exec_ctx, &output);
 | 
	
	
		
			
				|  | @@ -224,8 +238,24 @@ static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void test_encode_header_size(grpc_exec_ctx *exec_ctx) {
 | 
	
		
			
				|  |  | -  verify_table_size_change_match_elem_size(exec_ctx, "hello", "world");
 | 
	
		
			
				|  |  | -  verify_table_size_change_match_elem_size(exec_ctx, "hello-bin", "world");
 | 
	
		
			
				|  |  | +  verify_table_size_change_match_elem_size(exec_ctx, "hello", "world", false);
 | 
	
		
			
				|  |  | +  verify_table_size_change_match_elem_size(exec_ctx, "hello-bin", "world",
 | 
	
		
			
				|  |  | +                                           false);
 | 
	
		
			
				|  |  | +  verify_table_size_change_match_elem_size(exec_ctx, "true-binary-bin",
 | 
	
		
			
				|  |  | +                                           "I_am_true_binary_value", true);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void test_interned_key_indexed(grpc_exec_ctx *exec_ctx) {
 | 
	
		
			
				|  |  | +  int i;
 | 
	
		
			
				|  |  | +  verify_params params = {
 | 
	
		
			
				|  |  | +      .eof = false, .use_true_binary_metadata = false, .only_intern_key = true,
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  verify(exec_ctx, params, "000009 0104 deadbeef 40 0161 0162 0f2f 0163", 2,
 | 
	
		
			
				|  |  | +         "a", "b", "a", "c");
 | 
	
		
			
				|  |  | +  for (i = 0; i < 10; i++) {
 | 
	
		
			
				|  |  | +    verify(exec_ctx, params, "000008 0104 deadbeef 0f2f 0162 0f2f 0163", 2, "a",
 | 
	
		
			
				|  |  | +           "b", "a", "c");
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void run_test(void (*test)(grpc_exec_ctx *exec_ctx), const char *name) {
 | 
	
	
		
			
				|  | @@ -245,6 +275,7 @@ int main(int argc, char **argv) {
 | 
	
		
			
				|  |  |    TEST(test_basic_headers);
 | 
	
		
			
				|  |  |    TEST(test_decode_table_overflow);
 | 
	
		
			
				|  |  |    TEST(test_encode_header_size);
 | 
	
		
			
				|  |  | +  TEST(test_interned_key_indexed);
 | 
	
		
			
				|  |  |    grpc_shutdown();
 | 
	
		
			
				|  |  |    for (i = 0; i < num_to_delete; i++) {
 | 
	
		
			
				|  |  |      gpr_free(to_delete[i]);
 |