• 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/lib/transport/metadata.h"
20 
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include <string>
25 
26 #include "absl/strings/str_format.h"
27 
28 #include <grpc/grpc.h>
29 #include <grpc/support/alloc.h>
30 #include <grpc/support/log.h>
31 
32 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
33 #include "src/core/ext/transport/chttp2/transport/hpack_table.h"
34 #include "src/core/lib/gpr/string.h"
35 #include "src/core/lib/iomgr/exec_ctx.h"
36 #include "src/core/lib/slice/slice_internal.h"
37 #include "src/core/lib/transport/static_metadata.h"
38 #include "test/core/util/test_config.h"
39 
40 /* a large number */
41 #define MANY 10000
42 
test_no_op(void)43 static void test_no_op(void) {
44   gpr_log(GPR_INFO, "test_no_op");
45   grpc_init();
46   grpc_shutdown();
47 }
48 
maybe_intern(grpc_slice in,bool intern)49 static grpc_slice maybe_intern(grpc_slice in, bool intern) {
50   grpc_slice out = intern ? grpc_slice_intern(in) : grpc_slice_ref(in);
51   grpc_slice_unref(in);
52   return out;
53 }
54 
maybe_dup(grpc_slice in,bool dup)55 static grpc_slice maybe_dup(grpc_slice in, bool dup) {
56   grpc_slice out = dup ? grpc_slice_dup(in) : grpc_slice_ref(in);
57   grpc_slice_unref(in);
58   return out;
59 }
60 
test_create_metadata(bool intern_keys,bool intern_values)61 static void test_create_metadata(bool intern_keys, bool intern_values) {
62   grpc_mdelem m1, m2, m3;
63 
64   gpr_log(GPR_INFO, "test_create_metadata: intern_keys=%d intern_values=%d",
65           intern_keys, intern_values);
66 
67   grpc_init();
68   grpc_core::ExecCtx exec_ctx;
69   m1 = grpc_mdelem_from_slices(
70       maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
71       maybe_intern(grpc_slice_from_static_string("b"), intern_values));
72   m2 = grpc_mdelem_from_slices(
73       maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
74       maybe_intern(grpc_slice_from_static_string("b"), intern_values));
75   m3 = grpc_mdelem_from_slices(
76       maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
77       maybe_intern(grpc_slice_from_static_string("c"), intern_values));
78   GPR_ASSERT(grpc_mdelem_eq(m1, m2));
79   GPR_ASSERT(!grpc_mdelem_eq(m3, m1));
80   GPR_ASSERT(grpc_slice_eq(GRPC_MDKEY(m3), GRPC_MDKEY(m1)));
81   GPR_ASSERT(!grpc_slice_eq(GRPC_MDVALUE(m3), GRPC_MDVALUE(m1)));
82   GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDKEY(m1), "a") == 0);
83   GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDVALUE(m1), "b") == 0);
84   GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDVALUE(m3), "c") == 0);
85   GRPC_MDELEM_UNREF(m1);
86   GRPC_MDELEM_UNREF(m2);
87   GRPC_MDELEM_UNREF(m3);
88 
89   grpc_shutdown();
90 }
91 
test_create_many_ephemeral_metadata(bool intern_keys,bool intern_values)92 static void test_create_many_ephemeral_metadata(bool intern_keys,
93                                                 bool intern_values) {
94   char buffer[GPR_LTOA_MIN_BUFSIZE];
95   long i;
96 
97   gpr_log(
98       GPR_INFO,
99       "test_create_many_ephemeral_metadata: intern_keys=%d intern_values=%d",
100       intern_keys, intern_values);
101 
102   grpc_init();
103   grpc_core::ExecCtx exec_ctx;
104   /* add, and immediately delete a bunch of different elements */
105   for (i = 0; i < MANY; i++) {
106     gpr_ltoa(i, buffer);
107     GRPC_MDELEM_UNREF(grpc_mdelem_from_slices(
108         maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
109         maybe_intern(grpc_slice_from_copied_string(buffer), intern_values)));
110   }
111 
112   grpc_shutdown();
113 }
114 
test_create_many_persistant_metadata(void)115 static void test_create_many_persistant_metadata(void) {
116   char buffer[GPR_LTOA_MIN_BUFSIZE];
117   long i;
118   grpc_mdelem* created =
119       static_cast<grpc_mdelem*>(gpr_malloc(sizeof(grpc_mdelem) * MANY));
120   grpc_mdelem md;
121 
122   gpr_log(GPR_INFO, "test_create_many_persistant_metadata");
123 
124   grpc_init();
125   grpc_core::ExecCtx exec_ctx;
126   /* add phase */
127   for (i = 0; i < MANY; i++) {
128     gpr_ltoa(i, buffer);
129     created[i] = grpc_mdelem_from_slices(
130         grpc_slice_intern(grpc_slice_from_static_string("a")),
131         grpc_slice_intern(grpc_slice_from_static_string(buffer)));
132   }
133   /* verify phase */
134   for (i = 0; i < MANY; i++) {
135     gpr_ltoa(i, buffer);
136     md = grpc_mdelem_from_slices(
137         grpc_slice_intern(grpc_slice_from_static_string("a")),
138         grpc_slice_intern(grpc_slice_from_static_string(buffer)));
139     GPR_ASSERT(grpc_mdelem_eq(md, created[i]));
140     GRPC_MDELEM_UNREF(md);
141   }
142   /* cleanup phase */
143   for (i = 0; i < MANY; i++) {
144     GRPC_MDELEM_UNREF(created[i]);
145   }
146 
147   grpc_shutdown();
148 
149   gpr_free(created);
150 }
151 
test_spin_creating_the_same_thing(bool intern_keys,bool intern_values)152 static void test_spin_creating_the_same_thing(bool intern_keys,
153                                               bool intern_values) {
154   gpr_log(GPR_INFO,
155           "test_spin_creating_the_same_thing: intern_keys=%d intern_values=%d",
156           intern_keys, intern_values);
157 
158   grpc_init();
159   grpc_core::ExecCtx exec_ctx;
160   grpc_mdelem a, b, c;
161   GRPC_MDELEM_UNREF(
162       a = grpc_mdelem_from_slices(
163           maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
164           maybe_intern(grpc_slice_from_static_string("b"), intern_values)));
165   GRPC_MDELEM_UNREF(
166       b = grpc_mdelem_from_slices(
167           maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
168           maybe_intern(grpc_slice_from_static_string("b"), intern_values)));
169   GRPC_MDELEM_UNREF(
170       c = grpc_mdelem_from_slices(
171           maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
172           maybe_intern(grpc_slice_from_static_string("b"), intern_values)));
173   if (intern_keys && intern_values) {
174     GPR_ASSERT(a.payload == b.payload);
175     GPR_ASSERT(a.payload == c.payload);
176   }
177 
178   grpc_shutdown();
179 }
180 
test_identity_laws(bool intern_keys,bool intern_values)181 static void test_identity_laws(bool intern_keys, bool intern_values) {
182   gpr_log(GPR_INFO, "test_identity_laws: intern_keys=%d intern_values=%d",
183           intern_keys, intern_values);
184 
185   grpc_init();
186   grpc_core::ExecCtx exec_ctx;
187   grpc_mdelem a, b, c;
188   a = grpc_mdelem_from_slices(
189       maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
190       maybe_intern(grpc_slice_from_static_string("b"), intern_values));
191   b = grpc_mdelem_from_slices(
192       maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
193       maybe_intern(grpc_slice_from_static_string("b"), intern_values));
194   c = grpc_mdelem_from_slices(
195       maybe_intern(grpc_slice_from_static_string("a"), intern_keys),
196       maybe_intern(grpc_slice_from_static_string("b"), intern_values));
197   GPR_ASSERT(grpc_mdelem_eq(a, a));
198   GPR_ASSERT(grpc_mdelem_eq(b, b));
199   GPR_ASSERT(grpc_mdelem_eq(c, c));
200   GPR_ASSERT(grpc_mdelem_eq(a, b));
201   GPR_ASSERT(grpc_mdelem_eq(b, c));
202   GPR_ASSERT(grpc_mdelem_eq(a, c));
203   GPR_ASSERT(grpc_mdelem_eq(b, a));
204   GPR_ASSERT(grpc_mdelem_eq(c, b));
205   GPR_ASSERT(grpc_mdelem_eq(c, a));
206   if (intern_keys && intern_values) {
207     GPR_ASSERT(a.payload == b.payload);
208     GPR_ASSERT(a.payload == c.payload);
209   } else {
210     GPR_ASSERT(a.payload != b.payload);
211     GPR_ASSERT(a.payload != c.payload);
212     GPR_ASSERT(b.payload != c.payload);
213   }
214   GRPC_MDELEM_UNREF(a);
215   GRPC_MDELEM_UNREF(b);
216   GRPC_MDELEM_UNREF(c);
217 
218   grpc_shutdown();
219 }
220 
test_things_stick_around(void)221 static void test_things_stick_around(void) {
222   size_t i, j;
223   size_t nstrs = 1000;
224   grpc_slice* strs =
225       static_cast<grpc_slice*>(gpr_malloc(sizeof(grpc_slice) * nstrs));
226   size_t* shuf = static_cast<size_t*>(gpr_malloc(sizeof(size_t) * nstrs));
227   grpc_slice test;
228 
229   gpr_log(GPR_INFO, "test_things_stick_around");
230 
231   grpc_init();
232   grpc_core::ExecCtx exec_ctx;
233 
234   for (i = 0; i < nstrs; i++) {
235     std::string buffer =
236         absl::StrFormat("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%" PRIuPTR "x", i);
237     strs[i] = grpc_slice_intern(grpc_slice_from_static_string(buffer.c_str()));
238     shuf[i] = i;
239   }
240 
241   for (i = 0; i < nstrs; i++) {
242     grpc_slice_ref_internal(strs[i]);
243     grpc_slice_unref_internal(strs[i]);
244   }
245 
246   for (i = 0; i < nstrs; i++) {
247     size_t p = static_cast<size_t>(rand()) % nstrs;
248     size_t q = static_cast<size_t>(rand()) % nstrs;
249     size_t temp = shuf[p];
250     shuf[p] = shuf[q];
251     shuf[q] = temp;
252   }
253 
254   for (i = 0; i < nstrs; i++) {
255     grpc_slice_unref_internal(strs[shuf[i]]);
256     for (j = i + 1; j < nstrs; j++) {
257       std::string buffer = absl::StrFormat(
258           "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%" PRIuPTR "x", shuf[j]);
259       test = grpc_slice_intern(grpc_slice_from_static_string(buffer.c_str()));
260       GPR_ASSERT(grpc_slice_is_equivalent(test, strs[shuf[j]]));
261       grpc_slice_unref_internal(test);
262     }
263   }
264 
265   grpc_shutdown();
266   gpr_free(strs);
267   gpr_free(shuf);
268 }
269 
test_user_data_works(void)270 static void test_user_data_works(void) {
271   int* ud1;
272   int* ud2;
273   grpc_mdelem md;
274   gpr_log(GPR_INFO, "test_user_data_works");
275 
276   grpc_init();
277   grpc_core::ExecCtx exec_ctx;
278   ud1 = static_cast<int*>(gpr_malloc(sizeof(int)));
279   *ud1 = 1;
280   ud2 = static_cast<int*>(gpr_malloc(sizeof(int)));
281   *ud2 = 2;
282   md = grpc_mdelem_from_slices(
283       grpc_slice_intern(grpc_slice_from_static_string("abc")),
284       grpc_slice_intern(grpc_slice_from_static_string("123")));
285   grpc_mdelem_set_user_data(md, gpr_free, ud1);
286   grpc_mdelem_set_user_data(md, gpr_free, ud2);
287   GPR_ASSERT(grpc_mdelem_get_user_data(md, gpr_free) == ud1);
288   GRPC_MDELEM_UNREF(md);
289 
290   grpc_shutdown();
291 }
292 
test_user_data_works_for_allocated_md(void)293 static void test_user_data_works_for_allocated_md(void) {
294   int* ud1;
295   int* ud2;
296   grpc_mdelem md;
297   gpr_log(GPR_INFO, "test_user_data_works");
298 
299   grpc_init();
300   grpc_core::ExecCtx exec_ctx;
301   ud1 = static_cast<int*>(gpr_malloc(sizeof(int)));
302   *ud1 = 1;
303   ud2 = static_cast<int*>(gpr_malloc(sizeof(int)));
304   *ud2 = 2;
305   md = grpc_mdelem_from_slices(grpc_slice_from_static_string("abc"),
306                                grpc_slice_from_static_string("123"));
307   grpc_mdelem_set_user_data(md, gpr_free, ud1);
308   grpc_mdelem_set_user_data(md, gpr_free, ud2);
309   GPR_ASSERT(grpc_mdelem_get_user_data(md, gpr_free) == ud1);
310   GRPC_MDELEM_UNREF(md);
311 
312   grpc_shutdown();
313 }
314 
verify_ascii_header_size(const char * key,const char * value,bool intern_key,bool intern_value)315 static void verify_ascii_header_size(const char* key, const char* value,
316                                      bool intern_key, bool intern_value) {
317   grpc_mdelem elem = grpc_mdelem_from_slices(
318       maybe_intern(grpc_slice_from_static_string(key), intern_key),
319       maybe_intern(grpc_slice_from_static_string(value), intern_value));
320   size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, false);
321   size_t expected_size = 32 + strlen(key) + strlen(value);
322   GPR_ASSERT(expected_size == elem_size);
323   GRPC_MDELEM_UNREF(elem);
324 }
325 
verify_binary_header_size(const char * key,const uint8_t * value,size_t value_len,bool intern_key,bool intern_value)326 static void verify_binary_header_size(const char* key, const uint8_t* value,
327                                       size_t value_len, bool intern_key,
328                                       bool intern_value) {
329   grpc_mdelem elem = grpc_mdelem_from_slices(
330       maybe_intern(grpc_slice_from_static_string(key), intern_key),
331       maybe_intern(grpc_slice_from_static_buffer(value, value_len),
332                    intern_value));
333   GPR_ASSERT(grpc_is_binary_header(GRPC_MDKEY(elem)));
334   size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, false);
335   grpc_slice value_slice = grpc_slice_from_copied_buffer(
336       reinterpret_cast<const char*>(value), value_len);
337   grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice);
338   size_t expected_size = 32 + strlen(key) + GRPC_SLICE_LENGTH(base64_encoded);
339   GPR_ASSERT(expected_size == elem_size);
340   grpc_slice_unref_internal(value_slice);
341   grpc_slice_unref_internal(base64_encoded);
342   GRPC_MDELEM_UNREF(elem);
343 }
344 
345 #define BUFFER_SIZE 64
test_mdelem_sizes_in_hpack(bool intern_key,bool intern_value)346 static void test_mdelem_sizes_in_hpack(bool intern_key, bool intern_value) {
347   gpr_log(GPR_INFO, "test_mdelem_size: intern_key=%d intern_value=%d",
348           intern_key, intern_value);
349   grpc_init();
350   grpc_core::ExecCtx exec_ctx;
351 
352   uint8_t binary_value[BUFFER_SIZE] = {0};
353   for (uint8_t i = 0; i < BUFFER_SIZE; i++) {
354     binary_value[i] = i;
355   }
356 
357   verify_ascii_header_size("hello", "world", intern_key, intern_value);
358   verify_ascii_header_size("hello", "worldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
359                            intern_key, intern_value);
360   verify_ascii_header_size(":scheme", "http", intern_key, intern_value);
361 
362   for (uint8_t i = 0; i < BUFFER_SIZE; i++) {
363     verify_binary_header_size("hello-bin", binary_value, i, intern_key,
364                               intern_value);
365   }
366 
367   grpc_shutdown();
368 }
369 
test_copied_static_metadata(bool dup_key,bool dup_value)370 static void test_copied_static_metadata(bool dup_key, bool dup_value) {
371   gpr_log(GPR_INFO, "test_static_metadata: dup_key=%d dup_value=%d", dup_key,
372           dup_value);
373   grpc_init();
374   grpc_core::ExecCtx exec_ctx;
375 
376   for (size_t i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
377     grpc_mdelem p = GRPC_MAKE_MDELEM(&grpc_static_mdelem_table()[i],
378                                      GRPC_MDELEM_STORAGE_STATIC);
379     grpc_mdelem q =
380         grpc_mdelem_from_slices(maybe_dup(GRPC_MDKEY(p), dup_key),
381                                 maybe_dup(GRPC_MDVALUE(p), dup_value));
382     GPR_ASSERT(grpc_mdelem_eq(p, q));
383     if (dup_key || dup_value) {
384       GPR_ASSERT(p.payload != q.payload);
385     } else {
386       GPR_ASSERT(p.payload == q.payload);
387     }
388     GRPC_MDELEM_UNREF(p);
389     GRPC_MDELEM_UNREF(q);
390   }
391 
392   grpc_shutdown();
393 }
394 
main(int argc,char ** argv)395 int main(int argc, char** argv) {
396   grpc::testing::TestEnvironment env(argc, argv);
397   grpc_init();
398   test_no_op();
399   for (int k = 0; k <= 1; k++) {
400     for (int v = 0; v <= 1; v++) {
401       test_create_metadata(k, v);
402       test_create_many_ephemeral_metadata(k, v);
403       test_identity_laws(k, v);
404       test_spin_creating_the_same_thing(k, v);
405       test_mdelem_sizes_in_hpack(k, v);
406       test_copied_static_metadata(k, v);
407     }
408   }
409   test_create_many_persistant_metadata();
410   test_things_stick_around();
411   test_user_data_works();
412   test_user_data_works_for_allocated_md();
413   grpc_shutdown();
414   return 0;
415 }
416