diff options
Diffstat (limited to 'src/core/ext/transport/chttp2/transport/hpack_encoder.c')
-rw-r--r-- | src/core/ext/transport/chttp2/transport/hpack_encoder.c | 152 |
1 files changed, 99 insertions, 53 deletions
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c index 49a8326f62..63df8e135f 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c +++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c @@ -49,6 +49,7 @@ #include "src/core/ext/transport/chttp2/transport/hpack_table.h" #include "src/core/ext/transport/chttp2/transport/varint.h" #include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/transport/metadata.h" #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/timeout_encoding.h" @@ -64,6 +65,10 @@ /* don't consider adding anything bigger than this to the hpack table */ #define MAX_DECODER_SPACE_USAGE 512 +static grpc_slice_refcount terminal_slice_refcount = {NULL, NULL}; +static const grpc_slice terminal_slice = {&terminal_slice_refcount, + .data.refcounted = {0, 0}}; + extern int grpc_http_trace; typedef struct { @@ -185,9 +190,12 @@ static void evict_entry(grpc_chttp2_hpack_compressor *c) { /* add an element to the decoder table */ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, - grpc_mdelem *elem) { - uint32_t key_hash = elem->key->hash; - uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); + grpc_mdelem elem) { + GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem)); + + uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); + uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); + uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); uint32_t new_index = c->tail_remote_index + c->table_elems + 1; size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); @@ -212,17 +220,18 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, c->table_elems++; /* Store this element into {entries,indices}_elem */ - if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) { + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) { /* already there: update with new index */ c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) { + } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], + elem)) { /* already there (cuckoo): update with new index */ c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) { + } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) { /* not there, but a free element: add */ c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) { + } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) { /* not there (cuckoo), but a free element: add */ c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; @@ -241,24 +250,34 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, /* do exactly the same for the key (so we can find by that again too) */ - if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) { + if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], + GRPC_MDKEY(elem))) { c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) { + } else if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)], + GRPC_MDKEY(elem))) { c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) { - c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); + } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)].refcount == + &terminal_slice_refcount) { + c->entries_keys[HASH_FRAGMENT_2(key_hash)] = + grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) { - c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); + } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)].refcount == + &terminal_slice_refcount) { + c->entries_keys[HASH_FRAGMENT_3(key_hash)] = + grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] < c->indices_keys[HASH_FRAGMENT_3(key_hash)]) { - GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[HASH_FRAGMENT_2(key_hash)]); - c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); + grpc_slice_unref_internal(exec_ctx, + c->entries_keys[HASH_FRAGMENT_2(key_hash)]); + c->entries_keys[HASH_FRAGMENT_2(key_hash)] = + grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; } else { - GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[HASH_FRAGMENT_3(key_hash)]); - c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); + grpc_slice_unref_internal(exec_ctx, + c->entries_keys[HASH_FRAGMENT_3(key_hash)]); + c->entries_keys[HASH_FRAGMENT_3(key_hash)] = + grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } } @@ -270,20 +289,18 @@ static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index, len); } -static grpc_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) { - if (grpc_is_binary_header( - (const char *)GRPC_SLICE_START_PTR(elem->key->slice), - GRPC_SLICE_LENGTH(elem->key->slice))) { +static grpc_slice get_wire_value(grpc_mdelem elem, uint8_t *huffman_prefix) { + if (grpc_is_binary_header(GRPC_MDKEY(elem))) { *huffman_prefix = 0x80; - return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value); + return grpc_chttp2_base64_encode_and_huffman_compress(GRPC_MDVALUE(elem)); } /* TODO(ctiller): opportunistically compress non-binary headers */ *huffman_prefix = 0x00; - return elem->value->slice; + return grpc_slice_ref_internal(GRPC_MDVALUE(elem)); } static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c, - uint32_t key_index, grpc_mdelem *elem, + uint32_t key_index, grpc_mdelem elem, framer_state *st) { uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2); uint8_t huffman_prefix; @@ -296,11 +313,11 @@ static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c, add_tiny_header_data(st, len_pfx), len_pfx); GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, grpc_slice_ref_internal(value_slice)); + add_header_data(st, value_slice); } static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c, - uint32_t key_index, grpc_mdelem *elem, + uint32_t key_index, grpc_mdelem elem, framer_state *st) { uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4); uint8_t huffman_prefix; @@ -313,12 +330,12 @@ static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c, add_tiny_header_data(st, len_pfx), len_pfx); GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, grpc_slice_ref_internal(value_slice)); + add_header_data(st, value_slice); } static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c, - grpc_mdelem *elem, framer_state *st) { - uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key->slice); + grpc_mdelem elem, framer_state *st) { + uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); uint8_t huffman_prefix; grpc_slice value_slice = get_wire_value(elem, &huffman_prefix); uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice); @@ -329,15 +346,15 @@ static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c, *add_tiny_header_data(st, 1) = 0x40; GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, add_tiny_header_data(st, len_key_len), len_key_len); - add_header_data(st, grpc_slice_ref_internal(elem->key->slice)); + add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem))); GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, grpc_slice_ref_internal(value_slice)); + add_header_data(st, value_slice); } static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c, - grpc_mdelem *elem, framer_state *st) { - uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key->slice); + grpc_mdelem elem, framer_state *st) { + uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); uint8_t huffman_prefix; grpc_slice value_slice = get_wire_value(elem, &huffman_prefix); uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice); @@ -348,10 +365,10 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c, *add_tiny_header_data(st, 1) = 0x00; GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, add_tiny_header_data(st, len_key_len), len_key_len); - add_header_data(st, grpc_slice_ref_internal(elem->key->slice)); + add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem))); GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, grpc_slice_ref_internal(value_slice)); + add_header_data(st, value_slice); } static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c, @@ -369,15 +386,9 @@ static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) { /* encode an mdelem */ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, - grpc_mdelem *elem, framer_state *st) { - uint32_t key_hash = elem->key->hash; - uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); - size_t decoder_space_usage; - uint32_t indices_key; - int should_add_elem; - - GPR_ASSERT(GRPC_SLICE_LENGTH(elem->key->slice) > 0); - if (GRPC_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */ + grpc_mdelem elem, framer_state *st) { + GPR_ASSERT(GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)) > 0); + if (GRPC_SLICE_START_PTR(GRPC_MDKEY(elem))[0] != ':') { /* regular header */ st->seen_regular_header = 1; } else { GPR_ASSERT( @@ -385,11 +396,39 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, "Reserved header (colon-prefixed) happening after regular ones."); } + if (grpc_http_trace && !GRPC_MDELEM_IS_INTERNED(elem)) { + char *k = grpc_slice_to_c_string(GRPC_MDKEY(elem)); + char *v = grpc_slice_to_c_string(GRPC_MDVALUE(elem)); + gpr_log( + GPR_DEBUG, + "Encode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d", + k, v, GRPC_MDELEM_IS_INTERNED(elem), GRPC_MDELEM_STORAGE(elem), + grpc_slice_is_interned(GRPC_MDKEY(elem)), + grpc_slice_is_interned(GRPC_MDVALUE(elem))); + gpr_free(k); + gpr_free(v); + } + if (!GRPC_MDELEM_IS_INTERNED(elem)) { + emit_lithdr_noidx_v(c, elem, st); + return; + } + + uint32_t key_hash; + uint32_t value_hash; + uint32_t elem_hash; + size_t decoder_space_usage; + uint32_t indices_key; + int should_add_elem; + + key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); + value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); + elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); + inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems); /* is this elem currently in the decoders table? */ - if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem && + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) && c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) { /* HIT: complete element (first cuckoo hash) */ emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), @@ -397,7 +436,7 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, return; } - if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem && + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) && c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) { /* HIT: complete element (second cuckoo hash) */ emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), @@ -414,7 +453,8 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, /* no hits for the elem... maybe there's a key? */ indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)]; - if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key && + if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], + GRPC_MDKEY(elem)) && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ if (should_add_elem) { @@ -429,7 +469,8 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, } indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)]; - if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key && + if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)], + GRPC_MDKEY(elem)) && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ if (should_add_elem) { @@ -463,11 +504,11 @@ static void deadline_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, gpr_timespec deadline, framer_state *st) { char timeout_str[GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE]; - grpc_mdelem *mdelem; + grpc_mdelem mdelem; grpc_http2_encode_timeout( gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str); - mdelem = grpc_mdelem_from_metadata_strings( - exec_ctx, GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str)); + mdelem = grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_TIMEOUT, + grpc_slice_from_copied_string(timeout_str)); hpack_enc(exec_ctx, c, mdelem, st); GRPC_MDELEM_UNREF(exec_ctx, mdelem); } @@ -484,14 +525,19 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) { gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems); memset(c->table_elem_size, 0, sizeof(*c->table_elem_size) * c->cap_table_elems); + for (size_t i = 0; i < GPR_ARRAY_SIZE(c->entries_keys); i++) { + c->entries_keys[i] = terminal_slice; + } } void grpc_chttp2_hpack_compressor_destroy(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c) { int i; for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) { - if (c->entries_keys[i]) GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[i]); - if (c->entries_elems[i]) GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[i]); + if (c->entries_keys[i].refcount != &terminal_slice_refcount) { + grpc_slice_unref_internal(exec_ctx, c->entries_keys[i]); + } + GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[i]); } gpr_free(c->table_elem_size); } |