Use base64 encoded length for decoder table size
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index 819addd..ef89f1c 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/timeout_encoding.h"
#include "src/core/ext/transport/chttp2/transport/varint.h"
+#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
#define HASH_FRAGMENT_1(x) ((x)&255)
@@ -178,8 +179,7 @@
uint32_t key_hash = elem->key->hash;
uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
- size_t elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
- GPR_SLICE_LENGTH(elem->value->slice);
+ size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem);
GPR_ASSERT(elem_size < 65536);
@@ -395,8 +395,7 @@
}
/* should this elem be in the table? */
- decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
- GPR_SLICE_LENGTH(elem->value->slice);
+ decoder_space_usage = grpc_mdelem_get_size_in_hpack_table(elem);
should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c
index 451c8d1..b1005f3 100644
--- a/src/core/lib/transport/metadata.c
+++ b/src/core/lib/transport/metadata.c
@@ -38,6 +38,7 @@
#include <string.h>
#include <grpc/compression.h>
+#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
@@ -93,6 +94,9 @@
gpr_slice base64_and_huffman;
+ uint8_t has_size_in_decoder_table;
+ size_t size_in_decoder_table;
+
struct internal_string *bucket_next;
} internal_string;
@@ -407,6 +411,8 @@
}
s->has_base64_and_huffman_encoded = 0;
s->hash = hash;
+ s->has_size_in_decoder_table = 0;
+ s->size_in_decoder_table = 0;
s->bucket_next = shard->strs[idx];
shard->strs[idx] = s;
@@ -576,6 +582,29 @@
grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length));
}
+size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem) {
+ size_t overhead_and_key = 32 + GPR_SLICE_LENGTH(elem->key->slice);
+ if (is_mdstr_static(elem->value)) {
+ return overhead_and_key + GPR_SLICE_LENGTH(elem->value->slice);
+ } else {
+ internal_string *is = (internal_string *)elem->value;
+ size_t value_len = GPR_SLICE_LENGTH(is->slice);
+ static const uint8_t tail_xtra[3] = {0, 2, 3};
+ if (is->has_size_in_decoder_table == 0) {
+ is->has_size_in_decoder_table = 1;
+ if (grpc_is_binary_header(
+ (const char *)GPR_SLICE_START_PTR(elem->key->slice),
+ GPR_SLICE_LENGTH(elem->key->slice))) {
+ is->size_in_decoder_table =
+ value_len / 3 * 4 + tail_xtra[value_len % 3];
+ } else {
+ is->size_in_decoder_table = value_len;
+ }
+ }
+ return overhead_and_key + is->size_in_decoder_table;
+ }
+}
+
grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
internal_metadata *md = (internal_metadata *)gmd;
if (is_mdelem_static(gmd)) return gmd;
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index d72ec9a..9705a7f 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -110,6 +110,8 @@
const uint8_t *value,
size_t value_length);
+size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem);
+
/* Mutator and accessor for grpc_mdelem user data. The destructor function
is used as a type tag and is checked during user_data fetch. */
void *grpc_mdelem_get_user_data(grpc_mdelem *md,