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