• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
verify(const verify_params params,const char * expected,size_t nheaders,...)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 
test_basic_headers()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 
encode_int_to_str(int i,char * p)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 
test_decode_table_overflow()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 
verify_table_size_change_match_elem_size(const char * key,const char * value,bool use_true_binary)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 
test_encode_header_size()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 
test_interned_key_indexed()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 
run_test(void (* test)(),const char * name)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 
main(int argc,char ** argv)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