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