Home | History | Annotate | Download | only in chttp2
      1 /*
      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  */
     18 
     19 #include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
     20 
     21 #include <stdio.h>
     22 #include <string.h>
     23 
     24 #include <grpc/support/alloc.h>
     25 #include <grpc/support/log.h>
     26 #include <grpc/support/string_util.h>
     27 
     28 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
     29 #include "src/core/lib/gpr/string.h"
     30 #include "src/core/lib/slice/slice_internal.h"
     31 #include "src/core/lib/slice/slice_string_helpers.h"
     32 #include "src/core/lib/transport/metadata.h"
     33 #include "test/core/util/parse_hexstring.h"
     34 #include "test/core/util/slice_splitter.h"
     35 #include "test/core/util/test_config.h"
     36 
     37 #define TEST(x) run_test(x, #x)
     38 
     39 grpc_chttp2_hpack_compressor g_compressor;
     40 int g_failure = 0;
     41 
     42 void** to_delete = nullptr;
     43 size_t num_to_delete = 0;
     44 size_t cap_to_delete = 0;
     45 
     46 typedef struct {
     47   bool eof;
     48   bool use_true_binary_metadata;
     49   bool only_intern_key;
     50 } verify_params;
     51 
     52 /* verify that the output generated by encoding the stream matches the
     53    hexstring passed in */
     54 static void verify(const verify_params params, const char* expected,
     55                    size_t nheaders, ...) {
     56   grpc_slice_buffer output;
     57   grpc_slice merged;
     58   grpc_slice expect = parse_hexstring(expected);
     59   size_t i;
     60   va_list l;
     61   grpc_linked_mdelem* e =
     62       static_cast<grpc_linked_mdelem*>(gpr_malloc(sizeof(*e) * nheaders));
     63   grpc_metadata_batch b;
     64 
     65   grpc_metadata_batch_init(&b);
     66 
     67   va_start(l, nheaders);
     68   for (i = 0; i < nheaders; i++) {
     69     char* key = va_arg(l, char*);
     70     char* value = va_arg(l, char*);
     71     if (i) {
     72       e[i - 1].next = &e[i];
     73       e[i].prev = &e[i - 1];
     74     }
     75     grpc_slice value_slice = grpc_slice_from_static_string(value);
     76     if (!params.only_intern_key) {
     77       value_slice = grpc_slice_intern(value_slice);
     78     }
     79     e[i].md = grpc_mdelem_from_slices(
     80         grpc_slice_intern(grpc_slice_from_static_string(key)), value_slice);
     81   }
     82   e[0].prev = nullptr;
     83   e[nheaders - 1].next = nullptr;
     84   va_end(l);
     85 
     86   b.list.head = &e[0];
     87   b.list.tail = &e[nheaders - 1];
     88   b.list.count = nheaders;
     89 
     90   if (cap_to_delete == num_to_delete) {
     91     cap_to_delete = GPR_MAX(2 * cap_to_delete, 1000);
     92     to_delete = static_cast<void**>(
     93         gpr_realloc(to_delete, sizeof(*to_delete) * cap_to_delete));
     94   }
     95   to_delete[num_to_delete++] = e;
     96 
     97   grpc_slice_buffer_init(&output);
     98 
     99   grpc_transport_one_way_stats stats;
    100   memset(&stats, 0, sizeof(stats));
    101   grpc_encode_header_options hopt = {
    102       0xdeadbeef,                      /* stream_id */
    103       params.eof,                      /* is_eof */
    104       params.use_true_binary_metadata, /* use_true_binary_metadata */
    105       16384,                           /* max_frame_size */
    106       &stats                           /* stats */
    107   };
    108   grpc_chttp2_encode_header(&g_compressor, nullptr, 0, &b, &hopt, &output);
    109   merged = grpc_slice_merge(output.slices, output.count);
    110   grpc_slice_buffer_destroy_internal(&output);
    111   grpc_metadata_batch_destroy(&b);
    112 
    113   if (!grpc_slice_eq(merged, expect)) {
    114     char* expect_str = grpc_dump_slice(expect, GPR_DUMP_HEX | GPR_DUMP_ASCII);
    115     char* got_str = grpc_dump_slice(merged, GPR_DUMP_HEX | GPR_DUMP_ASCII);
    116     gpr_log(GPR_ERROR, "mismatched output for %s", expected);
    117     gpr_log(GPR_ERROR, "EXPECT: %s", expect_str);
    118     gpr_log(GPR_ERROR, "GOT:    %s", got_str);
    119     gpr_free(expect_str);
    120     gpr_free(got_str);
    121     g_failure = 1;
    122   }
    123 
    124   grpc_slice_unref_internal(merged);
    125   grpc_slice_unref_internal(expect);
    126 }
    127 
    128 static void test_basic_headers() {
    129   int i;
    130 
    131   verify_params params = {
    132       false,
    133       false,
    134       false,
    135   };
    136   verify(params, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a");
    137   verify(params, "000001 0104 deadbeef be", 1, "a", "a");
    138   verify(params, "000001 0104 deadbeef be", 1, "a", "a");
    139   verify(params, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a", "b", "c");
    140   verify(params, "000002 0104 deadbeef bf be", 2, "a", "a", "b", "c");
    141   verify(params, "000004 0104 deadbeef 7f 00 0164", 1, "a", "d");
    142 
    143   /* flush out what's there to make a few values look very popular */
    144   for (i = 0; i < 350; i++) {
    145     verify(params, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b", "c", "a",
    146            "d");
    147   }
    148 
    149   verify(params, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a", "k", "v");
    150   /* this could be 000004 0104 deadbeef 0f 30 0176 also */
    151   verify(params, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v");
    152 }
    153 
    154 static void encode_int_to_str(int i, char* p) {
    155   p[0] = static_cast<char>('a' + i % 26);
    156   i /= 26;
    157   GPR_ASSERT(i < 26);
    158   p[1] = static_cast<char>('a' + i);
    159   p[2] = 0;
    160 }
    161 
    162 static void test_decode_table_overflow() {
    163   // Decrease the default table size to make decode table overflow easier.
    164   grpc_chttp2_hpack_compressor_set_max_table_size(&g_compressor, 1024);
    165   int i;
    166   char key[3], value[3];
    167   char* expect;
    168 
    169   verify_params params = {
    170       false,
    171       false,
    172       false,
    173   };
    174 
    175   for (i = 0; i < 29; i++) {
    176     encode_int_to_str(i, key);
    177     encode_int_to_str(i + 1, value);
    178     if (i == 0) {
    179       // 3fe107 corresponds to the table size update.
    180       gpr_asprintf(&expect,
    181                    "00000a 0104 deadbeef 3fe107 40 02%02x%02x 02%02x%02x",
    182                    key[0], key[1], value[0], value[1]);
    183       verify(params, expect, 1, key, value);
    184     } else {
    185       gpr_asprintf(&expect,
    186                    "000008 0104 deadbeef %02x 40 02%02x%02x 02%02x%02x",
    187                    0x80 + 61 + i, key[0], key[1], value[0], value[1]);
    188       verify(params, expect, 2, "aa", "ba", key, value);
    189     }
    190     gpr_free(expect);
    191   }
    192 
    193   /* if the above passes, then we must have just knocked this pair out of the
    194      decoder stack, and so we'll be forced to re-encode it */
    195   verify(params, "000007 0104 deadbeef 40 026161 026261", 1, "aa", "ba");
    196 }
    197 
    198 static void verify_table_size_change_match_elem_size(const char* key,
    199                                                      const char* value,
    200                                                      bool use_true_binary) {
    201   grpc_slice_buffer output;
    202   grpc_mdelem elem = grpc_mdelem_from_slices(
    203       grpc_slice_intern(grpc_slice_from_static_string(key)),
    204       grpc_slice_intern(grpc_slice_from_static_string(value)));
    205   size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, use_true_binary);
    206   size_t initial_table_size = g_compressor.table_size;
    207   grpc_linked_mdelem* e =
    208       static_cast<grpc_linked_mdelem*>(gpr_malloc(sizeof(*e)));
    209   grpc_metadata_batch b;
    210   grpc_metadata_batch_init(&b);
    211   e[0].md = elem;
    212   e[0].prev = nullptr;
    213   e[0].next = nullptr;
    214   b.list.head = &e[0];
    215   b.list.tail = &e[0];
    216   b.list.count = 1;
    217   grpc_slice_buffer_init(&output);
    218 
    219   grpc_transport_one_way_stats stats;
    220   memset(&stats, 0, sizeof(stats));
    221   grpc_encode_header_options hopt = {
    222       0xdeadbeef,      /* stream_id */
    223       false,           /* is_eof */
    224       use_true_binary, /* use_true_binary_metadata */
    225       16384,           /* max_frame_size */
    226       &stats /* stats */};
    227   grpc_chttp2_encode_header(&g_compressor, nullptr, 0, &b, &hopt, &output);
    228   grpc_slice_buffer_destroy_internal(&output);
    229   grpc_metadata_batch_destroy(&b);
    230 
    231   GPR_ASSERT(g_compressor.table_size == elem_size + initial_table_size);
    232   gpr_free(e);
    233 }
    234 
    235 static void test_encode_header_size() {
    236   verify_table_size_change_match_elem_size("hello", "world", false);
    237   verify_table_size_change_match_elem_size("hello-bin", "world", false);
    238   verify_table_size_change_match_elem_size("true-binary-bin",
    239                                            "I_am_true_binary_value", true);
    240 }
    241 
    242 static void test_interned_key_indexed() {
    243   int i;
    244   verify_params params = {false, false, true};
    245   verify(params, "000009 0104 deadbeef 40 0161 0162 0f2f 0163", 2, "a", "b",
    246          "a", "c");
    247   for (i = 0; i < 10; i++) {
    248     verify(params, "000008 0104 deadbeef 0f2f 0162 0f2f 0163", 2, "a", "b", "a",
    249            "c");
    250   }
    251 }
    252 
    253 static void run_test(void (*test)(), const char* name) {
    254   gpr_log(GPR_INFO, "RUN TEST: %s", name);
    255   grpc_core::ExecCtx exec_ctx;
    256   grpc_chttp2_hpack_compressor_init(&g_compressor);
    257   test();
    258   grpc_chttp2_hpack_compressor_destroy(&g_compressor);
    259 }
    260 
    261 int main(int argc, char** argv) {
    262   size_t i;
    263   grpc_test_only_set_slice_hash_seed(0);
    264   grpc_test_init(argc, argv);
    265   grpc_init();
    266   TEST(test_basic_headers);
    267   TEST(test_decode_table_overflow);
    268   TEST(test_encode_header_size);
    269   TEST(test_interned_key_indexed);
    270   grpc_shutdown();
    271   for (i = 0; i < num_to_delete; i++) {
    272     gpr_free(to_delete[i]);
    273   }
    274   return g_failure;
    275 }
    276