aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/grpc/impl/codegen/grpc_types.h10
-rw-r--r--src/core/lib/channel/http_client_filter.c177
-rw-r--r--src/core/lib/channel/http_client_filter.h3
-rw-r--r--src/core/lib/channel/http_server_filter.c79
-rw-r--r--src/core/lib/surface/server.c11
-rw-r--r--src/core/lib/transport/static_metadata.c15
-rw-r--r--src/core/lib/transport/static_metadata.h98
-rw-r--r--src/core/lib/transport/transport.h1
-rw-r--r--test/core/end2end/fuzzers/hpack.dictionary1
-rwxr-xr-xtools/codegen/core/gen_static_metadata.py1
10 files changed, 323 insertions, 73 deletions
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index e5a82883be..b3372d7c31 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -222,10 +222,14 @@ typedef enum grpc_call_error {
#define GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST (0x00000010u)
/** Signal that the call should not return UNAVAILABLE before it has started */
#define GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY (0x00000020u)
+/** Signal that the call is cacheable. GRPC is free to use GET verb */
+#define GRPC_INITIAL_METADATA_CACHEABLE_REQUEST (0x00000040u)
+
/** Mask of all valid flags */
-#define GRPC_INITIAL_METADATA_USED_MASK \
- (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \
- GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY)
+#define GRPC_INITIAL_METADATA_USED_MASK \
+ (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \
+ GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY | \
+ GRPC_INITIAL_METADATA_CACHEABLE_REQUEST)
/** A single metadata element */
typedef struct grpc_metadata {
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 9e67df8a9c..ef68cc86ea 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -43,6 +43,9 @@
#define EXPECTED_CONTENT_TYPE "application/grpc"
#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
+/* default maximum size of payload eligable for GET request */
+static const size_t kMaxPayloadSizeForGet = 2048;
+
typedef struct call_data {
grpc_linked_mdelem method;
grpc_linked_mdelem scheme;
@@ -50,20 +53,39 @@ typedef struct call_data {
grpc_linked_mdelem te_trailers;
grpc_linked_mdelem content_type;
grpc_linked_mdelem user_agent;
+ grpc_linked_mdelem payload_bin;
grpc_metadata_batch *recv_initial_metadata;
+ uint8_t *payload_bytes;
+
+ /* Vars to read data off of send_message */
+ grpc_transport_stream_op send_op;
+ uint32_t send_length;
+ uint32_t send_flags;
+ gpr_slice incoming_slice;
+ grpc_slice_buffer_stream replacement_stream;
+ gpr_slice_buffer slices;
+ /* flag that indicates that all slices of send_messages aren't availble */
+ bool send_message_blocked;
/** Closure to call when finished with the hc_on_recv hook */
grpc_closure *on_done_recv;
+ grpc_closure *on_complete;
+ grpc_closure *post_send;
+
/** Receive closures are chained: we inject this closure as the on_done_recv
up-call on transport_op, and remember to call our on_done_recv member
after handling it. */
grpc_closure hc_on_recv;
+ grpc_closure hc_on_complete;
+ grpc_closure got_slice;
+ grpc_closure send_done;
} call_data;
typedef struct channel_data {
grpc_mdelem *static_scheme;
grpc_mdelem *user_agent;
+ size_t max_payload_size_for_get;
} channel_data;
typedef struct {
@@ -119,6 +141,24 @@ static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, error);
}
+static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_error *error) {
+ grpc_call_element *elem = user_data;
+ call_data *calld = elem->call_data;
+ if (calld->payload_bytes) {
+ gpr_free(calld->payload_bytes);
+ calld->payload_bytes = NULL;
+ }
+ calld->on_complete->cb(exec_ctx, calld->on_complete->cb_arg, error);
+}
+
+static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
+ grpc_call_element *elem = elemp;
+ call_data *calld = elem->call_data;
+ gpr_slice_buffer_reset_and_unref(&calld->slices);
+ calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
+}
+
static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
/* eat the things we'd like to set ourselves */
if (md->key == GRPC_MDSTR_METHOD) return NULL;
@@ -129,22 +169,105 @@ static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
return md;
}
-static void hc_mutate_op(grpc_call_element *elem,
+static void continue_send_message(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem) {
+ call_data *calld = elem->call_data;
+ uint8_t *wrptr = calld->payload_bytes;
+ while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
+ &calld->incoming_slice, ~(size_t)0,
+ &calld->got_slice)) {
+ memcpy(wrptr, GPR_SLICE_START_PTR(calld->incoming_slice),
+ GPR_SLICE_LENGTH(calld->incoming_slice));
+ wrptr += GPR_SLICE_LENGTH(calld->incoming_slice);
+ gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+ if (calld->send_length == calld->slices.length) {
+ calld->send_message_blocked = false;
+ break;
+ }
+ }
+}
+
+static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
+ grpc_call_element *elem = elemp;
+ call_data *calld = elem->call_data;
+ calld->send_message_blocked = false;
+ gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+ if (calld->send_length == calld->slices.length) {
+ /* Pass down the original send_message op that was blocked.*/
+ grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
+ calld->send_flags);
+ calld->send_op.send_message = &calld->replacement_stream.base;
+ calld->post_send = calld->send_op.on_complete;
+ calld->send_op.on_complete = &calld->send_done;
+ grpc_call_next_op(exec_ctx, elem, &calld->send_op);
+ } else {
+ continue_send_message(exec_ctx, elem);
+ }
+}
+
+static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
+
if (op->send_initial_metadata != NULL) {
+ /* Decide which HTTP VERB to use. We use GET if the request is marked
+ cacheable, and the operation contains both initial metadata and send
+ message, and the payload is below the size threshold, and all the data
+ for this request is immediately available. */
+ grpc_mdelem *method = GRPC_MDELEM_METHOD_POST;
+ calld->send_message_blocked = false;
+ if ((op->send_initial_metadata_flags &
+ GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) &&
+ op->send_message != NULL &&
+ op->send_message->length < channeld->max_payload_size_for_get) {
+ method = GRPC_MDELEM_METHOD_GET;
+ calld->send_message_blocked = true;
+ } else if (op->send_initial_metadata_flags &
+ GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
+ method = GRPC_MDELEM_METHOD_PUT;
+ }
+
+ /* Attempt to read the data from send_message and create a header field. */
+ if (method == GRPC_MDELEM_METHOD_GET) {
+ /* allocate memory to hold the entire payload */
+ calld->payload_bytes = gpr_malloc(op->send_message->length);
+ GPR_ASSERT(calld->payload_bytes);
+
+ /* read slices of send_message and copy into payload_bytes */
+ calld->send_op = *op;
+ calld->send_length = op->send_message->length;
+ calld->send_flags = op->send_message->flags;
+ continue_send_message(exec_ctx, elem);
+
+ if (calld->send_message_blocked == false) {
+ /* when all the send_message data is available, then create a MDELEM and
+ append to headers */
+ grpc_mdelem *payload_bin = grpc_mdelem_from_metadata_strings(
+ GRPC_MDSTR_GRPC_PAYLOAD_BIN,
+ grpc_mdstr_from_buffer(calld->payload_bytes,
+ op->send_message->length));
+ grpc_metadata_batch_add_tail(op->send_initial_metadata,
+ &calld->payload_bin, payload_bin);
+ calld->on_complete = op->on_complete;
+ op->on_complete = &calld->hc_on_complete;
+ op->send_message = NULL;
+ } else {
+ /* Not all data is available. Fall back to POST. */
+ gpr_log(GPR_DEBUG,
+ "Request is marked Cacheable but not all data is available.\
+ Falling back to POST");
+ method = GRPC_MDELEM_METHOD_POST;
+ }
+ }
+
grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter,
elem);
/* Send : prefixed headers, which have to be before any application
layer headers. */
- grpc_metadata_batch_add_head(
- op->send_initial_metadata, &calld->method,
- op->send_initial_metadata_flags &
- GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
- ? GRPC_MDELEM_METHOD_PUT
- : GRPC_MDELEM_METHOD_POST);
+ grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
+ method);
grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
channeld->static_scheme);
grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
@@ -169,9 +292,16 @@ static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op) {
GPR_TIMER_BEGIN("hc_start_transport_op", 0);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
- hc_mutate_op(elem, op);
+ hc_mutate_op(exec_ctx, elem, op);
GPR_TIMER_END("hc_start_transport_op", 0);
- grpc_call_next_op(exec_ctx, elem, op);
+ call_data *calld = elem->call_data;
+ if (op->send_message != NULL && calld->send_message_blocked) {
+ /* Don't forward the op. send_message contains slices that aren't ready
+ yet. The call will be forwarded by the op_complete of slice read call.
+ */
+ } else {
+ grpc_call_next_op(exec_ctx, elem, op);
+ }
}
/* Constructor for call_data */
@@ -180,14 +310,23 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element_args *args) {
call_data *calld = elem->call_data;
calld->on_done_recv = NULL;
+ calld->on_complete = NULL;
+ calld->payload_bytes = NULL;
+ gpr_slice_buffer_init(&calld->slices);
grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
+ grpc_closure_init(&calld->hc_on_complete, hc_on_complete, elem);
+ grpc_closure_init(&calld->got_slice, got_slice, elem);
+ grpc_closure_init(&calld->send_done, send_done, elem);
return GRPC_ERROR_NONE;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {}
+ void *ignored) {
+ call_data *calld = elem->call_data;
+ gpr_slice_buffer_destroy(&calld->slices);
+}
static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
unsigned i;
@@ -210,6 +349,22 @@ static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
return GRPC_MDELEM_SCHEME_HTTP;
}
+static size_t max_payload_size_from_args(const grpc_channel_args *args) {
+ if (args != NULL) {
+ for (size_t i = 0; i < args->num_args; ++i) {
+ if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET)) {
+ if (args->args[i].type != GRPC_ARG_INTEGER) {
+ gpr_log(GPR_ERROR, "%s: must be an integer",
+ GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET);
+ } else {
+ return (size_t)args->args[i].value.integer;
+ }
+ }
+ }
+ }
+ return kMaxPayloadSizeForGet;
+}
+
static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args,
const char *transport_name) {
gpr_strvec v;
@@ -268,6 +423,8 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(!args->is_last);
GPR_ASSERT(args->optional_transport != NULL);
chand->static_scheme = scheme_from_args(args->channel_args);
+ chand->max_payload_size_for_get =
+ max_payload_size_from_args(args->channel_args);
chand->user_agent = grpc_mdelem_from_metadata_strings(
GRPC_MDSTR_USER_AGENT,
user_agent_from_args(args->channel_args,
diff --git a/src/core/lib/channel/http_client_filter.h b/src/core/lib/channel/http_client_filter.h
index 47081175ea..9e6e106e9c 100644
--- a/src/core/lib/channel/http_client_filter.h
+++ b/src/core/lib/channel/http_client_filter.h
@@ -41,4 +41,7 @@ extern const grpc_channel_filter grpc_http_client_filter;
/* Channel arg to override the http2 :scheme header */
#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
+/* Channel arg to determine maximum size of payload eligable for GET request */
+#define GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET "grpc.max_payload_size_for_get"
+
#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index 5ce51f9016..0f2bf97824 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -49,17 +49,32 @@ typedef struct call_data {
uint8_t seen_scheme;
uint8_t seen_te_trailers;
uint8_t seen_authority;
+ uint8_t seen_payload_bin;
grpc_linked_mdelem status;
grpc_linked_mdelem content_type;
+ /* flag to ensure payload_bin is delivered only once */
+ uint8_t payload_bin_delivered;
+
grpc_metadata_batch *recv_initial_metadata;
bool *recv_idempotent_request;
+ bool *recv_cacheable_request;
/** Closure to call when finished with the hs_on_recv hook */
grpc_closure *on_done_recv;
+ /** Closure to call when we retrieve read message from the payload-bin header
+ */
+ grpc_closure *recv_message_ready;
+ grpc_closure *on_complete;
+ grpc_byte_stream **pp_recv_message;
+ gpr_slice_buffer read_slice_buffer;
+ grpc_slice_buffer_stream read_stream;
+
/** Receive closures are chained: we inject this closure as the on_done_recv
up-call on transport_op, and remember to call our on_done_recv member
after handling it. */
grpc_closure hs_on_recv;
+ grpc_closure hs_on_complete;
+ grpc_closure hs_recv_message_ready;
} call_data;
typedef struct channel_data { uint8_t unused; } channel_data;
@@ -76,16 +91,20 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
/* Check if it is one of the headers we care about. */
if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
- md == GRPC_MDELEM_METHOD_PUT || md == GRPC_MDELEM_SCHEME_HTTP ||
- md == GRPC_MDELEM_SCHEME_HTTPS ||
+ md == GRPC_MDELEM_METHOD_PUT || md == GRPC_MDELEM_METHOD_GET ||
+ md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS ||
md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
/* swallow it */
if (md == GRPC_MDELEM_METHOD_POST) {
calld->seen_method = 1;
*calld->recv_idempotent_request = false;
+ *calld->recv_cacheable_request = false;
} else if (md == GRPC_MDELEM_METHOD_PUT) {
calld->seen_method = 1;
*calld->recv_idempotent_request = true;
+ } else if (md == GRPC_MDELEM_METHOD_GET) {
+ calld->seen_method = 1;
+ *calld->recv_cacheable_request = true;
} else if (md->key == GRPC_MDSTR_SCHEME) {
calld->seen_scheme = 1;
} else if (md == GRPC_MDELEM_TE_TRAILERS) {
@@ -137,6 +156,16 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
calld->seen_authority = 1;
return authority;
+ } else if (md->key == GRPC_MDSTR_GRPC_PAYLOAD_BIN) {
+ /* Retrieve the payload from the value of the 'grpc-internal-payload-bin'
+ header field */
+ calld->seen_payload_bin = 1;
+ gpr_slice_buffer_init(&calld->read_slice_buffer);
+ gpr_slice_buffer_add(&calld->read_slice_buffer,
+ gpr_slice_ref(md->value->slice));
+ grpc_slice_buffer_stream_init(&calld->read_stream,
+ &calld->read_slice_buffer, 0);
+ return NULL;
} else {
return md;
}
@@ -189,6 +218,36 @@ static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
GRPC_ERROR_UNREF(err);
}
+static void hs_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_error *err) {
+ grpc_call_element *elem = user_data;
+ call_data *calld = elem->call_data;
+ /* Call recv_message_ready if we got the payload via the header field */
+ if (calld->seen_payload_bin && calld->recv_message_ready != NULL) {
+ *calld->pp_recv_message = calld->payload_bin_delivered
+ ? NULL
+ : (grpc_byte_stream *)&calld->read_stream;
+ calld->recv_message_ready->cb(exec_ctx, calld->recv_message_ready->cb_arg,
+ err);
+ calld->recv_message_ready = NULL;
+ calld->payload_bin_delivered = true;
+ }
+ calld->on_complete->cb(exec_ctx, calld->on_complete->cb_arg, err);
+}
+
+static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_error *err) {
+ grpc_call_element *elem = user_data;
+ call_data *calld = elem->call_data;
+ if (calld->seen_payload_bin) {
+ /* do nothing. This is probably a GET request, and payload will be returned
+ in hs_on_complete callback. */
+ } else {
+ calld->recv_message_ready->cb(exec_ctx, calld->recv_message_ready->cb_arg,
+ err);
+ }
+}
+
static void hs_mutate_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
@@ -206,11 +265,25 @@ static void hs_mutate_op(grpc_call_element *elem,
if (op->recv_initial_metadata) {
/* substitute our callback for the higher callback */
GPR_ASSERT(op->recv_idempotent_request != NULL);
+ GPR_ASSERT(op->recv_cacheable_request != NULL);
calld->recv_initial_metadata = op->recv_initial_metadata;
calld->recv_idempotent_request = op->recv_idempotent_request;
+ calld->recv_cacheable_request = op->recv_cacheable_request;
calld->on_done_recv = op->recv_initial_metadata_ready;
op->recv_initial_metadata_ready = &calld->hs_on_recv;
}
+
+ if (op->recv_message) {
+ calld->recv_message_ready = op->recv_message_ready;
+ calld->pp_recv_message = op->recv_message;
+ if (op->recv_message_ready) {
+ op->recv_message_ready = &calld->hs_recv_message_ready;
+ }
+ if (op->on_complete) {
+ calld->on_complete = op->on_complete;
+ op->on_complete = &calld->hs_on_complete;
+ }
+ }
}
static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
@@ -232,6 +305,8 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* initialize members */
memset(calld, 0, sizeof(*calld));
grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
+ grpc_closure_init(&calld->hs_on_complete, hs_on_complete, elem);
+ grpc_closure_init(&calld->hs_recv_message_ready, hs_recv_message_ready, elem);
return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 64afcecc07..55e6d99057 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -149,6 +149,7 @@ struct call_data {
grpc_metadata_batch *recv_initial_metadata;
bool recv_idempotent_request;
+ bool recv_cacheable_request;
grpc_metadata_array initial_metadata;
request_matcher *request_matcher;
@@ -497,9 +498,12 @@ static void publish_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
&rc->data.batch.details->method_capacity, calld->path);
rc->data.batch.details->deadline = calld->deadline;
rc->data.batch.details->flags =
- 0 | (calld->recv_idempotent_request
- ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
- : 0);
+ (calld->recv_idempotent_request
+ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
+ : 0) |
+ (calld->recv_cacheable_request
+ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST
+ : 0);
break;
case REGISTERED_CALL:
*rc->data.registered.deadline = calld->deadline;
@@ -779,6 +783,7 @@ static void server_mutate_op(grpc_call_element *elem,
calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata;
op->recv_idempotent_request = &calld->recv_idempotent_request;
+ op->recv_cacheable_request = &calld->recv_cacheable_request;
}
}
diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c
index 8f3e5b5b40..fce591f346 100644
--- a/src/core/lib/transport/static_metadata.c
+++ b/src/core/lib/transport/static_metadata.c
@@ -51,15 +51,15 @@ uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] =
- {11, 33, 10, 33, 12, 33, 12, 49, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33,
+ {11, 33, 10, 33, 12, 33, 12, 50, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33,
19, 33, 20, 33, 21, 33, 22, 33, 23, 33, 24, 33, 25, 33, 26, 33, 27, 33,
28, 18, 28, 33, 29, 33, 30, 33, 34, 33, 35, 33, 36, 33, 37, 33, 40, 31,
- 40, 32, 40, 48, 40, 53, 40, 54, 40, 55, 40, 56, 42, 31, 42, 48, 42, 53,
- 45, 0, 45, 1, 45, 2, 50, 33, 57, 33, 58, 33, 59, 33, 60, 33, 61, 33,
- 62, 33, 63, 33, 64, 33, 65, 33, 66, 33, 67, 33, 68, 38, 68, 70, 68, 73,
- 69, 81, 69, 82, 71, 33, 72, 33, 74, 33, 75, 33, 76, 33, 77, 33, 78, 39,
- 78, 51, 78, 52, 79, 33, 80, 33, 83, 3, 83, 4, 83, 5, 83, 6, 83, 7,
- 83, 8, 83, 9, 84, 33, 85, 86, 87, 33, 88, 33, 89, 33, 90, 33, 91, 33};
+ 40, 32, 40, 49, 40, 54, 40, 55, 40, 56, 40, 57, 42, 31, 42, 49, 42, 54,
+ 46, 0, 46, 1, 46, 2, 51, 33, 58, 33, 59, 33, 60, 33, 61, 33, 62, 33,
+ 63, 33, 64, 33, 65, 33, 66, 33, 67, 33, 68, 33, 69, 38, 69, 71, 69, 74,
+ 70, 82, 70, 83, 72, 33, 73, 33, 75, 33, 76, 33, 77, 33, 78, 33, 79, 39,
+ 79, 52, 79, 53, 80, 33, 81, 33, 84, 3, 84, 4, 84, 5, 84, 6, 84, 7,
+ 84, 8, 84, 9, 85, 33, 86, 87, 88, 33, 89, 33, 90, 33, 91, 33, 92, 33};
const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
"0",
@@ -107,6 +107,7 @@ const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
"grpc-encoding",
"grpc-internal-encoding-request",
"grpc-message",
+ "grpc-payload-bin",
"grpc-status",
"grpc-timeout",
"grpc-tracing-bin",
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index b51bacac50..54b6f38be1 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -44,7 +44,7 @@
#include "src/core/lib/transport/metadata.h"
-#define GRPC_STATIC_MDSTR_COUNT 92
+#define GRPC_STATIC_MDSTR_COUNT 93
extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
/* "0" */
#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
@@ -136,101 +136,103 @@ extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[43])
/* "grpc-message" */
#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[44])
+/* "grpc-payload-bin" */
+#define GRPC_MDSTR_GRPC_PAYLOAD_BIN (&grpc_static_mdstr_table[45])
/* "grpc-status" */
-#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[45])
+#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46])
/* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[46])
+#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47])
/* "grpc-tracing-bin" */
-#define GRPC_MDSTR_GRPC_TRACING_BIN (&grpc_static_mdstr_table[47])
+#define GRPC_MDSTR_GRPC_TRACING_BIN (&grpc_static_mdstr_table[48])
/* "gzip" */
-#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[48])
+#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[49])
/* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[49])
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[50])
/* "host" */
-#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[50])
+#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[51])
/* "http" */
-#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[51])
+#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[52])
/* "https" */
-#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[52])
+#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[53])
/* "identity" */
-#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[53])
+#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[54])
/* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[54])
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[55])
/* "identity,deflate,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
- (&grpc_static_mdstr_table[55])
+ (&grpc_static_mdstr_table[56])
/* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[56])
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[57])
/* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[57])
+#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[58])
/* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[58])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[59])
/* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[59])
+#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[60])
/* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[60])
+#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[61])
/* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[61])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[62])
/* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[62])
+#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[63])
/* "link" */
-#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[63])
+#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[64])
/* "load-reporting-initial" */
-#define GRPC_MDSTR_LOAD_REPORTING_INITIAL (&grpc_static_mdstr_table[64])
+#define GRPC_MDSTR_LOAD_REPORTING_INITIAL (&grpc_static_mdstr_table[65])
/* "load-reporting-trailing" */
-#define GRPC_MDSTR_LOAD_REPORTING_TRAILING (&grpc_static_mdstr_table[65])
+#define GRPC_MDSTR_LOAD_REPORTING_TRAILING (&grpc_static_mdstr_table[66])
/* "location" */
-#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[66])
+#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[67])
/* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[67])
+#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[68])
/* ":method" */
-#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[68])
+#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[69])
/* ":path" */
-#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[69])
+#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[70])
/* "POST" */
-#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[70])
+#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[71])
/* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[71])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[72])
/* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[72])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[73])
/* "PUT" */
-#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[73])
+#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[74])
/* "range" */
-#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[74])
+#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[75])
/* "referer" */
-#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[75])
+#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[76])
/* "refresh" */
-#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[76])
+#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[77])
/* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[77])
+#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[78])
/* ":scheme" */
-#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[78])
+#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[79])
/* "server" */
-#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[79])
+#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[80])
/* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[80])
+#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[81])
/* "/" */
-#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[81])
+#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[82])
/* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[82])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[83])
/* ":status" */
-#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[83])
+#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[84])
/* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[84])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[85])
/* "te" */
-#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[85])
+#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[86])
/* "trailers" */
-#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[86])
+#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[87])
/* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[87])
+#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[88])
/* "user-agent" */
-#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[88])
+#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[89])
/* "vary" */
-#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[89])
+#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[90])
/* "via" */
-#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[90])
+#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[91])
/* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[91])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[92])
#define GRPC_STATIC_MDELEM_COUNT 81
extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 1705e6e582..26ed6cb839 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -124,6 +124,7 @@ typedef struct grpc_transport_stream_op {
/** Receive initial metadata from the stream, into provided metadata batch. */
grpc_metadata_batch *recv_initial_metadata;
bool *recv_idempotent_request;
+ bool *recv_cacheable_request;
/** Should be enqueued when initial metadata is ready to be processed. */
grpc_closure *recv_initial_metadata_ready;
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index 3157dfca3f..e5a73d523f 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -44,6 +44,7 @@
"\x0Dgrpc-encoding"
"\x1Egrpc-internal-encoding-request"
"\x0Cgrpc-message"
+"\x10grpc-payload-bin"
"\x0Bgrpc-status"
"\x0Cgrpc-timeout"
"\x10grpc-tracing-bin"
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index 859adcbeb1..2a16baa1b9 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -42,6 +42,7 @@ import sys
CONFIG = [
'grpc-timeout',
'grpc-internal-encoding-request',
+ 'grpc-payload-bin',
':path',
'grpc-encoding',
'grpc-accept-encoding',