aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.cc2
-rw-r--r--src/core/lib/transport/metadata.cc65
-rw-r--r--src/core/lib/transport/metadata.h9
-rw-r--r--src/core/lib/transport/metadata_batch.cc188
-rw-r--r--src/core/lib/transport/metadata_batch.h25
5 files changed, 187 insertions, 102 deletions
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
index 4ce139eb0d..9842131d96 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -37,7 +37,7 @@
#include "src/core/lib/debug/stats.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/metadata_batch.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc
index 793a1fcd53..d10194a2fe 100644
--- a/src/core/lib/transport/metadata.cc
+++ b/src/core/lib/transport/metadata.cc
@@ -69,71 +69,6 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_metadata(false, "metadata");
#define TABLE_IDX(hash, capacity) (((hash) >> (LOG2_SHARD_COUNT)) % (capacity))
#define SHARD_IDX(hash) ((hash) & ((1 << (LOG2_SHARD_COUNT)) - 1))
-static_hpack_table_metadata_info static_hpack_table_metadata[] = {
- {0, 0, 0}, // NOT USED
- {GRPC_MDELEM_AUTHORITY_EMPTY_INDEX, 10 + 32, 3},
- {GRPC_MDELEM_METHOD_GET_INDEX, 10 + 32, 1},
- {GRPC_MDELEM_METHOD_POST_INDEX, 11 + 32, 1},
- {GRPC_MDELEM_PATH_SLASH_INDEX, 6 + 32, 0},
- {GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML_INDEX, 16 + 32, 0},
- {GRPC_MDELEM_SCHEME_HTTP_INDEX, 11 + 32, 4},
- {GRPC_MDELEM_SCHEME_HTTPS_INDEX, 12 + 32, 4},
- {GRPC_MDELEM_STATUS_200_INDEX, 10 + 32, 2},
- {GRPC_MDELEM_STATUS_204_INDEX, 10 + 32, 2},
- {GRPC_MDELEM_STATUS_206_INDEX, 10 + 32, 2},
- {GRPC_MDELEM_STATUS_304_INDEX, 10 + 32, 2},
- {GRPC_MDELEM_STATUS_400_INDEX, 10 + 32, 2},
- {GRPC_MDELEM_STATUS_404_INDEX, 10 + 32, 2},
- {GRPC_MDELEM_STATUS_500_INDEX, 10 + 32, 2},
- {GRPC_MDELEM_ACCEPT_CHARSET_EMPTY_INDEX, 14 + 32, 24}, // Not a callout
- {GRPC_MDELEM_ACCEPT_ENCODING_GZIP_DEFLATE_INDEX, 28 + 32, 16},
- {GRPC_MDELEM_MDELEM_ACCEPT_LANGUAGE_EMPTY_INDEX, 15 + 32, 24}, // Not a callout
- {GRPC_MDELEM_MDELEM_ACCEPT_RANGES_EMPTY_INDEX, 13 + 32, 24}, // Not a callout
- {GRPC_MDELEM_ACCEPT_EMPTY_INDEX, 6 + 32, 24}, // Not a callout
- {GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY_INDEX, 27 + 32, 24}, // Not a callout
- {GRPC_MDELEM_AGE_EMPTY_INDEX, 3 + 32, 24}, // Not a callout
- {GRPC_MDELEM_ALLOW_EMPTY_INDEX, 5 + 32, 24}, // Not a callout
- {GRPC_MDELEM_AUTHORIZATION_EMPTY_INDEX, 13 + 32, 24}, // Not a callout
- {GRPC_MDELEM_CACHE_CONTROL_EMPTY_INDEX, 13 + 32, 24}, // Not a callout
- {GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY_INDEX, 19 + 32, 24}, // Not a callout
- {GRPC_MDELEM_CONTENT_ENCODING_EMPTY_INDEX, 16 + 32, 15},
- {GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY_INDEX, 16 + 32, 24}, // Not a callout
- {GRPC_MDELEM_CONTENT_LENGTH_EMPTY_INDEX, 14 + 32, 24}, // Not a callout
- {GRPC_MDELEM_CONTENT_LOCATION_EMPTY_INDEX, 16 + 32, 24}, // Not a callout
- {GRPC_MDELEM_CONTENT_RANGE_EMPTY_INDEX, 13 + 32, 24}, // Not a callout
- {GRPC_MDELEM_CONTENT_TYPE_EMPTY_INDEX, 12 + 32, 15},
- {GRPC_MDELEM_COOKIE_EMPTY_INDEX, 6 + 32, 24}, // Not a callout
- {GRPC_MDELEM_DATE_EMPTY_INDEX, 4 + 32, 24}, // Not a callout
- {GRPC_MDELEM_ETAG_EMPTY_INDEX, 4 + 32, 24}, // Not a callout
- {GRPC_MDELEM_EXPECT_EMPTY_INDEX, 6 + 32, 24}, // Not a callout
- {GRPC_MDELEM_EXPIRES_EMPTY_INDEX, 7 + 32, 24}, // Not a callout
- {GRPC_MDELEM_FROM_EMPTY_INDEX, 4 + 32, 24}, // Not a callout
- {GRPC_MDELEM_HOST_EMPTY_INDEX, 4 + 32, 20},
- {GRPC_MDELEM_IF_MATCH_EMPTY_INDEX, 8 + 32, 24}, // Not a callout
- {GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY_INDEX, 17 + 32, 24}, // Not a callout
- {GRPC_MDELEM_IF_NONE_MATCH_EMPTY_INDEX, 13 + 32, 24}, // Not a callout
- {GRPC_MDELEM_IF_RANGE_EMPTY_INDEX, 8 + 32, 24}, // Not a callout
- {GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY_INDEX, 19 + 32, 24}, // Not a callout
- {GRPC_MDELEM_LAST_MODIFIED_EMPTY_INDEX, 13 + 32, 24}, // Not a callout
- {GRPC_MDELEM_LINK_EMPTY_INDEX, 4 + 32, 24}, // Not a callout
- {GRPC_MDELEM_LOCATION_EMPTY_INDEX, 8 + 32, 24}, // Not a callout
- {GRPC_MDELEM_MAX_FORWARDS_EMPTY_INDEX, 12 + 32, 24}, // Not a callout
- {GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY_INDEX, 18 + 32, 24}, // Not a callout
- {GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY_INDEX, 19 + 32, 24}, // Not a callout
- {GRPC_MDELEM_RANGE_EMPTY_INDEX, 5 + 32, 24}, // Not a callout
- {GRPC_MDELEM_REFERER_EMPTY_INDEX, 7 + 32, 24}, // Not a callout
- {GRPC_MDELEM_REFRESH_EMPTY_INDEX, 7 + 32, 24}, // Not a callout
- {GRPC_MDELEM_RETRY_AFTER_EMPTY_INDEX, 11 + 32, 24}, // Not a callout
- {GRPC_MDELEM_SERVER_EMPTY_INDEX, 6 + 32, 24}, // Not a callout
- {GRPC_MDELEM_SET_COOKIE_EMPTY_INDEX, 10 + 32, 24}, // Not a callout
- {GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY_INDEX, 25 + 32, 24}, // Not a callout
- {GRPC_MDELEM_TRANSFER_ENCODING_EMPTY_INDEX, 17 + 32, 24}, // Not a callout
- {GRPC_MDELEM_USER_AGENT_EMPTY_INDEX, 10 + 32, 19},
- {GRPC_MDELEM_VARY_EMPTY_INDEX, 4 + 32, 24}, // Not a callout
- {GRPC_MDELEM_VIA_EMPTY_INDEX, 3 + 32, 24}, // Not a callout
- {GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY_INDEX, 16 + 32, 24}, // Not a callout
- };
-
typedef void (*destroy_user_data_func)(void* user_data);
/* Shadow structure for grpc_mdelem_data for interned elements */
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 998d2fc64a..74c6672fd2 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -348,15 +348,6 @@ void grpc_mdctx_global_shutdown();
/* {"www-authenticate", ""} */
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY_INDEX 61
-/* Static hpack table metadata info */
-typedef struct static_hpack_table_metadata_info {
- uint8_t index; // Index in the static hpack table
- uint8_t size; // Size of the metadata per RFC-7540 section 6.5.2., including 32 bytes of padding
- uint8_t callouts_index; // For duplicate metadata detection. If GRPC_BATCH_CALLOUTS_COUNT, then the metadata is not one of the callouts.
-} static_hpack_table_metadata_info;
-
-extern static_hpack_table_metadata_info static_hpack_table_metadata[];
-
/* Forward declarations */
typedef struct grpc_mdelem grpc_mdelem;
#endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_H */
diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc
index 6cad7c9028..604ace5751 100644
--- a/src/core/lib/transport/metadata_batch.cc
+++ b/src/core/lib/transport/metadata_batch.cc
@@ -25,11 +25,103 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
+static_hpack_table_metadata_info static_hpack_table_metadata[] = {
+ {0, 0, GRPC_BATCH_CALLOUTS_COUNT}, // NOT USED
+ {GRPC_MDELEM_AUTHORITY_EMPTY_INDEX, 10 + 32, GRPC_BATCH_AUTHORITY},
+ {GRPC_MDELEM_METHOD_GET_INDEX, 10 + 32, GRPC_BATCH_METHOD},
+ {GRPC_MDELEM_METHOD_POST_INDEX, 11 + 32, GRPC_BATCH_METHOD},
+ {GRPC_MDELEM_PATH_SLASH_INDEX, 6 + 32, GRPC_BATCH_PATH},
+ {GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML_INDEX, 16 + 32, GRPC_BATCH_PATH},
+ {GRPC_MDELEM_SCHEME_HTTP_INDEX, 11 + 32, GRPC_BATCH_SCHEME},
+ {GRPC_MDELEM_SCHEME_HTTPS_INDEX, 12 + 32, GRPC_BATCH_SCHEME},
+ {GRPC_MDELEM_STATUS_200_INDEX, 10 + 32, GRPC_BATCH_STATUS},
+ {GRPC_MDELEM_STATUS_204_INDEX, 10 + 32, GRPC_BATCH_STATUS},
+ {GRPC_MDELEM_STATUS_206_INDEX, 10 + 32, GRPC_BATCH_STATUS},
+ {GRPC_MDELEM_STATUS_304_INDEX, 10 + 32, GRPC_BATCH_STATUS},
+ {GRPC_MDELEM_STATUS_400_INDEX, 10 + 32, GRPC_BATCH_STATUS},
+ {GRPC_MDELEM_STATUS_404_INDEX, 10 + 32, GRPC_BATCH_STATUS},
+ {GRPC_MDELEM_STATUS_500_INDEX, 10 + 32, GRPC_BATCH_STATUS},
+ {GRPC_MDELEM_ACCEPT_CHARSET_EMPTY_INDEX, 14 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_ACCEPT_ENCODING_GZIP_DEFLATE_INDEX, 28 + 32,
+ GRPC_BATCH_ACCEPT_ENCODING},
+ {GRPC_MDELEM_MDELEM_ACCEPT_LANGUAGE_EMPTY_INDEX, 15 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_MDELEM_ACCEPT_RANGES_EMPTY_INDEX, 13 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_ACCEPT_EMPTY_INDEX, 6 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY_INDEX, 27 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_AGE_EMPTY_INDEX, 3 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_ALLOW_EMPTY_INDEX, 5 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_AUTHORIZATION_EMPTY_INDEX, 13 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_CACHE_CONTROL_EMPTY_INDEX, 13 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY_INDEX, 19 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_CONTENT_ENCODING_EMPTY_INDEX, 16 + 32,
+ GRPC_BATCH_CONTENT_ENCODING},
+ {GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY_INDEX, 16 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_CONTENT_LENGTH_EMPTY_INDEX, 14 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_CONTENT_LOCATION_EMPTY_INDEX, 16 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_CONTENT_RANGE_EMPTY_INDEX, 13 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_CONTENT_TYPE_EMPTY_INDEX, 12 + 32, GRPC_BATCH_CONTENT_TYPE},
+ {GRPC_MDELEM_COOKIE_EMPTY_INDEX, 6 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_DATE_EMPTY_INDEX, 4 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_ETAG_EMPTY_INDEX, 4 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_EXPECT_EMPTY_INDEX, 6 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_EXPIRES_EMPTY_INDEX, 7 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_FROM_EMPTY_INDEX, 4 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_HOST_EMPTY_INDEX, 4 + 32, GRPC_BATCH_HOST},
+ {GRPC_MDELEM_IF_MATCH_EMPTY_INDEX, 8 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY_INDEX, 17 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_IF_NONE_MATCH_EMPTY_INDEX, 13 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_IF_RANGE_EMPTY_INDEX, 8 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY_INDEX, 19 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_LAST_MODIFIED_EMPTY_INDEX, 13 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_LINK_EMPTY_INDEX, 4 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_LOCATION_EMPTY_INDEX, 8 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_MAX_FORWARDS_EMPTY_INDEX, 12 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY_INDEX, 18 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY_INDEX, 19 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_RANGE_EMPTY_INDEX, 5 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_REFERER_EMPTY_INDEX, 7 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_REFRESH_EMPTY_INDEX, 7 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_RETRY_AFTER_EMPTY_INDEX, 11 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_SERVER_EMPTY_INDEX, 6 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_COOKIE_EMPTY_INDEX, 10 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY_INDEX, 25 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_TRANSFER_ENCODING_EMPTY_INDEX, 17 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_USER_AGENT_EMPTY_INDEX, 10 + 32, GRPC_BATCH_USER_AGENT},
+ {GRPC_MDELEM_VARY_EMPTY_INDEX, 4 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_VIA_EMPTY_INDEX, 3 + 32, GRPC_BATCH_CALLOUTS_COUNT},
+ {GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY_INDEX, 16 + 32,
+ GRPC_BATCH_CALLOUTS_COUNT},
+};
+
+/* This is a faster check for seeing if a mdelem index is used or not. To verify
+ that the index value is valid, use 'is_valid_mdelem_index' */
+static bool is_mdelem_index_used(uint8_t index);
+
+static void set_mdelem_index_unused(uint8_t* index);
+
+static grpc_metadata_batch_callouts_index get_callouts_index(
+ grpc_linked_mdelem* storage);
+
static void assert_valid_list(grpc_mdelem_list* list) {
#ifndef NDEBUG
grpc_linked_mdelem* l;
@@ -56,13 +148,21 @@ static void assert_valid_list(grpc_mdelem_list* list) {
static void assert_valid_callouts(grpc_metadata_batch* batch) {
#ifndef NDEBUG
for (grpc_linked_mdelem* l = batch->list.head; l != nullptr; l = l->next) {
- grpc_slice key_interned = grpc_slice_intern(GRPC_MDKEY(l->md));
- grpc_metadata_batch_callouts_index callout_idx =
- GRPC_BATCH_INDEX_OF(key_interned);
- if (callout_idx != GRPC_BATCH_CALLOUTS_COUNT) {
- GPR_ASSERT(batch->idx.array[callout_idx] == l);
+ grpc_metadata_batch_callouts_index callout_idx;
+ if (is_mdelem_index_used(l->md_index)) {
+ GPR_ASSERT(is_valid_mdelem_index(l->md_index));
+ callout_idx = get_callouts_index(l->md_index);
+ if (callout_idx != GRPC_BATCH_CALLOUTS_COUNT) {
+ GPR_ASSERT(batch->idx.array[callout_idx] == l);
+ }
+ } else {
+ grpc_slice key_interned = grpc_slice_intern(GRPC_MDKEY(l->md));
+ callout_idx = GRPC_BATCH_INDEX_OF(key_interned);
+ if (callout_idx != GRPC_BATCH_CALLOUTS_COUNT) {
+ GPR_ASSERT(batch->idx.array[callout_idx] == l);
+ }
+ grpc_slice_unref_internal(key_interned);
}
- grpc_slice_unref_internal(key_interned);
}
#endif
}
@@ -81,7 +181,9 @@ void grpc_metadata_batch_init(grpc_metadata_batch* batch) {
void grpc_metadata_batch_destroy(grpc_metadata_batch* batch) {
grpc_linked_mdelem* l;
for (l = batch->list.head; l; l = l->next) {
- GRPC_MDELEM_UNREF(l->md);
+ if (!is_mdelem_index_used(l->md_index)) {
+ GRPC_MDELEM_UNREF(l->md);
+ }
}
}
@@ -93,14 +195,22 @@ grpc_error* grpc_attach_md_to_error(grpc_error* src, grpc_mdelem md) {
return out;
}
+static grpc_metadata_batch_callouts_index get_callouts_index(
+ grpc_linked_mdelem* storage) {
+ if (is_mdelem_index_used(storage->md_index)) {
+ return static_hpack_table_metadata[storage->md_index].callouts_index;
+ } else {
+ return GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
+ }
+}
+
static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage)
GRPC_MUST_USE_RESULT;
static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage) {
- grpc_metadata_batch_callouts_index idx =
- GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
+ grpc_metadata_batch_callouts_index idx = get_callouts_index(storage);
if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
return GRPC_ERROR_NONE;
}
@@ -109,15 +219,27 @@ static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
batch->idx.array[idx] = storage;
return GRPC_ERROR_NONE;
}
- return grpc_attach_md_to_error(
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unallowed duplicate metadata"),
- storage->md);
+
+ grpc_error* err;
+ if (is_mdelem_index_used(storage->md_index)) {
+ char* message;
+ gpr_asprintf(&message,
+ "Unallowed duplicate metadata with static hpack table index "
+ "%d and callouts index %d",
+ storage->md_index, idx);
+ err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(message);
+ gpr_free(message);
+ } else {
+ err = grpc_attach_md_to_error(
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unallowed duplicate metadata"),
+ storage->md);
+ }
+ return err;
}
static void maybe_unlink_callout(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage) {
- grpc_metadata_batch_callouts_index idx =
- GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
+ grpc_metadata_batch_callouts_index idx = get_callouts_index(storage);
if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
return;
}
@@ -126,11 +248,18 @@ static void maybe_unlink_callout(grpc_metadata_batch* batch,
batch->idx.array[idx] = nullptr;
}
-bool is_valid_mdelem_index(int64_t index) {
+bool is_valid_mdelem_index(uint8_t index) {
return index >= MIN_STATIC_HPACK_TABLE_IDX &&
index <= MAX_STATIC_HPACK_TABLE_IDX;
}
+bool is_mdelem_index_used(uint8_t index) { return index != 0; }
+
+void set_mdelem_index_unused(uint8_t* index) {
+ GPR_ASSERT(index != nullptr);
+ *index = 0;
+}
+
grpc_error* grpc_metadata_batch_add_head(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage,
grpc_mdelem elem_to_add) {
@@ -141,7 +270,7 @@ grpc_error* grpc_metadata_batch_add_head(grpc_metadata_batch* batch,
grpc_error* grpc_metadata_batch_add_head_index(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage,
- int64_t index_to_add) {
+ uint8_t index_to_add) {
GPR_ASSERT(is_valid_mdelem_index(index_to_add));
storage->md_index = index_to_add;
return grpc_metadata_batch_link_head(batch, storage);
@@ -186,7 +315,7 @@ grpc_error* grpc_metadata_batch_add_tail(grpc_metadata_batch* batch,
grpc_error* grpc_metadata_batch_add_tail_index(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage,
- int64_t index_to_add) {
+ uint8_t index_to_add) {
GPR_ASSERT(is_valid_mdelem_index(index_to_add));
storage->md_index = index_to_add;
return grpc_metadata_batch_link_tail(batch, storage);
@@ -244,12 +373,15 @@ void grpc_metadata_batch_remove(grpc_metadata_batch* batch,
assert_valid_callouts(batch);
maybe_unlink_callout(batch, storage);
unlink_storage(&batch->list, storage);
- GRPC_MDELEM_UNREF(storage->md);
+ if (!is_mdelem_index_used(storage->md_index)) {
+ GRPC_MDELEM_UNREF(storage->md);
+ }
assert_valid_callouts(batch);
}
void grpc_metadata_batch_set_value(grpc_linked_mdelem* storage,
grpc_slice value) {
+ set_mdelem_index_unused(&storage->md_index);
grpc_mdelem old_mdelem = storage->md;
grpc_mdelem new_mdelem = grpc_mdelem_from_slices(
grpc_slice_ref_internal(GRPC_MDKEY(old_mdelem)), value);
@@ -263,18 +395,26 @@ grpc_error* grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
assert_valid_callouts(batch);
grpc_error* error = GRPC_ERROR_NONE;
grpc_mdelem old_mdelem = storage->md;
- if (!grpc_slice_eq(GRPC_MDKEY(new_mdelem), GRPC_MDKEY(old_mdelem))) {
+ bool is_index_used = is_mdelem_index_used(storage->md_index);
+ if (is_index_used ||
+ !grpc_slice_eq(GRPC_MDKEY(new_mdelem), GRPC_MDKEY(old_mdelem))) {
maybe_unlink_callout(batch, storage);
storage->md = new_mdelem;
+ set_mdelem_index_unused(&storage->md_index);
error = maybe_link_callout(batch, storage);
if (error != GRPC_ERROR_NONE) {
unlink_storage(&batch->list, storage);
- GRPC_MDELEM_UNREF(storage->md);
+ if (!is_index_used) {
+ GRPC_MDELEM_UNREF(storage->md);
+ }
}
} else {
storage->md = new_mdelem;
}
- GRPC_MDELEM_UNREF(old_mdelem);
+
+ if (!is_index_used) {
+ GRPC_MDELEM_UNREF(old_mdelem);
+ }
assert_valid_callouts(batch);
return error;
}
@@ -293,7 +433,11 @@ size_t grpc_metadata_batch_size(grpc_metadata_batch* batch) {
size_t size = 0;
for (grpc_linked_mdelem* elem = batch->list.head; elem != nullptr;
elem = elem->next) {
- size += GRPC_MDELEM_LENGTH(elem->md);
+ if (!is_mdelem_index_used(elem->md_index)) {
+ size += GRPC_MDELEM_LENGTH(elem->md);
+ } else { // Mdelem is represented by static hpack table index
+ size += static_hpack_table_metadata[elem->md_index].size;
+ }
}
return size;
}
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index f1c199489f..25f9d0c14c 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -32,13 +32,13 @@
/** Each grpc_linked_mdelem refers to a particular metadata element by either:
1) grpc_mdelem md
- 2) int64_t md_index
+ 2) uint8_t md_index
md_index is an optional optimization. It can only be used for metadata in
the hpack static table and is equivalent to the metadata's index in the
table. If a metadata elem is not contained in the hpack static table, then
md must be used instead. */
typedef struct grpc_linked_mdelem {
- int64_t md_index; // If -1, not used. Else, use this field instead of md.
+ uint8_t md_index; // If 0, not used. Else, use this field instead of md.
grpc_mdelem md; // If md_index is 0, use this field instead of md_index.
struct grpc_linked_mdelem* next;
struct grpc_linked_mdelem* prev;
@@ -115,7 +115,7 @@ grpc_error* grpc_metadata_batch_add_head(
be a valid static hpack table index */
grpc_error* grpc_metadata_batch_add_head_index(
grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
- int64_t index_to_add) GRPC_MUST_USE_RESULT;
+ uint8_t index_to_add) GRPC_MUST_USE_RESULT;
/** Add \a elem_to_add as the last element in \a batch, using
\a storage as backing storage for the linked list element.
@@ -132,11 +132,26 @@ grpc_error* grpc_metadata_batch_add_tail(
be a valid static hpack table index */
grpc_error* grpc_metadata_batch_add_head_index(
grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
- int64_t index_to_add) GRPC_MUST_USE_RESULT;
+ uint8_t index_to_add) GRPC_MUST_USE_RESULT;
grpc_error* grpc_attach_md_to_error(grpc_error* src, grpc_mdelem md);
-bool is_valid_mdelem_index(int64_t index);
+/** Returns if the index is a valid static hpack table index, and thus if the
+ grpc_linked_mdelem stores the index rather than the actual grpc_mdelem **/
+bool is_valid_mdelem_index(uint8_t index);
+
+/* Static hpack table metadata info */
+typedef struct static_hpack_table_metadata_info {
+ uint8_t index; // Index in the static hpack table
+ uint8_t size; // Size of the metadata per RFC-7540 section 6.5.2., including
+ // 32 bytes of padding
+ grpc_metadata_batch_callouts_index
+ callouts_index; // For duplicate metadata detection. If
+ // GRPC_BATCH_CALLOUTS_COUNT, then the metadata is not
+ // one of the callouts.
+} static_hpack_table_metadata_info;
+
+extern static_hpack_table_metadata_info static_hpack_table_metadata[];
typedef struct {
grpc_error* error;