aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c85
-rw-r--r--test/core/end2end/tests/large_metadata.c35
2 files changed, 70 insertions, 50 deletions
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 6314786525..1eaffc6692 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -854,24 +854,37 @@ static void perform_stream_op_locked(
stream_global->send_initial_metadata_finished =
add_closure_barrier(on_complete);
stream_global->send_initial_metadata = op->send_initial_metadata;
- if (contains_non_ok_status(transport_global, op->send_initial_metadata)) {
- stream_global->seen_error = true;
- grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
- }
- if (!stream_global->write_closed) {
- if (transport_global->is_client) {
- GPR_ASSERT(stream_global->id == 0);
- grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
- stream_global);
- maybe_start_some_streams(exec_ctx, transport_global);
+ const size_t metadata_size = grpc_metadata_batch_size(
+ op->send_initial_metadata);
+ const size_t metadata_peer_limit =
+ transport_global->settings[GRPC_PEER_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
+ if (metadata_size > metadata_peer_limit) {
+ gpr_log(GPR_DEBUG,
+ "initial metadata size exceeds peer limit (%lu vs. %lu)",
+ metadata_size, metadata_peer_limit);
+ cancel_from_api(exec_ctx, transport_global, stream_global,
+ GRPC_STATUS_RESOURCE_EXHAUSTED);
+ } else {
+ if (contains_non_ok_status(transport_global, op->send_initial_metadata)) {
+ stream_global->seen_error = true;
+ grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+ }
+ if (!stream_global->write_closed) {
+ if (transport_global->is_client) {
+ GPR_ASSERT(stream_global->id == 0);
+ grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
+ stream_global);
+ maybe_start_some_streams(exec_ctx, transport_global);
+ } else {
+ GPR_ASSERT(stream_global->id != 0);
+ grpc_chttp2_become_writable(transport_global, stream_global);
+ }
} else {
- GPR_ASSERT(stream_global->id != 0);
- grpc_chttp2_become_writable(transport_global, stream_global);
+ grpc_chttp2_complete_closure_step(
+ exec_ctx, stream_global,
+ &stream_global->send_initial_metadata_finished, 0);
}
- } else {
- grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->send_initial_metadata_finished, 0);
}
}
@@ -895,19 +908,33 @@ static void perform_stream_op_locked(
stream_global->send_trailing_metadata_finished =
add_closure_barrier(on_complete);
stream_global->send_trailing_metadata = op->send_trailing_metadata;
- if (contains_non_ok_status(transport_global, op->send_trailing_metadata)) {
- stream_global->seen_error = true;
- grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
- }
- if (stream_global->write_closed) {
- grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->send_trailing_metadata_finished,
- grpc_metadata_batch_is_empty(op->send_trailing_metadata));
- } else if (stream_global->id != 0) {
- /* TODO(ctiller): check if there's flow control for any outstanding
- bytes before going writable */
- grpc_chttp2_become_writable(transport_global, stream_global);
+ const size_t metadata_size = grpc_metadata_batch_size(
+ op->send_trailing_metadata);
+ const size_t metadata_peer_limit =
+ transport_global->settings[GRPC_PEER_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
+ if (metadata_size > metadata_peer_limit) {
+ gpr_log(GPR_DEBUG,
+ "trailing metadata size exceeds peer limit (%lu vs. %lu)",
+ metadata_size, metadata_peer_limit);
+ cancel_from_api(exec_ctx, transport_global, stream_global,
+ GRPC_STATUS_RESOURCE_EXHAUSTED);
+ } else {
+ if (contains_non_ok_status(transport_global,
+ op->send_trailing_metadata)) {
+ stream_global->seen_error = true;
+ grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+ }
+ if (stream_global->write_closed) {
+ grpc_chttp2_complete_closure_step(
+ exec_ctx, stream_global,
+ &stream_global->send_trailing_metadata_finished,
+ grpc_metadata_batch_is_empty(op->send_trailing_metadata));
+ } else if (stream_global->id != 0) {
+ /* TODO(ctiller): check if there's flow control for any outstanding
+ bytes before going writable */
+ grpc_chttp2_become_writable(transport_global, stream_global);
+ }
}
}
diff --git a/test/core/end2end/tests/large_metadata.c b/test/core/end2end/tests/large_metadata.c
index 2aa6381e9e..b78d5b8292 100644
--- a/test/core/end2end/tests/large_metadata.c
+++ b/test/core/end2end/tests/large_metadata.c
@@ -97,9 +97,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
grpc_completion_queue_destroy(f->cq);
}
-/* Request with a large amount of metadata.*/
-static void test_request_with_large_metadata(grpc_end2end_test_config config,
- int allow_large_metadata) {
+/* Request with a large amount of metadata. */
+static void test_request_with_large_metadata(grpc_end2end_test_config config) {
grpc_call *c;
grpc_call *s;
gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
@@ -107,16 +106,12 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config,
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
gpr_timespec deadline = five_seconds_time();
grpc_metadata meta;
- const char *test_name = allow_large_metadata
- ? "test_request_with_large_metadata_allowed"
- : "test_request_with_large_metadata_not_allowed";
const size_t large_size = 64 * 1024;
grpc_arg arg = { GRPC_ARG_INTEGER, GRPC_ARG_MAX_METADATA_SIZE,
{ .integer=(int)large_size + 1024 } };
grpc_channel_args args = { 1, &arg };
- grpc_channel_args* use_args = allow_large_metadata ? &args : NULL;
grpc_end2end_test_fixture f = begin_test(
- config, test_name, use_args, use_args);
+ config, "test_request_with_large_metadata", &args, &args);
cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_op ops[6];
grpc_op *op;
@@ -146,6 +141,7 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config,
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
+ /* Client: send request. */
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 1;
@@ -182,9 +178,11 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config,
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
+
cq_expect_completion(cqv, tag(101), 1);
cq_verify(cqv);
+ /* Server: send initial metadata and receive request. */
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
@@ -199,9 +197,11 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config,
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
- cq_expect_completion(cqv, tag(102), allow_large_metadata);
+ cq_expect_completion(cqv, tag(102), 1);
cq_verify(cqv);
+ /* Server: receive close and send status. This should trigger
+ completion of request on client. */
op = ops;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
@@ -222,19 +222,13 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config,
cq_expect_completion(cqv, tag(1), 1);
cq_verify(cqv);
- GPR_ASSERT(status == (allow_large_metadata ? GRPC_STATUS_OK
- : GRPC_STATUS_RESOURCE_EXHAUSTED));
+ GPR_ASSERT(status == GRPC_STATUS_OK);
+ GPR_ASSERT(0 == strcmp(details, "xyz"));
GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
GPR_ASSERT(was_cancelled == 0);
- if (allow_large_metadata) {
- GPR_ASSERT(0 == strcmp(details, "xyz"));
- GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world"));
- GPR_ASSERT(contains_metadata(&request_metadata_recv, "key", meta.value));
- } else {
- GPR_ASSERT(request_payload_recv == NULL);
- GPR_ASSERT(!contains_metadata_key(&request_metadata_recv, "key"));
- }
+ GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world"));
+ GPR_ASSERT(contains_metadata(&request_metadata_recv, "key", meta.value));
gpr_free(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -257,8 +251,7 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config,
}
void large_metadata(grpc_end2end_test_config config) {
- test_request_with_large_metadata(config, 1);
- test_request_with_large_metadata(config, 0);
+ test_request_with_large_metadata(config);
}
void large_metadata_pre_init(void) {}