aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUILD1
-rw-r--r--CMakeLists.txt39
-rw-r--r--Makefile2
-rw-r--r--Package.swift2
-rw-r--r--build_autogenerated.yaml19
-rw-r--r--config.m41
-rw-r--r--config.w321
-rw-r--r--gRPC-C++.podspec2
-rw-r--r--gRPC-Core.podspec3
-rw-r--r--grpc.gemspec2
-rw-r--r--grpc.gyp2
-rw-r--r--package.xml2
-rw-r--r--src/core/BUILD6
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.cc195
-rw-r--r--src/core/ext/transport/chttp2/transport/flow_control.cc31
-rw-r--r--src/core/ext/transport/chttp2/transport/flow_control.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/frame.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.cc112
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.h11
-rw-r--r--src/core/ext/transport/chttp2/transport/http2_settings.cc154
-rw-r--r--src/core/ext/transport/chttp2/transport/http2_settings.h179
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h23
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.cc53
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.cc69
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py1
-rw-r--r--test/core/transport/chttp2/BUILD17
-rw-r--r--test/core/transport/chttp2/http2_settings_test.cc514
-rwxr-xr-xtools/codegen/core/gen_settings_ids.py270
-rw-r--r--tools/doxygen/Doxyfile.c++.internal2
-rw-r--r--tools/doxygen/Doxyfile.core.internal2
-rw-r--r--tools/run_tests/generated/tests.json24
31 files changed, 1062 insertions, 681 deletions
diff --git a/BUILD b/BUILD
index 79fadd1ccd..f3bc81e1da 100644
--- a/BUILD
+++ b/BUILD
@@ -4077,6 +4077,7 @@ grpc_cc_library(
"//src/core:error",
"//src/core:error_utils",
"//src/core:experiments",
+ "//src/core:gpr_manual_constructor",
"//src/core:http2_errors",
"//src/core:http2_settings",
"//src/core:init_internally",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3724caf8f5..aa9de4ca98 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1097,6 +1097,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx hpack_parser_test)
add_dependencies(buildtests_cxx hpack_size_test)
add_dependencies(buildtests_cxx http2_client)
+ add_dependencies(buildtests_cxx http2_settings_test)
add_dependencies(buildtests_cxx http2_stats_test)
add_dependencies(buildtests_cxx http_proxy_mapper_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -1846,6 +1847,7 @@ add_library(grpc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
src/core/ext/transport/chttp2/transport/decode_huff.cc
src/core/ext/transport/chttp2/transport/flow_control.cc
+ src/core/ext/transport/chttp2/transport/frame.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
src/core/ext/transport/chttp2/transport/frame_ping.cc
@@ -2899,6 +2901,7 @@ add_library(grpc_unsecure
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
src/core/ext/transport/chttp2/transport/decode_huff.cc
src/core/ext/transport/chttp2/transport/flow_control.cc
+ src/core/ext/transport/chttp2/transport/frame.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
src/core/ext/transport/chttp2/transport/frame_ping.cc
@@ -12175,6 +12178,7 @@ if(gRPC_BUILD_TESTS)
add_executable(flow_control_test
src/core/ext/transport/chttp2/transport/flow_control.cc
+ src/core/ext/transport/chttp2/transport/frame.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
src/core/ext/upb-gen/google/protobuf/any.upb_minitable.c
src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c
@@ -12199,6 +12203,7 @@ add_executable(flow_control_test
src/core/lib/resource_quota/trace.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
+ src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/transport/bdp_estimator.cc
@@ -12244,6 +12249,7 @@ target_link_libraries(flow_control_test
absl::hash
absl::type_traits
absl::statusor
+ absl::span
gpr
)
@@ -14539,6 +14545,39 @@ target_link_libraries(http2_client
endif()
if(gRPC_BUILD_TESTS)
+add_executable(http2_settings_test
+ test/core/transport/chttp2/http2_settings_test.cc
+)
+target_compile_features(http2_settings_test PUBLIC cxx_std_14)
+target_include_directories(http2_settings_test
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ ${_gRPC_RE2_INCLUDE_DIR}
+ ${_gRPC_SSL_INCLUDE_DIR}
+ ${_gRPC_UPB_GENERATED_DIR}
+ ${_gRPC_UPB_GRPC_GENERATED_DIR}
+ ${_gRPC_UPB_INCLUDE_DIR}
+ ${_gRPC_XXHASH_INCLUDE_DIR}
+ ${_gRPC_ZLIB_INCLUDE_DIR}
+ third_party/googletest/googletest/include
+ third_party/googletest/googletest
+ third_party/googletest/googlemock/include
+ third_party/googletest/googlemock
+ ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(http2_settings_test
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ gtest
+ grpc_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
add_executable(http2_stats_test
test/core/end2end/cq_verifier.cc
test/core/end2end/end2end_test_main.cc
diff --git a/Makefile b/Makefile
index 615d63bb36..809c11b225 100644
--- a/Makefile
+++ b/Makefile
@@ -1051,6 +1051,7 @@ LIBGRPC_SRC = \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
src/core/ext/transport/chttp2/transport/decode_huff.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
+ src/core/ext/transport/chttp2/transport/frame.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
src/core/ext/transport/chttp2/transport/frame_ping.cc \
@@ -1956,6 +1957,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
src/core/ext/transport/chttp2/transport/decode_huff.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
+ src/core/ext/transport/chttp2/transport/frame.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
src/core/ext/transport/chttp2/transport/frame_ping.cc \
diff --git a/Package.swift b/Package.swift
index 4b7c86cfa7..5962c89119 100644
--- a/Package.swift
+++ b/Package.swift
@@ -289,6 +289,8 @@ let package = Package(
"src/core/ext/transport/chttp2/transport/decode_huff.h",
"src/core/ext/transport/chttp2/transport/flow_control.cc",
"src/core/ext/transport/chttp2/transport/flow_control.h",
+ "src/core/ext/transport/chttp2/transport/frame.cc",
+ "src/core/ext/transport/chttp2/transport/frame.h",
"src/core/ext/transport/chttp2/transport/frame_data.cc",
"src/core/ext/transport/chttp2/transport/frame_data.h",
"src/core/ext/transport/chttp2/transport/frame_goaway.cc",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 81b264232e..71e595e0d9 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -299,6 +299,7 @@ libs:
- src/core/ext/transport/chttp2/transport/context_list_entry.h
- src/core/ext/transport/chttp2/transport/decode_huff.h
- src/core/ext/transport/chttp2/transport/flow_control.h
+ - src/core/ext/transport/chttp2/transport/frame.h
- src/core/ext/transport/chttp2/transport/frame_data.h
- src/core/ext/transport/chttp2/transport/frame_goaway.h
- src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -1311,6 +1312,7 @@ libs:
- src/core/ext/transport/chttp2/transport/chttp2_transport.cc
- src/core/ext/transport/chttp2/transport/decode_huff.cc
- src/core/ext/transport/chttp2/transport/flow_control.cc
+ - src/core/ext/transport/chttp2/transport/frame.cc
- src/core/ext/transport/chttp2/transport/frame_data.cc
- src/core/ext/transport/chttp2/transport/frame_goaway.cc
- src/core/ext/transport/chttp2/transport/frame_ping.cc
@@ -2239,6 +2241,7 @@ libs:
- src/core/ext/transport/chttp2/transport/context_list_entry.h
- src/core/ext/transport/chttp2/transport/decode_huff.h
- src/core/ext/transport/chttp2/transport/flow_control.h
+ - src/core/ext/transport/chttp2/transport/frame.h
- src/core/ext/transport/chttp2/transport/frame_data.h
- src/core/ext/transport/chttp2/transport/frame_goaway.h
- src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -2723,6 +2726,7 @@ libs:
- src/core/ext/transport/chttp2/transport/chttp2_transport.cc
- src/core/ext/transport/chttp2/transport/decode_huff.cc
- src/core/ext/transport/chttp2/transport/flow_control.cc
+ - src/core/ext/transport/chttp2/transport/frame.cc
- src/core/ext/transport/chttp2/transport/frame_data.cc
- src/core/ext/transport/chttp2/transport/frame_goaway.cc
- src/core/ext/transport/chttp2/transport/frame_ping.cc
@@ -8978,6 +8982,7 @@ targets:
language: c++
headers:
- src/core/ext/transport/chttp2/transport/flow_control.h
+ - src/core/ext/transport/chttp2/transport/frame.h
- src/core/ext/transport/chttp2/transport/http2_settings.h
- src/core/ext/upb-gen/google/protobuf/any.upb.h
- src/core/ext/upb-gen/google/protobuf/any.upb_minitable.h
@@ -9024,6 +9029,7 @@ targets:
- src/core/lib/resource_quota/trace.h
- src/core/lib/slice/percent_encoding.h
- src/core/lib/slice/slice.h
+ - src/core/lib/slice/slice_buffer.h
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
@@ -9052,6 +9058,7 @@ targets:
- third_party/upb/upb/wire/types.h
src:
- src/core/ext/transport/chttp2/transport/flow_control.cc
+ - src/core/ext/transport/chttp2/transport/frame.cc
- src/core/ext/transport/chttp2/transport/http2_settings.cc
- src/core/ext/upb-gen/google/protobuf/any.upb_minitable.c
- src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c
@@ -9076,6 +9083,7 @@ targets:
- src/core/lib/resource_quota/trace.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
+ - src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/lib/transport/bdp_estimator.cc
@@ -9099,6 +9107,7 @@ targets:
- absl/hash:hash
- absl/meta:type_traits
- absl/status:statusor
+ - absl/types:span
- gpr
uses_polling: false
- name: for_each_test
@@ -10375,6 +10384,16 @@ targets:
deps:
- grpc++_test_config
- grpc++_test_util
+- name: http2_settings_test
+ gtest: true
+ build: test
+ language: c++
+ headers: []
+ src:
+ - test/core/transport/chttp2/http2_settings_test.cc
+ deps:
+ - gtest
+ - grpc_test_util
- name: http2_stats_test
gtest: true
build: test
diff --git a/config.m4 b/config.m4
index 157bc2a173..b69c9c21c9 100644
--- a/config.m4
+++ b/config.m4
@@ -133,6 +133,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
src/core/ext/transport/chttp2/transport/decode_huff.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
+ src/core/ext/transport/chttp2/transport/frame.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
src/core/ext/transport/chttp2/transport/frame_ping.cc \
diff --git a/config.w32 b/config.w32
index d36b3beb2f..27dfbf9ead 100644
--- a/config.w32
+++ b/config.w32
@@ -98,6 +98,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\transport\\chttp2\\transport\\chttp2_transport.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\decode_huff.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\flow_control.cc " +
+ "src\\core\\ext\\transport\\chttp2\\transport\\frame.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_data.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_goaway.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_ping.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 3656484f5b..2d6f37cee5 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -368,6 +368,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/context_list_entry.h',
'src/core/ext/transport/chttp2/transport/decode_huff.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
+ 'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.h',
'src/core/ext/transport/chttp2/transport/frame_goaway.h',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
@@ -1611,6 +1612,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/context_list_entry.h',
'src/core/ext/transport/chttp2/transport/decode_huff.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
+ 'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.h',
'src/core/ext/transport/chttp2/transport/frame_goaway.h',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index ae204f1fb0..b077d471cb 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -392,6 +392,8 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/decode_huff.h',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
'src/core/ext/transport/chttp2/transport/flow_control.h',
+ 'src/core/ext/transport/chttp2/transport/frame.cc',
+ 'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_data.h',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
@@ -2382,6 +2384,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/context_list_entry.h',
'src/core/ext/transport/chttp2/transport/decode_huff.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
+ 'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.h',
'src/core/ext/transport/chttp2/transport/frame_goaway.h',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 8e10a8c324..165f5778df 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -295,6 +295,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/decode_huff.h )
s.files += %w( src/core/ext/transport/chttp2/transport/flow_control.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/flow_control.h )
+ s.files += %w( src/core/ext/transport/chttp2/transport/frame.cc )
+ s.files += %w( src/core/ext/transport/chttp2/transport/frame.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_goaway.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 1b520b0969..790276d1bf 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -364,6 +364,7 @@
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
'src/core/ext/transport/chttp2/transport/decode_huff.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
+ 'src/core/ext/transport/chttp2/transport/frame.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
'src/core/ext/transport/chttp2/transport/frame_ping.cc',
@@ -1209,6 +1210,7 @@
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
'src/core/ext/transport/chttp2/transport/decode_huff.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
+ 'src/core/ext/transport/chttp2/transport/frame.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
'src/core/ext/transport/chttp2/transport/frame_ping.cc',
diff --git a/package.xml b/package.xml
index 7059b0c805..3c9247b661 100644
--- a/package.xml
+++ b/package.xml
@@ -277,6 +277,8 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/decode_huff.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/flow_control.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/flow_control.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_data.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_data.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_goaway.cc" role="src" />
diff --git a/src/core/BUILD b/src/core/BUILD
index 65a64fc5e5..7b233ef207 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -6137,9 +6137,15 @@ grpc_cc_library(
hdrs = [
"ext/transport/chttp2/transport/http2_settings.h",
],
+ external_deps = [
+ "absl/functional:function_ref",
+ "absl/strings",
+ "absl/types:optional",
+ ],
deps = [
"http2_errors",
"useful",
+ "//:chttp2_frame",
"//:gpr_platform",
],
)
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index 7c3c7dcd6e..f917662bf8 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -163,10 +163,6 @@ static void read_action_locked(grpc_core::RefCountedPtr<grpc_chttp2_transport>,
static void continue_read_action_locked(
grpc_core::RefCountedPtr<grpc_chttp2_transport> t);
-// Set a transport level setting, and push it to our peer
-static void queue_setting_update(grpc_chttp2_transport* t,
- grpc_chttp2_setting_id id, uint32_t value);
-
static void close_from_api(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
grpc_error_handle error, bool tarpit);
@@ -550,93 +546,54 @@ static void read_channel_args(grpc_chttp2_transport* t,
t->max_header_list_size_soft_limit = soft_limit;
}
- static const struct {
- absl::string_view channel_arg_name;
- grpc_chttp2_setting_id setting_id;
- int default_value;
- int min;
- int max;
- bool availability[2] /* server, client */;
- } settings_map[] = {{GRPC_ARG_MAX_CONCURRENT_STREAMS,
- GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
- -1,
- 0,
- INT32_MAX,
- {true, false}},
- {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER,
- GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
- -1,
- 0,
- INT32_MAX,
- {true, true}},
- {GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE,
- GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
- -1,
- 0,
- INT32_MAX,
- {true, true}},
- {GRPC_ARG_HTTP2_MAX_FRAME_SIZE,
- GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
- -1,
- 16384,
- 16777215,
- {true, true}},
- {GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY,
- GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA,
- 1,
- 0,
- 1,
- {true, true}},
- {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES,
- GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
- -1,
- 5,
- INT32_MAX,
- {true, true}}};
-
- for (size_t i = 0; i < GPR_ARRAY_SIZE(settings_map); i++) {
- const auto& setting = settings_map[i];
- if (setting.availability[is_client]) {
- const int value = channel_args.GetInt(setting.channel_arg_name)
- .value_or(setting.default_value);
- if (value >= 0) {
- const int clamped_value =
- grpc_core::Clamp(value, setting.min, setting.max);
- queue_setting_update(t, setting.setting_id, clamped_value);
- if (setting.setting_id == GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) {
- t->max_concurrent_streams_policy.SetTarget(clamped_value);
- }
- } else if (setting.setting_id ==
- GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE) {
- // Set value to 1.25 * soft limit if this is larger than
- // `DEFAULT_MAX_HEADER_LIST_SIZE` and
- // `GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE` is not set.
- const int soft_limit = channel_args.GetInt(GRPC_ARG_MAX_METADATA_SIZE)
- .value_or(setting.default_value);
- const int value = (soft_limit >= 0 && soft_limit < (INT_MAX / 1.25))
- ? static_cast<int>(soft_limit * 1.25)
- : soft_limit;
- if (value > DEFAULT_MAX_HEADER_LIST_SIZE) {
- queue_setting_update(
- t, setting.setting_id,
- grpc_core::Clamp(value, setting.min, setting.max));
- }
- }
- } else if (channel_args.Contains(setting.channel_arg_name)) {
- gpr_log(GPR_DEBUG, "%s is not available on %s",
- std::string(setting.channel_arg_name).c_str(),
- is_client ? "clients" : "servers");
+ int value;
+ if (!is_client) {
+ value = channel_args.GetInt(GRPC_ARG_MAX_CONCURRENT_STREAMS).value_or(-1);
+ if (value >= 0) {
+ t->settings.mutable_local().SetMaxConcurrentStreams(value);
+ t->max_concurrent_streams_policy.SetTarget(value);
+ }
+ } else if (channel_args.Contains(GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
+ gpr_log(GPR_DEBUG, "%s is not available on clients",
+ GRPC_ARG_MAX_CONCURRENT_STREAMS);
+ }
+ value =
+ channel_args.GetInt(GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER).value_or(-1);
+ if (value >= 0) {
+ t->settings.mutable_local().SetHeaderTableSize(value);
+ }
+ value = channel_args.GetInt(GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE).value_or(-1);
+ if (value >= 0) {
+ t->settings.mutable_local().SetMaxHeaderListSize(value);
+ } else {
+ // Set value to 1.25 * soft limit if this is larger than
+ // `DEFAULT_MAX_HEADER_LIST_SIZE` and
+ // `GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE` is not set.
+ const int soft_limit =
+ channel_args.GetInt(GRPC_ARG_MAX_METADATA_SIZE).value_or(-1);
+ const int value = (soft_limit >= 0 && soft_limit < (INT_MAX / 1.25))
+ ? static_cast<int>(soft_limit * 1.25)
+ : soft_limit;
+ if (value > DEFAULT_MAX_HEADER_LIST_SIZE) {
+ t->settings.mutable_local().SetMaxHeaderListSize(value);
}
}
+ value = channel_args.GetInt(GRPC_ARG_HTTP2_MAX_FRAME_SIZE).value_or(-1);
+ if (value >= 0) {
+ t->settings.mutable_local().SetMaxFrameSize(value);
+ }
+ value =
+ channel_args.GetInt(GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES).value_or(-1);
+ if (value >= 0) {
+ t->settings.mutable_local().SetInitialWindowSize(value);
+ }
+ value = channel_args.GetInt(GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY).value_or(-1);
+ if (value >= 0) {
+ t->settings.mutable_local().SetAllowTrueBinaryMetadata(value != 0);
+ }
if (t->enable_preferred_rx_crypto_frame_advertisement) {
- const grpc_chttp2_setting_parameters* sp =
- &grpc_chttp2_settings_parameters
- [GRPC_CHTTP2_SETTINGS_GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE];
- queue_setting_update(
- t, GRPC_CHTTP2_SETTINGS_GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE,
- grpc_core::Clamp(INT_MAX, static_cast<int>(sp->min_value),
- static_cast<int>(sp->max_value)));
+ t->settings.mutable_local().SetPreferredReceiveCryptoMessageSize(INT_MAX);
}
t->ping_on_rst_stream_percent = grpc_core::Clamp(
@@ -710,33 +667,22 @@ grpc_chttp2_transport::grpc_chttp2_transport(
grpc_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
}
grpc_slice_buffer_init(&qbuf);
- // copy in initial settings to all setting sets
- size_t i;
- int j;
- for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) {
- for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) {
- settings[j][i] = grpc_chttp2_settings_parameters[i].default_value;
- }
- }
grpc_chttp2_goaway_parser_init(&goaway_parser);
// configure http2 the way we like it
if (is_client) {
- queue_setting_update(this, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
- queue_setting_update(this, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
+ settings.mutable_local().SetEnablePush(false);
+ settings.mutable_local().SetMaxConcurrentStreams(0);
}
- queue_setting_update(this, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
- DEFAULT_MAX_HEADER_LIST_SIZE);
- queue_setting_update(this,
- GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, 1);
+ settings.mutable_local().SetMaxHeaderListSize(DEFAULT_MAX_HEADER_LIST_SIZE);
+ settings.mutable_local().SetAllowTrueBinaryMetadata(true);
read_channel_args(this, channel_args, is_client);
// Initially allow *UP TO* MAX_CONCURRENT_STREAMS incoming before we start
// blanket cancelling them.
num_incoming_streams_before_settings_ack =
- settings[GRPC_LOCAL_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS];
+ settings.local().max_concurrent_streams();
grpc_core::ExecCtx exec_ctx;
combiner->Run(
@@ -1126,9 +1072,7 @@ static void write_action(grpc_chttp2_transport* t) {
// Choose max_frame_size as the prefered rx crypto frame size indicated by the
// peer.
int max_frame_size =
- t->settings
- [GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE];
+ t->settings.peer().preferred_receive_crypto_message_size();
// Note: max frame size is 0 if the remote peer does not support adjusting the
// sending frame size.
if (max_frame_size == 0) {
@@ -1205,23 +1149,6 @@ static void write_action_end_locked(
grpc_chttp2_end_write(t.get(), error);
}
-// Dirties an HTTP2 setting to be sent out next time a writing path occurs.
-// If the change needs to occur immediately, manually initiate a write.
-static void queue_setting_update(grpc_chttp2_transport* t,
- grpc_chttp2_setting_id id, uint32_t value) {
- const grpc_chttp2_setting_parameters* sp =
- &grpc_chttp2_settings_parameters[id];
- uint32_t use_value = grpc_core::Clamp(value, sp->min_value, sp->max_value);
- if (use_value != value) {
- gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
- value, use_value);
- }
- if (use_value != t->settings[GRPC_LOCAL_SETTINGS][id]) {
- t->settings[GRPC_LOCAL_SETTINGS][id] = use_value;
- t->dirtied_local_settings = true;
- }
-}
-
// Cancel out streams that haven't yet started if we have received a GOAWAY
static void cancel_unstarted_streams(grpc_chttp2_transport* t,
grpc_error_handle error, bool tarpit) {
@@ -1320,9 +1247,7 @@ static void maybe_start_some_streams(grpc_chttp2_transport* t) {
// start streams where we have free grpc_chttp2_stream ids and free
// * concurrency
while (t->next_stream_id <= MAX_CLIENT_STREAM_ID &&
- t->stream_map.size() <
- t->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] &&
+ t->stream_map.size() < t->settings.peer().max_concurrent_streams() &&
grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) {
// safe since we can't (legally) be parsing this stream yet
GRPC_CHTTP2_IF_TRACING(gpr_log(
@@ -2707,21 +2632,19 @@ void grpc_chttp2_act_on_flowctl_action(
GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL, []() {});
WithUrgency(t, action.send_initial_window_update(),
GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS, [t, &action]() {
- queue_setting_update(t,
- GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
- action.initial_window_size());
- });
- WithUrgency(t, action.send_max_frame_size_update(),
- GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS, [t, &action]() {
- queue_setting_update(t, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
- action.max_frame_size());
+ t->settings.mutable_local().SetInitialWindowSize(
+ action.initial_window_size());
});
+ WithUrgency(
+ t, action.send_max_frame_size_update(),
+ GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS, [t, &action]() {
+ t->settings.mutable_local().SetMaxFrameSize(action.max_frame_size());
+ });
if (t->enable_preferred_rx_crypto_frame_advertisement) {
WithUrgency(
t, action.preferred_rx_crypto_frame_size_update(),
GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS, [t, &action]() {
- queue_setting_update(
- t, GRPC_CHTTP2_SETTINGS_GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE,
+ t->settings.mutable_local().SetPreferredReceiveCryptoMessageSize(
action.preferred_rx_crypto_frame_size());
});
}
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc
index 20031119b3..a24828e7a1 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.cc
+++ b/src/core/ext/transport/chttp2/transport/flow_control.cc
@@ -230,18 +230,14 @@ TransportFlowControl::TargetInitialWindowSizeBasedOnMemoryPressureAndBdp()
}
void TransportFlowControl::UpdateSetting(
- grpc_chttp2_setting_id id, int64_t* desired_value,
- uint32_t new_desired_value, FlowControlAction* action,
+ absl::string_view name, int64_t* desired_value, uint32_t new_desired_value,
+ FlowControlAction* action,
FlowControlAction& (FlowControlAction::*set)(FlowControlAction::Urgency,
uint32_t)) {
- new_desired_value =
- Clamp(new_desired_value, grpc_chttp2_settings_parameters[id].min_value,
- grpc_chttp2_settings_parameters[id].max_value);
if (new_desired_value != *desired_value) {
if (grpc_flowctl_trace.enabled()) {
gpr_log(GPR_INFO, "[flowctl] UPDATE SETTING %s from %" PRId64 " to %d",
- grpc_chttp2_settings_parameters[id].name, *desired_value,
- new_desired_value);
+ std::string(name).c_str(), *desired_value, new_desired_value);
}
// Reaching zero can only happen for initial window size, and if it occurs
// we really want to wake up writes and ensure all the queued stream
@@ -290,13 +286,15 @@ FlowControlAction TransportFlowControl::PeriodicUpdate() {
}
// Though initial window 'could' drop to 0, we keep the floor at
// kMinInitialWindowSize
- UpdateSetting(GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
- &target_initial_window_size_, target, &action,
- &FlowControlAction::set_send_initial_window_update);
+ UpdateSetting(Http2Settings::initial_window_size_name(),
+ &target_initial_window_size_,
+ std::min(target, Http2Settings::max_initial_window_size()),
+ &action, &FlowControlAction::set_send_initial_window_update);
// we target the max of BDP or bandwidth in microseconds.
- UpdateSetting(GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, &target_frame_size_,
- target, &action,
- &FlowControlAction::set_send_max_frame_size_update);
+ UpdateSetting(Http2Settings::max_frame_size_name(), &target_frame_size_,
+ Clamp(target, Http2Settings::min_max_frame_size(),
+ Http2Settings::max_max_frame_size()),
+ &action, &FlowControlAction::set_send_max_frame_size_update);
if (IsTcpFrameSizeTuningEnabled()) {
// Advertise PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE to peer. By advertising
@@ -306,10 +304,11 @@ FlowControlAction TransportFlowControl::PeriodicUpdate() {
// Clamp(target_frame_size_ * 2, 16384, 0x7fffffff). In the future, this
// maybe updated to a different function of the memory pressure.
UpdateSetting(
- GRPC_CHTTP2_SETTINGS_GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE,
+ Http2Settings::preferred_receive_crypto_message_size_name(),
&target_preferred_rx_crypto_frame_size_,
- Clamp(static_cast<unsigned int>(target_frame_size_ * 2), 16384u,
- 0x7ffffffu),
+ Clamp(static_cast<unsigned int>(target_frame_size_ * 2),
+ Http2Settings::min_preferred_receive_crypto_message_size(),
+ Http2Settings::max_preferred_receive_crypto_message_size()),
&action,
&FlowControlAction::set_preferred_rx_crypto_frame_size_update);
}
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h
index f155ad34e6..82dde68754 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.h
+++ b/src/core/ext/transport/chttp2/transport/flow_control.h
@@ -330,7 +330,7 @@ class TransportFlowControl final {
private:
double TargetInitialWindowSizeBasedOnMemoryPressureAndBdp() const;
- static void UpdateSetting(grpc_chttp2_setting_id id, int64_t* desired_value,
+ static void UpdateSetting(absl::string_view name, int64_t* desired_value,
uint32_t new_desired_value,
FlowControlAction* action,
FlowControlAction& (FlowControlAction::*set)(
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index fd6abe81df..be20ef4a0c 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -102,6 +102,8 @@ struct Http2RstStreamFrame {
// SETTINGS frame
struct Http2SettingsFrame {
struct Setting {
+ Setting(uint16_t id, uint32_t value) : id(id), value(value) {}
+
uint16_t id;
uint32_t value;
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.cc b/src/core/ext/transport/chttp2/transport/frame_settings.cc
index e4bf9d4fdb..c0e24c336e 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.cc
@@ -33,6 +33,7 @@
#include "src/core/ext/transport/chttp2/transport/flow_control.h"
#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
+#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
#include "src/core/ext/transport/chttp2/transport/http_trace.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/ext/transport/chttp2/transport/legacy_frame.h"
@@ -55,38 +56,6 @@ static uint8_t* fill_header(uint8_t* out, uint32_t length, uint8_t flags) {
return out;
}
-grpc_slice grpc_chttp2_settings_create(uint32_t* old_settings,
- const uint32_t* new_settings,
- uint32_t force_mask, size_t count) {
- size_t i;
- uint32_t n = 0;
- grpc_slice output;
- uint8_t* p;
-
- for (i = 0; i < count; i++) {
- n += (new_settings[i] != old_settings[i] || (force_mask & (1u << i)) != 0);
- }
-
- output = GRPC_SLICE_MALLOC(9 + 6 * n);
- p = fill_header(GRPC_SLICE_START_PTR(output), 6 * n, 0);
-
- for (i = 0; i < count; i++) {
- if (new_settings[i] != old_settings[i] || (force_mask & (1u << i)) != 0) {
- *p++ = static_cast<uint8_t>(grpc_setting_id_to_wire_id[i] >> 8);
- *p++ = static_cast<uint8_t>(grpc_setting_id_to_wire_id[i]);
- *p++ = static_cast<uint8_t>(new_settings[i] >> 24);
- *p++ = static_cast<uint8_t>(new_settings[i] >> 16);
- *p++ = static_cast<uint8_t>(new_settings[i] >> 8);
- *p++ = static_cast<uint8_t>(new_settings[i]);
- old_settings[i] = new_settings[i];
- }
- }
-
- GPR_ASSERT(p == GRPC_SLICE_END_PTR(output));
-
- return output;
-}
-
grpc_slice grpc_chttp2_settings_ack_create(void) {
grpc_slice output = GRPC_SLICE_MALLOC(9);
fill_header(GRPC_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
@@ -95,10 +64,9 @@ grpc_slice grpc_chttp2_settings_ack_create(void) {
grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
- uint32_t* settings) {
- parser->target_settings = settings;
- memcpy(parser->incoming_settings, settings,
- GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
+ grpc_core::Http2Settings& settings) {
+ parser->target_settings = &settings;
+ parser->incoming_settings.Init(settings);
parser->is_ack = 0;
parser->state = GRPC_CHTTP2_SPS_ID0;
if (flags == GRPC_CHTTP2_FLAG_ACK) {
@@ -125,7 +93,6 @@ grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
static_cast<grpc_chttp2_settings_parser*>(p);
const uint8_t* cur = GRPC_SLICE_START_PTR(slice);
const uint8_t* end = GRPC_SLICE_END_PTR(slice);
- grpc_chttp2_setting_id id;
if (parser->is_ack) {
return absl::OkStatus();
@@ -137,8 +104,7 @@ grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_ID0;
if (is_last) {
- memcpy(parser->target_settings, parser->incoming_settings,
- GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
+ *parser->target_settings = *parser->incoming_settings;
t->num_pending_induced_frames++;
grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
grpc_chttp2_initiate_write(t,
@@ -187,7 +153,7 @@ grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
parser->value |= (static_cast<uint32_t>(*cur)) << 8;
cur++;
ABSL_FALLTHROUGH_INTENDED;
- case GRPC_CHTTP2_SPS_VAL3:
+ case GRPC_CHTTP2_SPS_VAL3: {
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL3;
return absl::OkStatus();
@@ -197,47 +163,35 @@ grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
parser->value |= *cur;
cur++;
- if (grpc_wire_id_to_setting_id(parser->id, &id)) {
- const grpc_chttp2_setting_parameters* sp =
- &grpc_chttp2_settings_parameters[id];
- if (parser->value < sp->min_value || parser->value > sp->max_value) {
- switch (sp->invalid_value_behavior) {
- case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
- parser->value = grpc_core::Clamp(parser->value, sp->min_value,
- sp->max_value);
- break;
- case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
- grpc_chttp2_goaway_append(
- t->last_new_stream_id, sp->error_value,
- grpc_slice_from_static_string("HTTP2 settings error"),
- &t->qbuf);
- return GRPC_ERROR_CREATE(absl::StrFormat(
- "invalid value %u passed for %s", parser->value, sp->name));
- }
- }
- if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
- parser->incoming_settings[id] != parser->value) {
- t->initial_window_update += static_cast<int64_t>(parser->value) -
- parser->incoming_settings[id];
- if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) ||
- GRPC_TRACE_FLAG_ENABLED(grpc_flowctl_trace)) {
- gpr_log(GPR_INFO, "%p[%s] adding %d for initial_window change", t,
- t->is_client ? "cli" : "svr",
- static_cast<int>(t->initial_window_update));
- }
- }
- parser->incoming_settings[id] = parser->value;
- if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
- gpr_log(GPR_INFO, "CHTTP2:%s:%s: got setting %s = %d",
- t->is_client ? "CLI" : "SVR",
- std::string(t->peer_string.as_string_view()).c_str(),
- sp->name, parser->value);
+ if (parser->id == grpc_core::Http2Settings::kInitialWindowSizeWireId) {
+ t->initial_window_update +=
+ static_cast<int64_t>(parser->value) -
+ parser->incoming_settings->initial_window_size();
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) ||
+ GRPC_TRACE_FLAG_ENABLED(grpc_flowctl_trace)) {
+ gpr_log(GPR_INFO, "%p[%s] adding %d for initial_window change", t,
+ t->is_client ? "cli" : "svr",
+ static_cast<int>(t->initial_window_update));
}
- } else if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
- gpr_log(GPR_DEBUG, "CHTTP2: Ignoring unknown setting %d (value %d)",
- parser->id, parser->value);
}
- break;
+ auto error =
+ parser->incoming_settings->Apply(parser->id, parser->value);
+ if (error != GRPC_HTTP2_NO_ERROR) {
+ grpc_chttp2_goaway_append(
+ t->last_new_stream_id, error,
+ grpc_slice_from_static_string("HTTP2 settings error"), &t->qbuf);
+ return GRPC_ERROR_CREATE(absl::StrFormat(
+ "invalid value %u passed for %s", parser->value,
+ grpc_core::Http2Settings::WireIdToName(parser->id).c_str()));
+ }
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
+ gpr_log(GPR_INFO, "CHTTP2:%s:%s: got setting %s = %d",
+ t->is_client ? "CLI" : "SVR",
+ std::string(t->peer_string.as_string_view()).c_str(),
+ grpc_core::Http2Settings::WireIdToName(parser->id).c_str(),
+ parser->value);
+ }
+ } break;
}
}
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
index 24a97c905d..56dc5baae6 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -28,6 +28,7 @@
#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
#include "src/core/ext/transport/chttp2/transport/legacy_frame.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/iomgr/error.h"
typedef enum {
@@ -41,22 +42,18 @@ typedef enum {
struct grpc_chttp2_settings_parser {
grpc_chttp2_settings_parse_state state;
- uint32_t* target_settings;
+ grpc_core::Http2Settings* target_settings;
+ grpc_core::ManualConstructor<grpc_core::Http2Settings> incoming_settings;
uint8_t is_ack;
uint16_t id;
uint32_t value;
- uint32_t incoming_settings[GRPC_CHTTP2_NUM_SETTINGS];
};
-// Create a settings frame by diffing old & new, and updating old to be new
-grpc_slice grpc_chttp2_settings_create(uint32_t* old_settings,
- const uint32_t* new_settings,
- uint32_t force_mask, size_t count);
// Create an ack settings frame
grpc_slice grpc_chttp2_settings_ack_create(void);
grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
- uint32_t* settings);
+ grpc_core::Http2Settings& settings);
grpc_error_handle grpc_chttp2_settings_parser_parse(void* parser,
grpc_chttp2_transport* t,
grpc_chttp2_stream* s,
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.cc b/src/core/ext/transport/chttp2/transport/http2_settings.cc
index d966a7aebe..d9e4341250 100644
--- a/src/core/ext/transport/chttp2/transport/http2_settings.cc
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -22,43 +22,133 @@
#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
+#include "absl/strings/str_cat.h"
+
+#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/transport/http2_errors.h"
-const uint16_t grpc_setting_id_to_wire_id[] = {1, 2, 3, 4, 5, 6, 65027, 65028};
+namespace grpc_core {
+
+void Http2Settings::Diff(
+ bool is_first_send, const Http2Settings& old,
+ absl::FunctionRef<void(uint16_t key, uint32_t value)> cb) const {
+ if (header_table_size_ != old.header_table_size_) {
+ cb(kHeaderTableSizeWireId, header_table_size_);
+ }
+ if (enable_push_ != old.enable_push_) {
+ cb(kEnablePushWireId, enable_push_);
+ }
+ if (max_concurrent_streams_ != old.max_concurrent_streams_) {
+ cb(kMaxConcurrentStreamsWireId, max_concurrent_streams_);
+ }
+ if (is_first_send || initial_window_size_ != old.initial_window_size_) {
+ cb(kInitialWindowSizeWireId, initial_window_size_);
+ }
+ if (max_frame_size_ != old.max_frame_size_) {
+ cb(kMaxFrameSizeWireId, max_frame_size_);
+ }
+ if (max_header_list_size_ != old.max_header_list_size_) {
+ cb(kMaxHeaderListSizeWireId, max_header_list_size_);
+ }
+ if (allow_true_binary_metadata_ != old.allow_true_binary_metadata_) {
+ cb(kGrpcAllowTrueBinaryMetadataWireId, allow_true_binary_metadata_);
+ }
+ if (preferred_receive_crypto_message_size_ !=
+ old.preferred_receive_crypto_message_size_) {
+ cb(kGrpcPreferredReceiveCryptoFrameSizeWireId,
+ preferred_receive_crypto_message_size_);
+ }
+}
+
+std::string Http2Settings::WireIdToName(uint16_t wire_id) {
+ switch (wire_id) {
+ case kHeaderTableSizeWireId:
+ return std::string(header_table_size_name());
+ case kEnablePushWireId:
+ return std::string(enable_push_name());
+ case kMaxConcurrentStreamsWireId:
+ return std::string(max_concurrent_streams_name());
+ case kInitialWindowSizeWireId:
+ return std::string(initial_window_size_name());
+ case kMaxFrameSizeWireId:
+ return std::string(max_frame_size_name());
+ case kMaxHeaderListSizeWireId:
+ return std::string(max_header_list_size_name());
+ case kGrpcAllowTrueBinaryMetadataWireId:
+ return std::string(allow_true_binary_metadata_name());
+ case kGrpcPreferredReceiveCryptoFrameSizeWireId:
+ return std::string(preferred_receive_crypto_message_size_name());
+ default:
+ return absl::StrCat("UNKNOWN (", wire_id, ")");
+ }
+}
+
+grpc_http2_error_code Http2Settings::Apply(uint16_t key, uint32_t value) {
+ switch (key) {
+ case kHeaderTableSizeWireId:
+ header_table_size_ = value;
+ break;
+ case kEnablePushWireId:
+ if (value > 1) return GRPC_HTTP2_PROTOCOL_ERROR;
+ enable_push_ = value != 0;
+ break;
+ case kMaxConcurrentStreamsWireId:
+ max_concurrent_streams_ = value;
+ break;
+ case kInitialWindowSizeWireId:
+ if (value > max_initial_window_size()) {
+ return GRPC_HTTP2_FLOW_CONTROL_ERROR;
+ }
+ initial_window_size_ = value;
+ break;
+ case kMaxFrameSizeWireId:
+ if (value < min_max_frame_size() || value > max_max_frame_size()) {
+ return GRPC_HTTP2_PROTOCOL_ERROR;
+ }
+ max_frame_size_ = value;
+ break;
+ case kMaxHeaderListSizeWireId:
+ max_header_list_size_ = std::min(value, 16777216u);
+ break;
+ case kGrpcAllowTrueBinaryMetadataWireId:
+ if (value > 1) return GRPC_HTTP2_PROTOCOL_ERROR;
+ allow_true_binary_metadata_ = value != 0;
+ break;
+ case kGrpcPreferredReceiveCryptoFrameSizeWireId:
+ preferred_receive_crypto_message_size_ =
+ Clamp(value, min_preferred_receive_crypto_message_size(),
+ max_preferred_receive_crypto_message_size());
+ break;
+ }
+ return GRPC_HTTP2_NO_ERROR;
+}
-bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id* out) {
- uint32_t i = wire_id - 1;
- uint32_t x = i % 256;
- uint32_t y = i / 256;
- uint32_t h = x;
- switch (y) {
- case 254:
- h += 4;
+absl::optional<Http2SettingsFrame> Http2SettingsManager::MaybeSendUpdate() {
+ switch (update_state_) {
+ case UpdateState::kSending:
+ return absl::nullopt;
+ case UpdateState::kIdle:
+ if (local_ == sent_) return absl::nullopt;
+ break;
+ case UpdateState::kFirst:
break;
}
- *out = static_cast<grpc_chttp2_setting_id>(h);
- return h < GPR_ARRAY_SIZE(grpc_setting_id_to_wire_id) &&
- grpc_setting_id_to_wire_id[h] == wire_id;
+ Http2SettingsFrame frame;
+ local_.Diff(update_state_ == UpdateState::kFirst, sent_,
+ [&frame](uint16_t key, uint32_t value) {
+ frame.settings.emplace_back(key, value);
+ });
+ sent_ = local_;
+ update_state_ = UpdateState::kSending;
+ return frame;
+}
+
+bool Http2SettingsManager::AckLastSend() {
+ if (update_state_ != UpdateState::kSending) return false;
+ update_state_ = UpdateState::kIdle;
+ acked_ = sent_;
+ return true;
}
-const grpc_chttp2_setting_parameters
- grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
- {"HEADER_TABLE_SIZE", 4096u, 0u, 4294967295u,
- GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
- {"ENABLE_PUSH", 1u, 0u, 1u, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
- GRPC_HTTP2_PROTOCOL_ERROR},
- {"MAX_CONCURRENT_STREAMS", 4294967295u, 0u, 4294967295u,
- GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
- {"INITIAL_WINDOW_SIZE", 65535u, 0u, 2147483647u,
- GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
- GRPC_HTTP2_FLOW_CONTROL_ERROR},
- {"MAX_FRAME_SIZE", 16384u, 16384u, 16777215u,
- GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
- {"MAX_HEADER_LIST_SIZE", 16777216u, 0u, 16777216u,
- GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
- {"GRPC_ALLOW_TRUE_BINARY_METADATA", 0u, 0u, 1u,
- GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
- {"GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE", 0u, 16384u, 2147483647u,
- GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
-};
+} // namespace grpc_core
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.h b/src/core/ext/transport/chttp2/transport/http2_settings.h
index 314a5c0414..8578d91340 100644
--- a/src/core/ext/transport/chttp2/transport/http2_settings.h
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.h
@@ -14,10 +14,6 @@
// limitations under the License.
//
-//
-// Automatically generated by tools/codegen/core/gen_settings_ids.py
-//
-
#ifndef GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H
@@ -25,38 +21,147 @@
#include <stdint.h>
-typedef enum {
- GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 0, // wire id 1
- GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 1, // wire id 2
- GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 2, // wire id 3
- GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 3, // wire id 4
- GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 4, // wire id 5
- GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 5, // wire id 6
- GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA = 6, // wire id 65027
- GRPC_CHTTP2_SETTINGS_GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE =
- 7, // wire id 65028
-} grpc_chttp2_setting_id;
-
-#define GRPC_CHTTP2_NUM_SETTINGS 8
-extern const uint16_t grpc_setting_id_to_wire_id[];
-
-bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id* out);
-
-typedef enum {
- GRPC_CHTTP2_CLAMP_INVALID_VALUE,
- GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE
-} grpc_chttp2_invalid_value_behavior;
-
-typedef struct {
- const char* name;
- uint32_t default_value;
- uint32_t min_value;
- uint32_t max_value;
- grpc_chttp2_invalid_value_behavior invalid_value_behavior;
- uint32_t error_value;
-} grpc_chttp2_setting_parameters;
-
-extern const grpc_chttp2_setting_parameters
- grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
+#include <cstdint>
+
+#include "absl/functional/function_ref.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/transport/http2_errors.h"
+
+namespace grpc_core {
+
+class Http2Settings {
+ public:
+ enum : uint16_t {
+ kHeaderTableSizeWireId = 1,
+ kEnablePushWireId = 2,
+ kMaxConcurrentStreamsWireId = 3,
+ kInitialWindowSizeWireId = 4,
+ kMaxFrameSizeWireId = 5,
+ kMaxHeaderListSizeWireId = 6,
+ kGrpcAllowTrueBinaryMetadataWireId = 65027,
+ kGrpcPreferredReceiveCryptoFrameSizeWireId = 65028,
+ };
+
+ void Diff(bool is_first_send, const Http2Settings& old,
+ absl::FunctionRef<void(uint16_t key, uint32_t value)> cb) const;
+ GRPC_MUST_USE_RESULT grpc_http2_error_code Apply(uint16_t key,
+ uint32_t value);
+ uint32_t header_table_size() const { return header_table_size_; }
+ uint32_t max_concurrent_streams() const { return max_concurrent_streams_; }
+ uint32_t initial_window_size() const { return initial_window_size_; }
+ uint32_t max_frame_size() const { return max_frame_size_; }
+ uint32_t max_header_list_size() const { return max_header_list_size_; }
+ uint32_t preferred_receive_crypto_message_size() const {
+ return preferred_receive_crypto_message_size_;
+ }
+ bool enable_push() const { return enable_push_; }
+ bool allow_true_binary_metadata() const {
+ return allow_true_binary_metadata_;
+ }
+
+ void SetHeaderTableSize(uint32_t x) { header_table_size_ = x; }
+ void SetMaxConcurrentStreams(uint32_t x) { max_concurrent_streams_ = x; }
+ void SetInitialWindowSize(uint32_t x) {
+ initial_window_size_ = std::min(x, max_initial_window_size());
+ }
+ void SetEnablePush(bool x) { enable_push_ = x; }
+ void SetMaxHeaderListSize(uint32_t x) {
+ max_header_list_size_ = std::min(x, 16777216u);
+ }
+ void SetAllowTrueBinaryMetadata(bool x) { allow_true_binary_metadata_ = x; }
+ void SetMaxFrameSize(uint32_t x) {
+ max_frame_size_ = Clamp(x, min_max_frame_size(), max_max_frame_size());
+ }
+ void SetPreferredReceiveCryptoMessageSize(uint32_t x) {
+ preferred_receive_crypto_message_size_ =
+ Clamp(x, min_preferred_receive_crypto_message_size(),
+ max_preferred_receive_crypto_message_size());
+ }
+
+ static absl::string_view header_table_size_name() {
+ return "HEADER_TABLE_SIZE";
+ }
+ static absl::string_view max_concurrent_streams_name() {
+ return "MAX_CONCURRENT_STREAMS";
+ }
+ static absl::string_view initial_window_size_name() {
+ return "INITIAL_WINDOW_SIZE";
+ }
+ static absl::string_view max_frame_size_name() { return "MAX_FRAME_SIZE"; }
+ static absl::string_view max_header_list_size_name() {
+ return "MAX_HEADER_LIST_SIZE";
+ }
+ static absl::string_view enable_push_name() { return "ENABLE_PUSH"; }
+ static absl::string_view allow_true_binary_metadata_name() {
+ return "GRPC_ALLOW_TRUE_BINARY_METADATA";
+ }
+ static absl::string_view preferred_receive_crypto_message_size_name() {
+ return "GRPC_PREFERRED_RECEIVE_MESSAGE_SIZE";
+ }
+
+ static uint32_t max_initial_window_size() { return 2147483647u; }
+ static uint32_t max_max_frame_size() { return 16777215u; }
+ static uint32_t min_max_frame_size() { return 16384u; }
+ static uint32_t min_preferred_receive_crypto_message_size() { return 16384u; }
+ static uint32_t max_preferred_receive_crypto_message_size() {
+ return 2147483647u;
+ }
+
+ static std::string WireIdToName(uint16_t wire_id);
+
+ bool operator==(const Http2Settings& rhs) const {
+ return header_table_size_ == rhs.header_table_size_ &&
+ max_concurrent_streams_ == rhs.max_concurrent_streams_ &&
+ initial_window_size_ == rhs.initial_window_size_ &&
+ max_frame_size_ == rhs.max_frame_size_ &&
+ max_header_list_size_ == rhs.max_header_list_size_ &&
+ preferred_receive_crypto_message_size_ ==
+ rhs.preferred_receive_crypto_message_size_ &&
+ enable_push_ == rhs.enable_push_ &&
+ allow_true_binary_metadata_ == rhs.allow_true_binary_metadata_;
+ }
+
+ bool operator!=(const Http2Settings& rhs) const { return !operator==(rhs); }
+
+ private:
+ uint32_t header_table_size_ = 4096;
+ uint32_t max_concurrent_streams_ = 4294967295u;
+ uint32_t initial_window_size_ = 65535u;
+ uint32_t max_frame_size_ = 16384u;
+ uint32_t max_header_list_size_ = 16777216u;
+ uint32_t preferred_receive_crypto_message_size_ = 0u;
+ bool enable_push_ = true;
+ bool allow_true_binary_metadata_ = false;
+};
+
+class Http2SettingsManager {
+ public:
+ Http2Settings& mutable_local() { return local_; }
+ const Http2Settings& local() const { return local_; }
+ const Http2Settings& acked() const { return acked_; }
+ Http2Settings& mutable_peer() { return peer_; }
+ const Http2Settings& peer() const { return peer_; }
+
+ absl::optional<Http2SettingsFrame> MaybeSendUpdate();
+ GRPC_MUST_USE_RESULT bool AckLastSend();
+
+ private:
+ enum class UpdateState : uint8_t {
+ kFirst,
+ kSending,
+ kIdle,
+ };
+ UpdateState update_state_ = UpdateState::kFirst;
+ Http2Settings local_;
+ Http2Settings sent_;
+ Http2Settings peer_;
+ Http2Settings acked_;
+};
+
+} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 7e105e8f69..d41d6356f2 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -203,18 +203,6 @@ struct grpc_chttp2_stream_link {
grpc_chttp2_stream* next;
grpc_chttp2_stream* prev;
};
-// We keep several sets of connection wide parameters
-typedef enum {
- // The settings our peer has asked for (and we have acked)
- GRPC_PEER_SETTINGS = 0,
- // The settings we'd like to have
- GRPC_LOCAL_SETTINGS,
- // The settings we've published to our peer
- GRPC_SENT_SETTINGS,
- // The settings the peer has acked
- GRPC_ACKED_SETTINGS,
- GRPC_NUM_SETTING_SETS
-} grpc_chttp2_setting_set;
typedef enum {
GRPC_CHTTP2_NO_GOAWAY_SEND,
@@ -359,12 +347,8 @@ struct grpc_chttp2_transport final
grpc_chttp2_sent_goaway_state sent_goaway_state = GRPC_CHTTP2_NO_GOAWAY_SEND;
- /// bitmask of setting indexes to send out
- /// Hack: it's common for implementations to assume 65536 bytes initial send
- /// window -- this should by rights be 0
- uint32_t force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
/// settings values
- uint32_t settings[GRPC_NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS];
+ grpc_core::Http2SettingsManager settings;
grpc_event_engine::experimental::EventEngine::TaskHandle
settings_ack_watchdog =
@@ -538,11 +522,6 @@ struct grpc_chttp2_transport final
/// is this a client?
bool is_client;
- /// are the local settings dirty and need to be sent?
- bool dirtied_local_settings = true;
- /// have local settings been sent?
- bool sent_local_settings = false;
-
/// If start_bdp_ping_locked has been called
bool bdp_ping_started = false;
// True if pings should be acked
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index 7ccdffee98..f2f5e7dc53 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -357,13 +357,10 @@ absl::variant<size_t, absl::Status> grpc_chttp2_perform_read(
}
goto dts_fh_0; // loop
} else if (t->incoming_frame_size >
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]) {
- return GRPC_ERROR_CREATE(
- absl::StrFormat("Frame size %d is larger than max frame size %d",
- t->incoming_frame_size,
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]));
+ t->settings.acked().max_frame_size()) {
+ return GRPC_ERROR_CREATE(absl::StrFormat(
+ "Frame size %d is larger than max frame size %d",
+ t->incoming_frame_size, t->settings.acked().max_frame_size()));
}
if (++cur == end) {
return absl::OkStatus();
@@ -505,8 +502,7 @@ static grpc_error_handle init_header_skip_frame_parser(
/*metadata_size_soft_limit=*/
t->max_header_list_size_soft_limit,
/*metadata_size_hard_limit=*/
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE],
+ t->settings.acked().max_header_list_size(),
hpack_boundary_type(t, is_eoh), priority_type,
hpack_parser_log_info(t, HPackParser::LogInfo::kDontKnow));
return absl::OkStatus();
@@ -646,10 +642,8 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
"ignoring grpc_chttp2_stream with non-client generated index %d",
t->incoming_stream_id));
return init_header_skip_frame_parser(t, priority_type, is_eoh);
- } else if (GPR_UNLIKELY(
- t->stream_map.size() + t->extra_streams >=
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS])) {
+ } else if (GPR_UNLIKELY(t->stream_map.size() + t->extra_streams >=
+ t->settings.acked().max_concurrent_streams())) {
if (grpc_core::IsRfcMaxConcurrentStreamsEnabled()) {
++t->num_pending_induced_frames;
grpc_slice_buffer_add(
@@ -678,8 +672,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
t->max_concurrent_streams_policy.AdvertiseValue() &&
grpc_core::RandomEarlyDetection(
t->max_concurrent_streams_policy.AdvertiseValue(),
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS])
+ t->settings.acked().max_concurrent_streams())
.Reject(t->stream_map.size(), t->bitgen))) {
// We are under the limit of max concurrent streams for the current
// setting, but are over the next value that will be advertised.
@@ -788,15 +781,13 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
return GRPC_ERROR_CREATE(
"Trailing metadata frame received without an end-o-stream");
}
- t->hpack_parser.BeginFrame(
- incoming_metadata_buffer,
- /*metadata_size_soft_limit=*/
- t->max_header_list_size_soft_limit,
- /*metadata_size_hard_limit=*/
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE],
- hpack_boundary_type(t, is_eoh), priority_type,
- hpack_parser_log_info(t, frame_type));
+ t->hpack_parser.BeginFrame(incoming_metadata_buffer,
+ /*metadata_size_soft_limit=*/
+ t->max_header_list_size_soft_limit,
+ /*metadata_size_hard_limit=*/
+ t->settings.acked().max_header_list_size(),
+ hpack_boundary_type(t, is_eoh), priority_type,
+ hpack_parser_log_info(t, frame_type));
return absl::OkStatus();
}
@@ -867,21 +858,20 @@ static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t) {
grpc_error_handle err = grpc_chttp2_settings_parser_begin_frame(
&t->simple.settings, t->incoming_frame_size, t->incoming_frame_flags,
- t->settings[GRPC_PEER_SETTINGS]);
+ t->settings.mutable_peer());
if (!err.ok()) {
return err;
}
if (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
t->max_concurrent_streams_policy.AckLastSend();
- memcpy(t->settings[GRPC_ACKED_SETTINGS], t->settings[GRPC_SENT_SETTINGS],
- GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
+ if (!t->settings.AckLastSend()) {
+ return GRPC_ERROR_CREATE("Received unexpected settings ack");
+ }
t->hpack_parser.hpack_table()->SetMaxBytes(
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+ t->settings.acked().header_table_size());
grpc_chttp2_act_on_flowctl_action(
t->flow_control.SetAckedInitialWindow(
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]),
+ t->settings.acked().initial_window_size()),
t, nullptr);
if (t->settings_ack_watchdog !=
grpc_event_engine::experimental::EventEngine::TaskHandle::kInvalid) {
@@ -889,7 +879,6 @@ static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t) {
t->settings_ack_watchdog,
grpc_event_engine::experimental::EventEngine::TaskHandle::kInvalid));
}
- t->sent_local_settings = false;
// This is more streams than can be started in http2, so setting this
// effictively removes the limit for the rest of the connection.
t->num_incoming_streams_before_settings_ack =
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index 8ca99c4fdf..b1f9f30d2f 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -218,15 +218,12 @@ static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
":peer_initwin=%d:t_win=%" PRId64 ":s_win=%d:s_delta=%" PRId64 "]",
std::string(t->peer_string.as_string_view()).c_str(), t, s->id, staller,
s->flow_controlled_buffer.length, s->flow_controlled_bytes_flowed,
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
+ t->settings.acked().initial_window_size(),
t->flow_control.remote_window(),
static_cast<uint32_t>(std::max(
- int64_t{0},
- s->flow_control.remote_window_delta() +
- static_cast<int64_t>(
- t->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]))),
+ int64_t{0}, s->flow_control.remote_window_delta() +
+ static_cast<int64_t>(
+ t->settings.peer().initial_window_size()))),
s->flow_control.remote_window_delta());
}
}
@@ -266,21 +263,12 @@ class WriteContext {
}
void FlushSettings() {
- const bool dirty =
- t_->dirtied_local_settings ||
- t_->settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] !=
- t_->max_concurrent_streams_policy.AdvertiseValue();
- if (dirty && !t_->sent_local_settings) {
- t_->settings[GRPC_LOCAL_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] =
- t_->max_concurrent_streams_policy.AdvertiseValue();
- grpc_slice_buffer_add(
- t_->outbuf.c_slice_buffer(),
- grpc_chttp2_settings_create(t_->settings[GRPC_SENT_SETTINGS],
- t_->settings[GRPC_LOCAL_SETTINGS],
- t_->force_send_settings,
- GRPC_CHTTP2_NUM_SETTINGS));
+ t_->settings.mutable_local().SetMaxConcurrentStreams(
+ t_->max_concurrent_streams_policy.AdvertiseValue());
+ auto update = t_->settings.MaybeSendUpdate();
+ if (update.has_value()) {
+ grpc_core::Http2Frame frame(std::move(*update));
+ Serialize(absl::Span<grpc_core::Http2Frame>(&frame, 1), t_->outbuf);
if (t_->keepalive_timeout != grpc_core::Duration::Infinity()) {
GPR_ASSERT(
t_->settings_ack_watchdog ==
@@ -294,9 +282,6 @@ class WriteContext {
grpc_chttp2_settings_timeout(std::move(t));
});
}
- t_->force_send_settings = false;
- t_->dirtied_local_settings = false;
- t_->sent_local_settings = true;
t_->flow_control.FlushedSettings();
t_->max_concurrent_streams_policy.FlushedSettings();
grpc_core::global_stats().IncrementHttp2SettingsWrites();
@@ -336,8 +321,7 @@ class WriteContext {
void EnactHpackSettings() {
t_->hpack_compressor.SetMaxTableSize(
- t_->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+ t_->settings.peer().header_table_size());
}
void UpdateStreamsNoLongerStalled() {
@@ -410,17 +394,14 @@ class DataSendContext {
return static_cast<uint32_t>(std::max(
int64_t{0},
s_->flow_control.remote_window_delta() +
- static_cast<int64_t>(
- t_->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE])));
+ static_cast<int64_t>(t_->settings.peer().initial_window_size())));
}
uint32_t max_outgoing() const {
return grpc_core::Clamp<uint32_t>(
std::min<int64_t>(
- {t_->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
- stream_remote_window(), t_->flow_control.remote_window(),
+ {t_->settings.peer().max_frame_size(), stream_remote_window(),
+ t_->flow_control.remote_window(),
grpc_core::IsWriteSizeCapEnabled()
? static_cast<int64_t>(write_context_->target_write_size())
: std::numeric_limits<uint32_t>::max()}),
@@ -494,14 +475,10 @@ class StreamWriteContext {
grpc_core::HPackCompressor::EncodeHeaderOptions{
s_->id, // stream_id
false, // is_eof
- t_->settings
- [GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA] !=
- 0, // use_true_binary_metadata
- t_->settings
- [GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], // max_frame_size
- &s_->stats.outgoing // stats
+ t_->settings.peer()
+ .allow_true_binary_metadata(), // use_true_binary_metadata
+ t_->settings.peer().max_frame_size(), // max_frame_size
+ &s_->stats.outgoing // stats
},
*s_->send_initial_metadata, t_->outbuf.c_slice_buffer());
grpc_chttp2_reset_ping_clock(t_);
@@ -596,14 +573,8 @@ class StreamWriteContext {
}
t_->hpack_compressor.EncodeHeaders(
grpc_core::HPackCompressor::EncodeHeaderOptions{
- s_->id, true,
- t_->settings
- [GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA] !=
- 0,
- t_->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
- &s_->stats.outgoing},
+ s_->id, true, t_->settings.peer().allow_true_binary_metadata(),
+ t_->settings.peer().max_frame_size(), &s_->stats.outgoing},
*s_->send_trailing_metadata, t_->outbuf.c_slice_buffer());
}
write_context_->IncTrailingMetadataWrites();
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 021c735053..6bf08a818f 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -107,6 +107,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
'src/core/ext/transport/chttp2/transport/decode_huff.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
+ 'src/core/ext/transport/chttp2/transport/frame.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
'src/core/ext/transport/chttp2/transport/frame_ping.cc',
diff --git a/test/core/transport/chttp2/BUILD b/test/core/transport/chttp2/BUILD
index 77ce6b4d10..1c11d2f554 100644
--- a/test/core/transport/chttp2/BUILD
+++ b/test/core/transport/chttp2/BUILD
@@ -446,3 +446,20 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
],
)
+
+grpc_cc_test(
+ name = "http2_settings_test",
+ srcs = [
+ "http2_settings_test.cc",
+ ],
+ external_deps = [
+ "gtest",
+ ],
+ language = "C++",
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//src/core:http2_settings",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/transport/chttp2/http2_settings_test.cc b/test/core/transport/chttp2/http2_settings_test.cc
new file mode 100644
index 0000000000..776a131be4
--- /dev/null
+++ b/test/core/transport/chttp2/http2_settings_test.cc
@@ -0,0 +1,514 @@
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace grpc_core {
+
+TEST(Http2SettingsTest, CanSetAndRetrieveSettings) {
+ Http2Settings settings;
+ settings.SetHeaderTableSize(1);
+ settings.SetEnablePush(true);
+ settings.SetMaxConcurrentStreams(3);
+ settings.SetInitialWindowSize(4);
+ settings.SetMaxFrameSize(50000);
+ settings.SetMaxHeaderListSize(6);
+ settings.SetAllowTrueBinaryMetadata(true);
+ settings.SetPreferredReceiveCryptoMessageSize(77777);
+ EXPECT_EQ(settings.header_table_size(), 1u);
+ EXPECT_EQ(settings.enable_push(), true);
+ EXPECT_EQ(settings.max_concurrent_streams(), 3u);
+ EXPECT_EQ(settings.initial_window_size(), 4u);
+ EXPECT_EQ(settings.max_frame_size(), 50000u);
+ EXPECT_EQ(settings.max_header_list_size(), 6u);
+ EXPECT_EQ(settings.allow_true_binary_metadata(), true);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 77777u);
+ settings.SetHeaderTableSize(10);
+ settings.SetEnablePush(false);
+ settings.SetMaxConcurrentStreams(30);
+ settings.SetInitialWindowSize(40);
+ settings.SetMaxFrameSize(5000000);
+ settings.SetMaxHeaderListSize(60);
+ settings.SetAllowTrueBinaryMetadata(false);
+ settings.SetPreferredReceiveCryptoMessageSize(70000);
+ EXPECT_EQ(settings.header_table_size(), 10u);
+ EXPECT_EQ(settings.enable_push(), false);
+ EXPECT_EQ(settings.max_concurrent_streams(), 30u);
+ EXPECT_EQ(settings.initial_window_size(), 40u);
+ EXPECT_EQ(settings.max_frame_size(), 5000000u);
+ EXPECT_EQ(settings.max_header_list_size(), 60u);
+ EXPECT_EQ(settings.allow_true_binary_metadata(), false);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 70000u);
+}
+
+TEST(Http2SettingsTest, InitialWindowSizeLimits) {
+ Http2Settings settings;
+ settings.SetInitialWindowSize(0);
+ EXPECT_EQ(settings.initial_window_size(), 0u);
+ settings.SetInitialWindowSize(0x7fffffff);
+ EXPECT_EQ(settings.initial_window_size(), 0x7fffffffu);
+ settings.SetInitialWindowSize(0x80000000);
+ EXPECT_EQ(settings.initial_window_size(), 0x7fffffffu);
+ settings.SetInitialWindowSize(0xffffffff);
+ EXPECT_EQ(settings.initial_window_size(), 0x7fffffffu);
+}
+
+TEST(Http2SettingsTest, MaxFrameSizeLimits) {
+ Http2Settings settings;
+ settings.SetMaxFrameSize(0);
+ EXPECT_EQ(settings.max_frame_size(), 16384u);
+ settings.SetMaxFrameSize(16384);
+ EXPECT_EQ(settings.max_frame_size(), 16384u);
+ settings.SetMaxFrameSize(16385);
+ EXPECT_EQ(settings.max_frame_size(), 16385u);
+ settings.SetMaxFrameSize(16777215);
+ EXPECT_EQ(settings.max_frame_size(), 16777215u);
+ settings.SetMaxFrameSize(16777216);
+ EXPECT_EQ(settings.max_frame_size(), 16777215u);
+ settings.SetMaxFrameSize(16777217);
+ EXPECT_EQ(settings.max_frame_size(), 16777215u);
+ settings.SetMaxFrameSize(0xffffffff);
+ EXPECT_EQ(settings.max_frame_size(), 16777215u);
+}
+
+TEST(Http2SettingsTest, PreferredReceiveCryptoMessageSize) {
+ Http2Settings settings;
+ settings.SetPreferredReceiveCryptoMessageSize(0);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16384u);
+ settings.SetPreferredReceiveCryptoMessageSize(16384);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16384u);
+ settings.SetPreferredReceiveCryptoMessageSize(16385);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16385u);
+ settings.SetPreferredReceiveCryptoMessageSize(16777215);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16777215u);
+ settings.SetPreferredReceiveCryptoMessageSize(16777216);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16777216u);
+ settings.SetPreferredReceiveCryptoMessageSize(16777217);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16777217u);
+ settings.SetPreferredReceiveCryptoMessageSize(0x7fffffff);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu);
+ settings.SetPreferredReceiveCryptoMessageSize(0x80000000);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu);
+ settings.SetPreferredReceiveCryptoMessageSize(0xffffffff);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu);
+}
+
+namespace {
+using KeyValue = std::pair<uint16_t, uint32_t>;
+using KeyValueVec = std::vector<KeyValue>;
+
+KeyValueVec Diff(const Http2Settings& a, const Http2Settings& b,
+ bool is_first_send) {
+ KeyValueVec diffs;
+ a.Diff(is_first_send, b, [&diffs](uint16_t key, uint32_t value) {
+ diffs.emplace_back(key, value);
+ });
+ return diffs;
+}
+
+bool operator==(const KeyValue& a, const Http2SettingsFrame::Setting& b) {
+ return a.first == b.id && a.second == b.value;
+}
+
+} // namespace
+
+TEST(Http2SettingsTest, DiffOnFreshlyInitializedSettings) {
+ const Http2Settings settings1;
+ const Http2Settings settings2;
+ EXPECT_THAT(Diff(settings1, settings2, false), ::testing::IsEmpty());
+ EXPECT_THAT(Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(KeyValue{4, 65535}));
+}
+
+TEST(Http2SettingsTest, DiffOnSettingsWithOneValueSet) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ EXPECT_THAT(Diff(settings1, settings2, false),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}));
+ EXPECT_THAT(
+ Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{4, 65535}));
+}
+
+TEST(Http2SettingsTest, DiffOnSettingsWithTwoValuesSet) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ settings1.SetEnablePush(false);
+ EXPECT_THAT(Diff(settings1, settings2, false),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0}));
+ EXPECT_THAT(Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0},
+ KeyValue{4, 65535}));
+}
+
+TEST(Http2SettingsTest, DiffOnSettingsWithThreeValuesSet) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ settings1.SetEnablePush(false);
+ settings1.SetMaxConcurrentStreams(3);
+ EXPECT_THAT(Diff(settings1, settings2, false),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0},
+ KeyValue{3, 3}));
+ EXPECT_THAT(
+ Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0},
+ KeyValue{3, 3}, KeyValue{4, 65535}));
+}
+
+TEST(Http2SettingsTest, DiffOnSettingsWithFourValuesSet) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ settings1.SetEnablePush(false);
+ settings1.SetMaxConcurrentStreams(3);
+ settings1.SetInitialWindowSize(4);
+ EXPECT_THAT(Diff(settings1, settings2, false),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0},
+ KeyValue{3, 3}, KeyValue{4, 4}));
+ EXPECT_THAT(Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0},
+ KeyValue{3, 3}, KeyValue{4, 4}));
+}
+
+TEST(Http2SettingsTest, DiffOnSettingsWithFiveValuesSet) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ settings1.SetEnablePush(false);
+ settings1.SetMaxConcurrentStreams(3);
+ settings1.SetInitialWindowSize(4);
+ settings1.SetMaxFrameSize(50000);
+ EXPECT_THAT(Diff(settings1, settings2, false),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0},
+ KeyValue{3, 3}, KeyValue{4, 4},
+ KeyValue{5, 50000}));
+ EXPECT_THAT(Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0},
+ KeyValue{3, 3}, KeyValue{4, 4},
+ KeyValue{5, 50000}));
+}
+
+TEST(Http2SettingsTest, DiffOnSettingsWithSixValuesSet) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ settings1.SetEnablePush(false);
+ settings1.SetMaxConcurrentStreams(3);
+ settings1.SetInitialWindowSize(4);
+ settings1.SetMaxFrameSize(50000);
+ settings1.SetMaxHeaderListSize(6);
+ EXPECT_THAT(Diff(settings1, settings2, false),
+ ::testing::UnorderedElementsAre(
+ KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3},
+ KeyValue{4, 4}, KeyValue{5, 50000}, KeyValue{6, 6}));
+ EXPECT_THAT(Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(
+ KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3},
+ KeyValue{4, 4}, KeyValue{5, 50000}, KeyValue{6, 6}));
+}
+
+TEST(Http2SettingsTest, DiffOnSettingsWithSevenValuesSet) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ settings1.SetEnablePush(false);
+ settings1.SetMaxConcurrentStreams(3);
+ settings1.SetInitialWindowSize(4);
+ settings1.SetMaxFrameSize(50000);
+ settings1.SetMaxHeaderListSize(6);
+ settings1.SetAllowTrueBinaryMetadata(true);
+ EXPECT_THAT(
+ Diff(settings1, settings2, false),
+ ::testing::UnorderedElementsAre(
+ KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3}, KeyValue{4, 4},
+ KeyValue{5, 50000}, KeyValue{6, 6}, KeyValue{65027, 1}));
+ EXPECT_THAT(
+ Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(
+ KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3}, KeyValue{4, 4},
+ KeyValue{5, 50000}, KeyValue{6, 6}, KeyValue{65027, 1}));
+}
+
+TEST(Http2SettingsTest, DiffOnSettingsWithEightValuesSet) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ settings1.SetEnablePush(false);
+ settings1.SetMaxConcurrentStreams(3);
+ settings1.SetInitialWindowSize(4);
+ settings1.SetMaxFrameSize(50000);
+ settings1.SetMaxHeaderListSize(6);
+ settings1.SetAllowTrueBinaryMetadata(true);
+ settings1.SetPreferredReceiveCryptoMessageSize(77777);
+ EXPECT_THAT(Diff(settings1, settings2, false),
+ ::testing::UnorderedElementsAre(
+ KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3},
+ KeyValue{4, 4}, KeyValue{5, 50000}, KeyValue{6, 6},
+ KeyValue{65027, 1}, KeyValue{65028, 77777}));
+ EXPECT_THAT(Diff(settings1, settings2, true),
+ ::testing::UnorderedElementsAre(
+ KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3},
+ KeyValue{4, 4}, KeyValue{5, 50000}, KeyValue{6, 6},
+ KeyValue{65027, 1}, KeyValue{65028, 77777}));
+}
+
+TEST(Http2SettingsTest, ChangingHeaderTableSizeChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetHeaderTableSize(1);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetHeaderTableSize(1);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetHeaderTableSize(2);
+ EXPECT_NE(settings1, settings2);
+}
+
+TEST(Http2SettingsTest, ChangingEnablePushChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetEnablePush(false);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetEnablePush(false);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetEnablePush(true);
+ EXPECT_NE(settings1, settings2);
+}
+
+TEST(Http2SettingsTest, ChangingMaxConcurrentStreamsChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetMaxConcurrentStreams(1);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetMaxConcurrentStreams(1);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetMaxConcurrentStreams(2);
+ EXPECT_NE(settings1, settings2);
+}
+
+TEST(Http2SettingsTest, ChangingInitialWindowSizeChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetInitialWindowSize(1);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetInitialWindowSize(1);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetInitialWindowSize(2);
+ EXPECT_NE(settings1, settings2);
+}
+
+TEST(Http2SettingsTest, ChangingMaxFrameSizeChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetMaxFrameSize(100000);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetMaxFrameSize(100000);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetMaxFrameSize(200000);
+ EXPECT_NE(settings1, settings2);
+}
+
+TEST(Http2SettingsTest, ChangingMaxHeaderListSizeChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetMaxHeaderListSize(1);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetMaxHeaderListSize(1);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetMaxHeaderListSize(2);
+ EXPECT_NE(settings1, settings2);
+}
+
+TEST(Http2SettingsTest, ChangingAllowTrueBinaryMetadataChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetAllowTrueBinaryMetadata(true);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetAllowTrueBinaryMetadata(true);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetAllowTrueBinaryMetadata(false);
+ EXPECT_NE(settings1, settings2);
+}
+
+TEST(Http2SettingsTest,
+ ChangingPreferredReceiveCryptoMessageSizeChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetPreferredReceiveCryptoMessageSize(100000);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetPreferredReceiveCryptoMessageSize(100000);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetPreferredReceiveCryptoMessageSize(200000);
+ EXPECT_NE(settings1, settings2);
+}
+
+TEST(Http2SettingsTest, WireIdToNameWorks) {
+ EXPECT_EQ(Http2Settings::WireIdToName(1), "HEADER_TABLE_SIZE");
+ EXPECT_EQ(Http2Settings::WireIdToName(2), "ENABLE_PUSH");
+ EXPECT_EQ(Http2Settings::WireIdToName(3), "MAX_CONCURRENT_STREAMS");
+ EXPECT_EQ(Http2Settings::WireIdToName(4), "INITIAL_WINDOW_SIZE");
+ EXPECT_EQ(Http2Settings::WireIdToName(5), "MAX_FRAME_SIZE");
+ EXPECT_EQ(Http2Settings::WireIdToName(6), "MAX_HEADER_LIST_SIZE");
+ EXPECT_EQ(Http2Settings::WireIdToName(65027),
+ "GRPC_ALLOW_TRUE_BINARY_METADATA");
+ EXPECT_EQ(Http2Settings::WireIdToName(65028),
+ "GRPC_PREFERRED_RECEIVE_MESSAGE_SIZE");
+ EXPECT_EQ(Http2Settings::WireIdToName(65029), "UNKNOWN (65029)");
+}
+
+TEST(Http2SettingsTest, ApplyHeaderTableSizeWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(1, 1), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.header_table_size(), 1u);
+ EXPECT_EQ(settings.Apply(1, 0x7fffffff), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.header_table_size(), 0x7fffffffu);
+}
+
+TEST(Http2SettingsTest, ApplyEnablePushWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(2, 0), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.enable_push(), false);
+ EXPECT_EQ(settings.Apply(2, 1), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.enable_push(), true);
+ EXPECT_EQ(settings.Apply(2, 2), GRPC_HTTP2_PROTOCOL_ERROR);
+}
+
+TEST(Http2SettingsTest, ApplyMaxConcurrentStreamsWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(3, 1), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.max_concurrent_streams(), 1u);
+ EXPECT_EQ(settings.Apply(3, 0x7fffffff), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.max_concurrent_streams(), 0x7fffffffu);
+}
+
+TEST(Http2SettingsTest, ApplyInitialWindowSizeWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(4, 1), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.initial_window_size(), 1u);
+ EXPECT_EQ(settings.Apply(4, 0x7fffffff), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.initial_window_size(), 0x7fffffffu);
+}
+
+TEST(Http2SettingsTest, ApplyMaxFrameSizeWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(5, 16384), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.max_frame_size(), 16384u);
+ EXPECT_EQ(settings.Apply(5, 16777215), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.max_frame_size(), 16777215);
+ EXPECT_EQ(settings.Apply(5, 16383), GRPC_HTTP2_PROTOCOL_ERROR);
+ EXPECT_EQ(settings.Apply(5, 16777216), GRPC_HTTP2_PROTOCOL_ERROR);
+}
+
+TEST(Http2SettingsTest, ApplyMaxHeaderListSizeWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(6, 1), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.max_header_list_size(), 1u);
+ EXPECT_EQ(settings.Apply(6, 0x7fffffff), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.max_header_list_size(), 16777216);
+}
+
+TEST(Http2SettingsTest, ApplyAllowTrueBinaryMetadataWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(65027, 0), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.allow_true_binary_metadata(), false);
+ EXPECT_EQ(settings.Apply(65027, 1), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.allow_true_binary_metadata(), true);
+ EXPECT_EQ(settings.Apply(65027, 2), GRPC_HTTP2_PROTOCOL_ERROR);
+}
+
+TEST(Http2SettingsTest, ApplyPreferredReceiveCryptoMessageSizeWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(65028, 1), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16384u);
+ EXPECT_EQ(settings.Apply(65028, 0x7fffffff), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu);
+ EXPECT_EQ(settings.Apply(65028, 0x80000000), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu);
+}
+
+namespace {
+MATCHER_P(SettingsFrame, settings, "") {
+ if (!arg.has_value()) {
+ *result_listener << "Expected a settings frame, got nothing";
+ return false;
+ }
+ if (arg->ack) {
+ *result_listener << "Expected a settings frame, got an ack";
+ return false;
+ }
+ if (arg->settings.size() != settings.size()) {
+ *result_listener << "Expected settings frame with " << settings.size()
+ << " settings, got " << arg->settings.size();
+ return false;
+ }
+ for (size_t i = 0; i < settings.size(); i++) {
+ bool found = false;
+ for (size_t j = 0; j < arg->settings.size(); j++) {
+ if (settings[i] == arg->settings[j]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ *result_listener << "Expected settings frame with setting "
+ << settings[i].first << " = " << settings[i].second
+ << ", but it was not found";
+ return false;
+ }
+ }
+ return true;
+}
+} // namespace
+
+TEST(Http2SettingsManagerTest, ImmediatelyNeedsToSend) {
+ Http2SettingsManager settings_manager;
+ EXPECT_THAT(settings_manager.MaybeSendUpdate(),
+ SettingsFrame(KeyValueVec{{4, 65535}}));
+}
+
+TEST(Http2SettingsManagerTest, SendAckWorks) {
+ Http2SettingsManager settings_manager;
+ settings_manager.mutable_local().SetInitialWindowSize(100000);
+ EXPECT_EQ(settings_manager.acked().initial_window_size(), 65535u);
+ EXPECT_THAT(settings_manager.MaybeSendUpdate(),
+ SettingsFrame(KeyValueVec{{4, 100000}}));
+ EXPECT_TRUE(settings_manager.AckLastSend());
+ EXPECT_EQ(settings_manager.acked().initial_window_size(), 100000u);
+}
+
+TEST(Http2SettingsManagerTest, AckWithoutSendFails) {
+ Http2SettingsManager settings_manager;
+ EXPECT_FALSE(settings_manager.AckLastSend());
+}
+
+TEST(Http2SettingsManagerTest, AckAfterAckFails) {
+ Http2SettingsManager settings_manager;
+ settings_manager.mutable_local().SetInitialWindowSize(100000);
+ EXPECT_THAT(settings_manager.MaybeSendUpdate(),
+ SettingsFrame(KeyValueVec{{4, 100000}}));
+ EXPECT_TRUE(settings_manager.AckLastSend());
+ EXPECT_FALSE(settings_manager.AckLastSend());
+}
+
+} // namespace grpc_core
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tools/codegen/core/gen_settings_ids.py b/tools/codegen/core/gen_settings_ids.py
deleted file mode 100755
index 1ac8740748..0000000000
--- a/tools/codegen/core/gen_settings_ids.py
+++ /dev/null
@@ -1,270 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright 2017 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-
-import collections
-import sys
-
-import perfection
-
-_MAX_HEADER_LIST_SIZE = 16 * 1024 * 1024
-
-Setting = collections.namedtuple("Setting", "id default min max on_error")
-OnError = collections.namedtuple("OnError", "behavior code")
-clamp_invalid_value = OnError("CLAMP_INVALID_VALUE", "PROTOCOL_ERROR")
-disconnect_on_invalid_value = lambda e: OnError(
- "DISCONNECT_ON_INVALID_VALUE", e
-)
-DecoratedSetting = collections.namedtuple(
- "DecoratedSetting", "enum name setting"
-)
-
-_SETTINGS = {
- "HEADER_TABLE_SIZE": Setting(1, 4096, 0, 0xFFFFFFFF, clamp_invalid_value),
- "ENABLE_PUSH": Setting(
- 2, 1, 0, 1, disconnect_on_invalid_value("PROTOCOL_ERROR")
- ),
- "MAX_CONCURRENT_STREAMS": Setting(
- 3,
- 0xFFFFFFFF,
- 0,
- 0xFFFFFFFF,
- disconnect_on_invalid_value("PROTOCOL_ERROR"),
- ),
- "INITIAL_WINDOW_SIZE": Setting(
- 4,
- 65535,
- 0,
- 0x7FFFFFFF,
- disconnect_on_invalid_value("FLOW_CONTROL_ERROR"),
- ),
- "MAX_FRAME_SIZE": Setting(
- 5, 16384, 16384, 16777215, disconnect_on_invalid_value("PROTOCOL_ERROR")
- ),
- "MAX_HEADER_LIST_SIZE": Setting(
- 6, _MAX_HEADER_LIST_SIZE, 0, _MAX_HEADER_LIST_SIZE, clamp_invalid_value
- ),
- "GRPC_ALLOW_TRUE_BINARY_METADATA": Setting(
- 0xFE03, 0, 0, 1, clamp_invalid_value
- ),
- "GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE": Setting(
- 0xFE04, 0, 16384, 0x7FFFFFFF, clamp_invalid_value
- ),
-}
-
-H = open("src/core/ext/transport/chttp2/transport/http2_settings.h", "w")
-C = open("src/core/ext/transport/chttp2/transport/http2_settings.cc", "w")
-
-
-# utility: print a big comment block into a set of files
-def put_banner(files, banner):
- for f in files:
- print("/*", file=f)
- for line in banner:
- print(" * %s" % line, file=f)
- print(" */", file=f)
- print(file=f)
-
-
-# copy-paste copyright notice from this file
-with open(sys.argv[0]) as my_source:
- copyright = []
- for line in my_source:
- if line[0] != "#":
- break
- for line in my_source:
- if line[0] == "#":
- copyright.append(line)
- break
- for line in my_source:
- if line[0] != "#":
- break
- copyright.append(line)
- put_banner([H, C], [line[2:].rstrip() for line in copyright])
-
-put_banner(
- [H, C],
- ["Automatically generated by tools/codegen/core/gen_settings_ids.py"],
-)
-
-print(
- "#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H", file=H
-)
-print(
- "#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H", file=H
-)
-print(file=H)
-print("#include <grpc/support/port_platform.h>", file=H)
-print("#include <stdint.h>", file=H)
-print(file=H)
-
-print("#include <grpc/support/port_platform.h>", file=C)
-print(
- '#include "src/core/ext/transport/chttp2/transport/http2_settings.h"',
- file=C,
-)
-print(file=C)
-print('#include "src/core/lib/gpr/useful.h"', file=C)
-print('#include "src/core/lib/transport/http2_errors.h"', file=C)
-print(file=C)
-
-p = perfection.hash_parameters(sorted(x.id for x in list(_SETTINGS.values())))
-print(p)
-
-
-def hash(i):
- i += p.offset
- x = i % p.t
- y = i // p.t
- return x + p.r[y]
-
-
-decorated_settings = [
- DecoratedSetting(hash(setting.id), name, setting)
- for name, setting in _SETTINGS.items()
-]
-
-print("typedef enum {", file=H)
-for decorated_setting in sorted(decorated_settings):
- print(
- " GRPC_CHTTP2_SETTINGS_%s = %d, /* wire id %d */"
- % (
- decorated_setting.name,
- decorated_setting.enum,
- decorated_setting.setting.id,
- ),
- file=H,
- )
-print("} grpc_chttp2_setting_id;", file=H)
-print(file=H)
-print(
- "#define GRPC_CHTTP2_NUM_SETTINGS %d"
- % (max(x.enum for x in decorated_settings) + 1),
- file=H,
-)
-
-print("extern const uint16_t grpc_setting_id_to_wire_id[];", file=H)
-print(
- "const uint16_t grpc_setting_id_to_wire_id[] = {%s};"
- % ",".join("%d" % s for s in p.slots),
- file=C,
-)
-print(file=H)
-print(
- (
- "bool grpc_wire_id_to_setting_id(uint32_t wire_id,"
- " grpc_chttp2_setting_id *out);"
- ),
- file=H,
-)
-cgargs = {
- "r": ",".join("%d" % (r if r is not None else 0) for r in p.r),
- "t": p.t,
- "offset": abs(p.offset),
- "offset_sign": "+" if p.offset > 0 else "-",
-}
-print(
- """
-bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out) {
- uint32_t i = wire_id %(offset_sign)s %(offset)d;
- uint32_t x = i %% %(t)d;
- uint32_t y = i / %(t)d;
- uint32_t h = x;
- switch (y) {
-"""
- % cgargs,
- file=C,
-)
-for i, r in enumerate(p.r):
- if not r:
- continue
- if r < 0:
- print("case %d: h -= %d; break;" % (i, -r), file=C)
- else:
- print("case %d: h += %d; break;" % (i, r), file=C)
-print(
- """
- }
- *out = static_cast<grpc_chttp2_setting_id>(h);
- return h < GPR_ARRAY_SIZE(grpc_setting_id_to_wire_id) && grpc_setting_id_to_wire_id[h] == wire_id;
-}
-"""
- % cgargs,
- file=C,
-)
-
-print(
- """
-typedef enum {
- GRPC_CHTTP2_CLAMP_INVALID_VALUE,
- GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE
-} grpc_chttp2_invalid_value_behavior;
-
-typedef struct {
- const char *name;
- uint32_t default_value;
- uint32_t min_value;
- uint32_t max_value;
- grpc_chttp2_invalid_value_behavior invalid_value_behavior;
- uint32_t error_value;
-} grpc_chttp2_setting_parameters;
-
-extern const grpc_chttp2_setting_parameters grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
-""",
- file=H,
-)
-print(
- (
- "const grpc_chttp2_setting_parameters"
- " grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {"
- ),
- file=C,
-)
-i = 0
-for decorated_setting in sorted(decorated_settings):
- while i < decorated_setting.enum:
- print(
- (
- "{NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,"
- " GRPC_HTTP2_PROTOCOL_ERROR},"
- ),
- file=C,
- )
- i += 1
- print(
- '{"%s", %du, %du, %du, GRPC_CHTTP2_%s, GRPC_HTTP2_%s},'
- % (
- decorated_setting.name,
- decorated_setting.setting.default,
- decorated_setting.setting.min,
- decorated_setting.setting.max,
- decorated_setting.setting.on_error.behavior,
- decorated_setting.setting.on_error.code,
- ),
- file=C,
- )
- i += 1
-print("};", file=C)
-
-print(file=H)
-print(
- "#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H */",
- file=H,
-)
-
-H.close()
-C.close()
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 608c24cf63..dd6261d57f 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1293,6 +1293,8 @@ src/core/ext/transport/chttp2/transport/decode_huff.cc \
src/core/ext/transport/chttp2/transport/decode_huff.h \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/flow_control.h \
+src/core/ext/transport/chttp2/transport/frame.cc \
+src/core/ext/transport/chttp2/transport/frame.h \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_data.h \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index cbc40815ef..0dda802746 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1068,6 +1068,8 @@ src/core/ext/transport/chttp2/transport/decode_huff.cc \
src/core/ext/transport/chttp2/transport/decode_huff.h \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/flow_control.h \
+src/core/ext/transport/chttp2/transport/frame.cc \
+src/core/ext/transport/chttp2/transport/frame.h \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_data.h \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index a8edaa5d45..7e6fcc1d51 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -4742,6 +4742,30 @@
"flaky": false,
"gtest": true,
"language": "c++",
+ "name": "http2_settings_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
"name": "http2_stats_test",
"platforms": [
"linux",