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