diff --git a/BUILD b/BUILD
index 50a4cc23ed7..0be13c0df87 100644
--- a/BUILD
+++ b/BUILD
@@ -4701,6 +4701,7 @@ grpc_cc_library(
"//src/core:ext/transport/chttp2/transport/frame_goaway.cc",
"//src/core:ext/transport/chttp2/transport/frame_ping.cc",
"//src/core:ext/transport/chttp2/transport/frame_rst_stream.cc",
+ "//src/core:ext/transport/chttp2/transport/frame_security.cc",
"//src/core:ext/transport/chttp2/transport/frame_settings.cc",
"//src/core:ext/transport/chttp2/transport/frame_window_update.cc",
"//src/core:ext/transport/chttp2/transport/parsing.cc",
@@ -4715,6 +4716,7 @@ grpc_cc_library(
"//src/core:ext/transport/chttp2/transport/frame_goaway.h",
"//src/core:ext/transport/chttp2/transport/frame_ping.h",
"//src/core:ext/transport/chttp2/transport/frame_rst_stream.h",
+ "//src/core:ext/transport/chttp2/transport/frame_security.h",
"//src/core:ext/transport/chttp2/transport/frame_settings.h",
"//src/core:ext/transport/chttp2/transport/frame_window_update.h",
"//src/core:ext/transport/chttp2/transport/internal.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c6eae5b40c0..f56216d4f82 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2317,6 +2317,7 @@ add_library(grpc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
src/core/ext/transport/chttp2/transport/frame_ping.cc
src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
+ src/core/ext/transport/chttp2/transport/frame_security.cc
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -3428,6 +3429,7 @@ add_library(grpc_unsecure
src/core/ext/transport/chttp2/transport/frame_goaway.cc
src/core/ext/transport/chttp2/transport/frame_ping.cc
src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
+ src/core/ext/transport/chttp2/transport/frame_security.cc
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
diff --git a/Makefile b/Makefile
index d72c8ab669c..45e2e7e72c0 100644
--- a/Makefile
+++ b/Makefile
@@ -720,6 +720,7 @@ LIBGRPC_SRC = \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
src/core/ext/transport/chttp2/transport/frame_ping.cc \
src/core/ext/transport/chttp2/transport/frame_rst_stream.cc \
+ src/core/ext/transport/chttp2/transport/frame_security.cc \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
diff --git a/Package.swift b/Package.swift
index ceb8a6164dd..1ba620eab9a 100644
--- a/Package.swift
+++ b/Package.swift
@@ -229,6 +229,8 @@ let package = Package(
"src/core/ext/transport/chttp2/transport/frame_ping.h",
"src/core/ext/transport/chttp2/transport/frame_rst_stream.cc",
"src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
+ "src/core/ext/transport/chttp2/transport/frame_security.cc",
+ "src/core/ext/transport/chttp2/transport/frame_security.h",
"src/core/ext/transport/chttp2/transport/frame_settings.cc",
"src/core/ext/transport/chttp2/transport/frame_settings.h",
"src/core/ext/transport/chttp2/transport/frame_window_update.cc",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 077cc43958f..b5f26926fea 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -277,6 +277,7 @@ libs:
- src/core/ext/transport/chttp2/transport/frame_goaway.h
- src/core/ext/transport/chttp2/transport/frame_ping.h
- src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+ - src/core/ext/transport/chttp2/transport/frame_security.h
- src/core/ext/transport/chttp2/transport/frame_settings.h
- src/core/ext/transport/chttp2/transport/frame_window_update.h
- src/core/ext/transport/chttp2/transport/hpack_constants.h
@@ -1332,6 +1333,7 @@ libs:
- src/core/ext/transport/chttp2/transport/frame_goaway.cc
- src/core/ext/transport/chttp2/transport/frame_ping.cc
- src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
+ - src/core/ext/transport/chttp2/transport/frame_security.cc
- src/core/ext/transport/chttp2/transport/frame_settings.cc
- src/core/ext/transport/chttp2/transport/frame_window_update.cc
- src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -2313,6 +2315,7 @@ libs:
- src/core/ext/transport/chttp2/transport/frame_goaway.h
- src/core/ext/transport/chttp2/transport/frame_ping.h
- src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+ - src/core/ext/transport/chttp2/transport/frame_security.h
- src/core/ext/transport/chttp2/transport/frame_settings.h
- src/core/ext/transport/chttp2/transport/frame_window_update.h
- src/core/ext/transport/chttp2/transport/hpack_constants.h
@@ -2796,6 +2799,7 @@ libs:
- src/core/ext/transport/chttp2/transport/frame_goaway.cc
- src/core/ext/transport/chttp2/transport/frame_ping.cc
- src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
+ - src/core/ext/transport/chttp2/transport/frame_security.cc
- src/core/ext/transport/chttp2/transport/frame_settings.cc
- src/core/ext/transport/chttp2/transport/frame_window_update.cc
- src/core/ext/transport/chttp2/transport/hpack_encoder.cc
diff --git a/config.m4 b/config.m4
index 8e8e92c9110..f8b38adf606 100644
--- a/config.m4
+++ b/config.m4
@@ -95,6 +95,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
src/core/ext/transport/chttp2/transport/frame_ping.cc \
src/core/ext/transport/chttp2/transport/frame_rst_stream.cc \
+ src/core/ext/transport/chttp2/transport/frame_security.cc \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
diff --git a/config.w32 b/config.w32
index 2cda7c51ba4..7a03656de1d 100644
--- a/config.w32
+++ b/config.w32
@@ -60,6 +60,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\transport\\chttp2\\transport\\frame_goaway.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_ping.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_rst_stream.cc " +
+ "src\\core\\ext\\transport\\chttp2\\transport\\frame_security.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_settings.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_window_update.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_encoder.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 879779e4e23..72a7240a5e4 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -325,6 +325,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_goaway.h',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
+ 'src/core/ext/transport/chttp2/transport/frame_security.h',
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_constants.h',
@@ -1615,6 +1616,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_goaway.h',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
+ 'src/core/ext/transport/chttp2/transport/frame_security.h',
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_constants.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 626c7d9f815..d8a7b33b9bd 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -349,6 +349,8 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_ping.h',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.cc',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
+ 'src/core/ext/transport/chttp2/transport/frame_security.cc',
+ 'src/core/ext/transport/chttp2/transport/frame_security.h',
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
@@ -2467,6 +2469,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_goaway.h',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
+ 'src/core/ext/transport/chttp2/transport/frame_security.h',
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_constants.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 1f0331818d0..268da42963b 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -235,6 +235,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/frame_ping.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_rst_stream.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_rst_stream.h )
+ s.files += %w( src/core/ext/transport/chttp2/transport/frame_security.cc )
+ s.files += %w( src/core/ext/transport/chttp2/transport/frame_security.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.cc )
diff --git a/include/grpc/impl/channel_arg_names.h b/include/grpc/impl/channel_arg_names.h
index aa973c21977..94361a9182e 100644
--- a/include/grpc/impl/channel_arg_names.h
+++ b/include/grpc/impl/channel_arg_names.h
@@ -400,6 +400,8 @@
"grpc.max_allowed_incoming_connections"
/** Configure per-channel or per-server stats plugins. */
#define GRPC_ARG_EXPERIMENTAL_STATS_PLUGINS "grpc.experimental.stats_plugins"
+/** If non-zero, allow security frames to be sent and received. */
+#define GRPC_ARG_SECURITY_FRAME_ALLOWED "grpc.security_frame_allowed"
/** \} */
#endif /* GRPC_IMPL_CHANNEL_ARG_NAMES_H */
diff --git a/package.xml b/package.xml
index cac0a8fc360..b19e583a1b9 100644
--- a/package.xml
+++ b/package.xml
@@ -217,6 +217,8 @@
+
+
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index 8b204a1d5b1..d4817366fb9 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -60,6 +60,7 @@
#include "src/core/ext/transport/chttp2/transport/frame_data.h"
#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
+#include "src/core/ext/transport/chttp2/transport/frame_security.h"
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
@@ -549,6 +550,9 @@ static void read_channel_args(grpc_chttp2_transport* t,
t->settings.mutable_local().SetPreferredReceiveCryptoMessageSize(INT_MAX);
}
+ t->settings.mutable_local().SetAllowSecurityFrame(
+ channel_args.GetBool(GRPC_ARG_SECURITY_FRAME_ALLOWED).value_or(false));
+
t->ping_on_rst_stream_percent = grpc_core::Clamp(
channel_args.GetInt(GRPC_ARG_HTTP2_PING_ON_RST_STREAM_PERCENT)
.value_or(1),
@@ -592,8 +596,19 @@ void grpc_chttp2_transport::WriteSecurityFrameLocked(
if (data == nullptr) {
return;
}
- // TODO(alishananda): create security frame and append to qbuf, initiate write
- grpc_core::Crash("unreachable");
+ if (!settings.peer().allow_security_frame()) {
+ close_transport_locked(
+ this,
+ grpc_error_set_int(
+ GRPC_ERROR_CREATE("Unexpected SECURITY frame scheduled for write"),
+ grpc_core::StatusIntProperty::kRpcStatus,
+ GRPC_STATUS_FAILED_PRECONDITION));
+ }
+ grpc_core::SliceBuffer security_frame;
+ grpc_chttp2_security_frame_create(data->c_slice_buffer(), data->Length(),
+ security_frame.c_slice_buffer());
+ grpc_slice_buffer_move_into(security_frame.c_slice_buffer(), &qbuf);
+ grpc_chttp2_initiate_write(this, GRPC_CHTTP2_INITIATE_WRITE_SEND_MESSAGE);
}
using grpc_event_engine::experimental::QueryExtension;
@@ -638,13 +653,15 @@ grpc_chttp2_transport::grpc_chttp2_transport(
}
}
- transport_framing_endpoint_extension = QueryExtension<
- grpc_core::TransportFramingEndpointExtension>(
- grpc_event_engine::experimental::grpc_get_wrapped_event_engine_endpoint(
- ep.get()));
- if (transport_framing_endpoint_extension != nullptr) {
- transport_framing_endpoint_extension->SetSendFrameCallback(
- [this](grpc_core::SliceBuffer* data) { WriteSecurityFrame(data); });
+ if (channel_args.GetBool(GRPC_ARG_SECURITY_FRAME_ALLOWED).value_or(false)) {
+ transport_framing_endpoint_extension = QueryExtension<
+ grpc_core::TransportFramingEndpointExtension>(
+ grpc_event_engine::experimental::grpc_get_wrapped_event_engine_endpoint(
+ ep.get()));
+ if (transport_framing_endpoint_extension != nullptr) {
+ transport_framing_endpoint_extension->SetSendFrameCallback(
+ [this](grpc_core::SliceBuffer* data) { WriteSecurityFrame(data); });
+ }
}
CHECK(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
diff --git a/src/core/ext/transport/chttp2/transport/frame.cc b/src/core/ext/transport/chttp2/transport/frame.cc
index cd9093f94a9..2545eb356db 100644
--- a/src/core/ext/transport/chttp2/transport/frame.cc
+++ b/src/core/ext/transport/chttp2/transport/frame.cc
@@ -38,6 +38,7 @@ constexpr uint8_t kFrameTypePing = 6;
constexpr uint8_t kFrameTypeGoaway = 7;
constexpr uint8_t kFrameTypeWindowUpdate = 8;
constexpr uint8_t kFrameTypePushPromise = 5;
+constexpr uint8_t kFrameTypeSecurity = 200;
constexpr uint8_t kFlagEndStream = 1;
constexpr uint8_t kFlagAck = 1;
@@ -122,6 +123,7 @@ class SerializeExtraBytesRequired {
size_t operator()(const Http2PingFrame&) { return 8; }
size_t operator()(const Http2GoawayFrame&) { return 8; }
size_t operator()(const Http2WindowUpdateFrame&) { return 4; }
+ size_t operator()(const Http2SecurityFrame&) { return 0; }
size_t operator()(const Http2UnknownFrame&) { Crash("unreachable"); }
};
@@ -218,6 +220,15 @@ class SerializeHeaderAndPayload {
out_.AppendIndexed(Slice(std::move(hdr_and_payload)));
}
+ void operator()(Http2SecurityFrame& frame) {
+ auto hdr = extra_bytes_.TakeFirst(kFrameHeaderSize);
+ Http2FrameHeader{static_cast(frame.payload.Length()),
+ kFrameTypeSecurity, 0, 0}
+ .Serialize(hdr.begin());
+ out_.AppendIndexed(Slice(std::move(hdr)));
+ out_.TakeAndAppend(frame.payload);
+ }
+
void operator()(Http2UnknownFrame&) { Crash("unreachable"); }
private:
@@ -415,6 +426,11 @@ absl::StatusOr ParseWindowUpdateFrame(
return Http2WindowUpdateFrame{hdr.stream_id, Read4b(buffer)};
}
+absl::StatusOr ParseSecurityFrame(
+ const Http2FrameHeader& /*hdr*/, SliceBuffer& payload) {
+ return Http2SecurityFrame{std::move(payload)};
+}
+
} // namespace
void Http2FrameHeader::Serialize(uint8_t* output) const {
@@ -447,6 +463,8 @@ std::string Http2FrameTypeString(uint8_t frame_type) {
return "WINDOW_UPDATE";
case kFrameTypePing:
return "PING";
+ case kFrameTypeSecurity:
+ return "SECURITY";
}
return absl::StrCat("UNKNOWN(", frame_type, ")");
}
@@ -495,6 +513,8 @@ absl::StatusOr ParseFramePayload(const Http2FrameHeader& hdr,
return absl::InternalError(
"push promise not supported (and SETTINGS_ENABLE_PUSH explicitly "
"disabled).");
+ case kFrameTypeSecurity:
+ return ParseSecurityFrame(hdr, payload);
default:
return Http2UnknownFrame{};
}
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index ccefc083f92..8a91d9e1df0 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -151,6 +151,15 @@ struct Http2WindowUpdateFrame {
}
};
+// Security-related frame
+struct Http2SecurityFrame {
+ SliceBuffer payload;
+
+ bool operator==(const Http2SecurityFrame& other) const {
+ return payload.JoinIntoString() == other.payload.JoinIntoString();
+ }
+};
+
// Type of frame was unknown (and should be ignored)
struct Http2UnknownFrame {
bool operator==(const Http2UnknownFrame&) const { return true; }
@@ -164,7 +173,8 @@ struct Http2UnknownFrame {
using Http2Frame =
absl::variant;
+ Http2GoawayFrame, Http2WindowUpdateFrame, Http2SecurityFrame,
+ Http2UnknownFrame>;
///////////////////////////////////////////////////////////////////////////////
// Frame header
diff --git a/src/core/ext/transport/chttp2/transport/frame_security.cc b/src/core/ext/transport/chttp2/transport/frame_security.cc
new file mode 100644
index 00000000000..08a8b800892
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_security.cc
@@ -0,0 +1,82 @@
+//
+// 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/frame_security.h"
+
+#include
+#include
+
+#include "absl/status/status.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/ext/transport/chttp2/transport/legacy_frame.h"
+#include "src/core/lib/iomgr/event_engine_shims/endpoint.h"
+#include "src/core/lib/slice/slice.h"
+#include "src/core/lib/slice/slice_buffer.h"
+#include "src/core/lib/transport/transport_framing_endpoint_extension.h"
+
+absl::Status grpc_chttp2_security_frame_parser_parse(void* parser,
+ grpc_chttp2_transport* t,
+ grpc_chttp2_stream* /*s*/,
+ const grpc_slice& slice,
+ int is_last) {
+ // Ignore frames from non-EventEngine endpoints.
+ if (t->transport_framing_endpoint_extension == nullptr) {
+ return absl::OkStatus();
+ }
+
+ grpc_chttp2_security_frame_parser* p =
+ static_cast(parser);
+ p->payload.Append(grpc_core::Slice(slice));
+
+ if (is_last) {
+ // Send security frame payload to endpoint.
+ t->transport_framing_endpoint_extension->ReceiveFrame(
+ std::move(p->payload));
+ }
+
+ return absl::OkStatus();
+}
+
+absl::Status grpc_chttp2_security_frame_parser_begin_frame(
+ grpc_chttp2_security_frame_parser* parser) {
+ parser->payload.Clear();
+ return absl::OkStatus();
+}
+
+void grpc_chttp2_security_frame_create(grpc_slice_buffer* payload,
+ uint32_t length,
+ grpc_slice_buffer* frame) {
+ // does this frame need padding for security?
+ // do we need to worry about max frame size? it's 16 bytes
+ grpc_slice hdr;
+ uint8_t* p;
+ static const size_t header_size = 9;
+
+ hdr = GRPC_SLICE_MALLOC(header_size);
+ p = GRPC_SLICE_START_PTR(hdr);
+ *p++ = static_cast(length >> 16);
+ *p++ = static_cast(length >> 8);
+ *p++ = static_cast(length);
+ *p++ = GRPC_CHTTP2_FRAME_SECURITY;
+ *p++ = 0; // no flags
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+
+ grpc_slice_buffer_add(frame, hdr);
+ grpc_slice_buffer_move_first_no_ref(payload, payload->length, frame);
+}
diff --git a/src/core/ext/transport/chttp2/transport/frame_security.h b/src/core/ext/transport/chttp2/transport/frame_security.h
new file mode 100644
index 00000000000..ea6e81f9743
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_security.h
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+
+#ifndef GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SECURITY_H
+#define GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SECURITY_H
+
+#include
+#include
+#include
+
+#include "src/core/ext/transport/chttp2/transport/legacy_frame.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/slice/slice_buffer.h"
+#include "src/core/lib/transport/transport_framing_endpoint_extension.h"
+
+struct grpc_chttp2_security_frame_parser {
+ grpc_core::SliceBuffer payload;
+};
+
+void grpc_chttp2_security_frame_create(grpc_slice_buffer* payload,
+ uint32_t length,
+ grpc_slice_buffer* frame);
+
+absl::Status grpc_chttp2_security_frame_parser_begin_frame(
+ grpc_chttp2_security_frame_parser* parser);
+
+grpc_error_handle grpc_chttp2_security_frame_parser_parse(
+ void* parser, grpc_chttp2_transport* t, grpc_chttp2_stream* s,
+ const grpc_slice& slice, int is_last);
+
+#endif // GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SECURITY_H
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.cc b/src/core/ext/transport/chttp2/transport/http2_settings.cc
index 83bf6e5c5d8..1115fb9dfb5 100644
--- a/src/core/ext/transport/chttp2/transport/http2_settings.cc
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -58,6 +58,9 @@ void Http2Settings::Diff(
cb(kGrpcPreferredReceiveCryptoFrameSizeWireId,
preferred_receive_crypto_message_size_);
}
+ if (allow_security_frame_ != old.allow_security_frame_) {
+ cb(kGrpcAllowSecurityFrameWireId, allow_security_frame_);
+ }
}
std::string Http2Settings::WireIdToName(uint16_t wire_id) {
@@ -78,6 +81,8 @@ std::string Http2Settings::WireIdToName(uint16_t wire_id) {
return std::string(allow_true_binary_metadata_name());
case kGrpcPreferredReceiveCryptoFrameSizeWireId:
return std::string(preferred_receive_crypto_message_size_name());
+ case kGrpcAllowSecurityFrameWireId:
+ return std::string(allow_security_frame_name());
default:
return absl::StrCat("UNKNOWN (", wire_id, ")");
}
@@ -119,6 +124,10 @@ grpc_http2_error_code Http2Settings::Apply(uint16_t key, uint32_t value) {
Clamp(value, min_preferred_receive_crypto_message_size(),
max_preferred_receive_crypto_message_size());
break;
+ case kGrpcAllowSecurityFrameWireId:
+ if (value > 1) return GRPC_HTTP2_PROTOCOL_ERROR;
+ allow_security_frame_ = value != 0;
+ break;
}
return GRPC_HTTP2_NO_ERROR;
}
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.h b/src/core/ext/transport/chttp2/transport/http2_settings.h
index 44ed672d123..dc383ed5294 100644
--- a/src/core/ext/transport/chttp2/transport/http2_settings.h
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.h
@@ -42,6 +42,7 @@ class Http2Settings {
kMaxHeaderListSizeWireId = 6,
kGrpcAllowTrueBinaryMetadataWireId = 65027,
kGrpcPreferredReceiveCryptoFrameSizeWireId = 65028,
+ kGrpcAllowSecurityFrameWireId = 65029,
};
void Diff(bool is_first_send, const Http2Settings& old,
@@ -60,6 +61,7 @@ class Http2Settings {
bool allow_true_binary_metadata() const {
return allow_true_binary_metadata_;
}
+ bool allow_security_frame() const { return allow_security_frame_; }
void SetHeaderTableSize(uint32_t x) { header_table_size_ = x; }
void SetMaxConcurrentStreams(uint32_t x) { max_concurrent_streams_ = x; }
@@ -79,6 +81,7 @@ class Http2Settings {
Clamp(x, min_preferred_receive_crypto_message_size(),
max_preferred_receive_crypto_message_size());
}
+ void SetAllowSecurityFrame(bool x) { allow_security_frame_ = x; }
static absl::string_view header_table_size_name() {
return "HEADER_TABLE_SIZE";
@@ -100,6 +103,9 @@ class Http2Settings {
static absl::string_view preferred_receive_crypto_message_size_name() {
return "GRPC_PREFERRED_RECEIVE_MESSAGE_SIZE";
}
+ static absl::string_view allow_security_frame_name() {
+ return "GRPC_ALLOW_SECURITY_FRAME";
+ }
static uint32_t max_initial_window_size() { return 2147483647u; }
static uint32_t max_max_frame_size() { return 16777215u; }
@@ -120,7 +126,8 @@ class Http2Settings {
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_;
+ allow_true_binary_metadata_ == rhs.allow_true_binary_metadata_ &&
+ allow_security_frame_ == rhs.allow_security_frame_;
}
bool operator!=(const Http2Settings& rhs) const { return !operator==(rhs); }
@@ -134,6 +141,7 @@ class Http2Settings {
uint32_t preferred_receive_crypto_message_size_ = 0u;
bool enable_push_ = true;
bool allow_true_binary_metadata_ = false;
+ bool allow_security_frame_ = false;
};
class Http2SettingsManager {
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 6d9eb84d227..4db6642292a 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -45,6 +45,7 @@
#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
#include "src/core/ext/transport/chttp2/transport/frame_ping.h"
#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
+#include "src/core/ext/transport/chttp2/transport/frame_security.h"
#include "src/core/ext/transport/chttp2/transport/frame_settings.h"
#include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
@@ -405,6 +406,8 @@ struct grpc_chttp2_transport final : public grpc_core::FilterStackTransport,
} simple;
/// parser for goaway frames
grpc_chttp2_goaway_parser goaway_parser;
+ // parser for secure frames
+ grpc_chttp2_security_frame_parser security_frame_parser;
grpc_core::chttp2::TransportFlowControl flow_control;
/// initial window change. This is tracked as we parse settings frames from
diff --git a/src/core/ext/transport/chttp2/transport/legacy_frame.h b/src/core/ext/transport/chttp2/transport/legacy_frame.h
index f0a6e639d74..14371f49aa5 100644
--- a/src/core/ext/transport/chttp2/transport/legacy_frame.h
+++ b/src/core/ext/transport/chttp2/transport/legacy_frame.h
@@ -33,6 +33,7 @@ typedef struct grpc_chttp2_transport grpc_chttp2_transport;
#define GRPC_CHTTP2_FRAME_PING 6
#define GRPC_CHTTP2_FRAME_GOAWAY 7
#define GRPC_CHTTP2_FRAME_WINDOW_UPDATE 8
+#define GRPC_CHTTP2_FRAME_SECURITY 200
#define GRPC_CHTTP2_DATA_FLAG_END_STREAM 1
#define GRPC_CHTTP2_FLAG_ACK 1
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index f1c7e07a217..eb024e5b576 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -47,6 +47,7 @@
#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
#include "src/core/ext/transport/chttp2/transport/frame_ping.h"
#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
+#include "src/core/ext/transport/chttp2/transport/frame_security.h"
#include "src/core/ext/transport/chttp2/transport/frame_settings.h"
#include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
@@ -88,6 +89,7 @@ static grpc_error_handle init_window_update_frame_parser(
grpc_chttp2_transport* t);
static grpc_error_handle init_ping_parser(grpc_chttp2_transport* t);
static grpc_error_handle init_goaway_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_security_frame_parser(grpc_chttp2_transport* t);
static grpc_error_handle init_non_header_skip_frame_parser(
grpc_chttp2_transport* t);
@@ -194,6 +196,8 @@ std::string FrameTypeString(uint8_t frame_type, uint8_t flags) {
return MakeFrameTypeString("GOAWAY", flags, {});
case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
return MakeFrameTypeString("WINDOW_UPDATE", flags, {});
+ case GRPC_CHTTP2_FRAME_SECURITY:
+ return MakeFrameTypeString("SECURITY", flags, {});
default:
return MakeFrameTypeString(
absl::StrCat("UNKNOWN_FRAME_TYPE_", static_cast(frame_type)),
@@ -451,6 +455,14 @@ static grpc_error_handle init_frame_parser(grpc_chttp2_transport* t,
return init_ping_parser(t);
case GRPC_CHTTP2_FRAME_GOAWAY:
return init_goaway_parser(t);
+ case GRPC_CHTTP2_FRAME_SECURITY:
+ if (!t->settings.peer().allow_security_frame()) {
+ if (GRPC_TRACE_FLAG_ENABLED(http)) {
+ LOG(ERROR) << "Security frame received but not allowed, ignoring";
+ }
+ return init_non_header_skip_frame_parser(t);
+ }
+ return init_security_frame_parser(t);
default:
GRPC_TRACE_LOG(http, ERROR)
<< "Unknown frame type "
@@ -882,6 +894,16 @@ static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t) {
return absl::OkStatus();
}
+static grpc_error_handle init_security_frame_parser(grpc_chttp2_transport* t) {
+ grpc_error_handle err =
+ grpc_chttp2_security_frame_parser_begin_frame(&t->security_frame_parser);
+ if (!err.ok()) return err;
+ t->parser = grpc_chttp2_transport::Parser{
+ "security_frame", grpc_chttp2_security_frame_parser_parse,
+ &t->security_frame_parser};
+ return absl::OkStatus();
+}
+
static grpc_error_handle parse_frame_slice(grpc_chttp2_transport* t,
const grpc_slice& slice,
int is_last) {
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 8e5687f3941..b73b62761e7 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -69,6 +69,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
'src/core/ext/transport/chttp2/transport/frame_ping.cc',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.cc',
+ 'src/core/ext/transport/chttp2/transport/frame_security.cc',
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
diff --git a/test/core/bad_client/tests/simple_request.cc b/test/core/bad_client/tests/simple_request.cc
index 52db06cccb3..3b9b385a943 100644
--- a/test/core/bad_client/tests/simple_request.cc
+++ b/test/core/bad_client/tests/simple_request.cc
@@ -39,6 +39,26 @@
"\x10\x02te\x08trailers" \
"\x10\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)"
+#define ONE_SETTING_HDR \
+ "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
+ "\x00\x00\x06\x04\x00\x00\x00\x00\x00" /* settings frame */
+
+#define USUAL_HDR \
+ "\x00\x00\xc9\x01\x04\x00\x00\x00\x01" /* headers: generated from \
+ simple_request.headers in this \
+ directory */ \
+ "\x10\x05:path\x08/foo/bar" \
+ "\x10\x07:scheme\x04http" \
+ "\x10\x07:method\x04POST" \
+ "\x10\x0a:authority\x09localhost" \
+ "\x10\x0c" \
+ "content-type\x10" \
+ "application/grpc" \
+ "\x10\x14grpc-accept-encoding\x15" \
+ "deflate,identity,gzip" \
+ "\x10\x02te\x08trailers" \
+ "\x10\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)"
+
#define PFX_STR_UNUSUAL \
"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
"\x00\x00\x00\x04\x00\x00\x00\x00\x00" /* settings frame */ \
@@ -219,7 +239,6 @@ int main(int argc, char** argv) {
"\x00\x00\x05\x00\x00\x00\x00\x00\x01"
"\x34\x00\x00\x00\x00",
0);
-
// push a data frame with bad flags
GRPC_RUN_BAD_CLIENT_TEST(verifier, nullptr,
PFX_STR "\x00\x00\x00\x00\x02\x00\x00\x00\x01", 0);
@@ -235,6 +254,22 @@ int main(int argc, char** argv) {
"\x00\x00\x04\x08\x00\x00\x00\x00\x01"
"\x00\x00\x00\x00",
0);
+ // push a valid secure frame with payload "hello" and setting
+ // `allow_security_frame` enabled, frame should be parsed
+ GRPC_RUN_BAD_CLIENT_TEST(
+ verifier, nullptr,
+ ONE_SETTING_HDR
+ "\xFE\x05\x00\x00\x00\x01" USUAL_HDR
+ "\x00\x00\x05\xC8\x00\x00\x00\x00\x00\x68\x65\x6C\x6C\x6F",
+ 0);
+ // push a valid secure frame with payload "hello" and setting
+ // `allow_security_frame` disabled, frame should be ignored
+ GRPC_RUN_BAD_CLIENT_TEST(
+ VerifyRpcDoesNotGetCanceled, nullptr,
+ ONE_SETTING_HDR
+ "\xFE\x05\x00\x00\x00\x00" USUAL_HDR
+ "\x00\x00\x05\xC8\x00\x00\x00\x00\x00\x68\x65\x6C\x6C\x6F",
+ 0);
// push a short goaway
GRPC_RUN_BAD_CLIENT_TEST(failure_verifier, nullptr,
PFX_STR "\x00\x00\x04\x07\x00\x00\x00\x00\x00", 0);
diff --git a/test/core/end2end/fuzzers/fuzzer_input.proto b/test/core/end2end/fuzzers/fuzzer_input.proto
index 32b1c5d4436..0cab21cb4e5 100644
--- a/test/core/end2end/fuzzers/fuzzer_input.proto
+++ b/test/core/end2end/fuzzers/fuzzer_input.proto
@@ -121,6 +121,10 @@ message H2WindowUpdateFrame {
uint32 increment = 2;
}
+message H2SecurityFrame {
+ bytes payload = 1;
+}
+
message H2ClientPrefix {}
message ChaoticGoodServerFragment {
@@ -202,6 +206,7 @@ message InputSegment {
uint32 repeated_zeros = 12;
ChaoticGoodFrame chaotic_good = 13;
FakeTransportFrame fake_transport_frame = 14;
+ H2SecurityFrame security_frame = 15;
}
}
diff --git a/test/core/end2end/fuzzers/network_input.cc b/test/core/end2end/fuzzers/network_input.cc
index 6a91a74d9ca..c86b7c221fb 100644
--- a/test/core/end2end/fuzzers/network_input.cc
+++ b/test/core/end2end/fuzzers/network_input.cc
@@ -326,6 +326,9 @@ grpc_slice SliceFromSegment(const fuzzer_input::InputSegment& segment) {
segment.window_update().stream_id(),
segment.window_update().increment(),
});
+ case fuzzer_input::InputSegment::kSecurityFrame:
+ return SliceFromH2Frame(Http2SecurityFrame{
+ SliceBufferFromBytes(segment.security_frame().payload())});
case fuzzer_input::InputSegment::kClientPrefix:
return grpc_slice_from_static_string("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n");
case fuzzer_input::InputSegment::kRepeatedZeros: {
diff --git a/test/core/transport/chttp2/frame_test.cc b/test/core/transport/chttp2/frame_test.cc
index 456d8a01af4..f8761ccf68d 100644
--- a/test/core/transport/chttp2/frame_test.cc
+++ b/test/core/transport/chttp2/frame_test.cc
@@ -162,6 +162,8 @@ TEST(Frame, Serialization) {
0x0b, 'h', 'e', 'l', 'l', 'o'));
EXPECT_EQ(Serialize(Http2WindowUpdateFrame{1, 0x12345678}),
ByteVec(0, 0, 4, 8, 0, 0, 0, 0, 1, 0x12, 0x34, 0x56, 0x78));
+ EXPECT_EQ(Serialize(Http2SecurityFrame{SliceBufferFromString("hello")}),
+ ByteVec(0, 0, 5, 200, 0, 0, 0, 0, 0, 'h', 'e', 'l', 'l', 'o'));
}
TEST(Frame, Parse) {
@@ -215,6 +217,8 @@ TEST(Frame, Parse) {
Slice::FromCopiedString("hello")}));
EXPECT_EQ(ParseFrame(0, 0, 4, 8, 0, 0, 0, 0, 1, 0x12, 0x34, 0x56, 0x78),
Http2Frame(Http2WindowUpdateFrame{1, 0x12345678}));
+ EXPECT_EQ(ParseFrame(0, 0, 5, 200, 0, 0, 0, 0, 0, 'h', 'e', 'l', 'l', 'o'),
+ Http2Frame(Http2SecurityFrame{SliceBufferFromString("hello")}));
}
TEST(Frame, ParsePadded) {
diff --git a/test/core/transport/chttp2/http2_settings_test.cc b/test/core/transport/chttp2/http2_settings_test.cc
index 776a131be4d..d11db9593f9 100644
--- a/test/core/transport/chttp2/http2_settings_test.cc
+++ b/test/core/transport/chttp2/http2_settings_test.cc
@@ -29,6 +29,7 @@ TEST(Http2SettingsTest, CanSetAndRetrieveSettings) {
settings.SetMaxHeaderListSize(6);
settings.SetAllowTrueBinaryMetadata(true);
settings.SetPreferredReceiveCryptoMessageSize(77777);
+ settings.SetAllowSecurityFrame(true);
EXPECT_EQ(settings.header_table_size(), 1u);
EXPECT_EQ(settings.enable_push(), true);
EXPECT_EQ(settings.max_concurrent_streams(), 3u);
@@ -37,6 +38,7 @@ TEST(Http2SettingsTest, CanSetAndRetrieveSettings) {
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);
+ EXPECT_EQ(settings.allow_security_frame(), true);
settings.SetHeaderTableSize(10);
settings.SetEnablePush(false);
settings.SetMaxConcurrentStreams(30);
@@ -45,6 +47,7 @@ TEST(Http2SettingsTest, CanSetAndRetrieveSettings) {
settings.SetMaxHeaderListSize(60);
settings.SetAllowTrueBinaryMetadata(false);
settings.SetPreferredReceiveCryptoMessageSize(70000);
+ settings.SetAllowSecurityFrame(false);
EXPECT_EQ(settings.header_table_size(), 10u);
EXPECT_EQ(settings.enable_push(), false);
EXPECT_EQ(settings.max_concurrent_streams(), 30u);
@@ -53,6 +56,7 @@ TEST(Http2SettingsTest, CanSetAndRetrieveSettings) {
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);
+ EXPECT_EQ(settings.allow_security_frame(), false);
}
TEST(Http2SettingsTest, InitialWindowSizeLimits) {
@@ -269,6 +273,32 @@ TEST(Http2SettingsTest, DiffOnSettingsWithEightValuesSet) {
KeyValue{65027, 1}, KeyValue{65028, 77777}));
}
+TEST(Http2SettingsTest, DiffOnSettingsWithNineValuesSet) {
+ 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);
+ settings1.SetAllowSecurityFrame(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},
+ KeyValue{65028, 77777}, KeyValue{65029, 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},
+ KeyValue{65028, 77777}, KeyValue{65029, 1}));
+}
+
TEST(Http2SettingsTest, ChangingHeaderTableSizeChangesEquality) {
Http2Settings settings1;
Http2Settings settings2;
@@ -358,6 +388,17 @@ TEST(Http2SettingsTest,
EXPECT_NE(settings1, settings2);
}
+TEST(Http2SettingsTest, ChangingAllowSecurityFrameChangesEquality) {
+ Http2Settings settings1;
+ Http2Settings settings2;
+ settings1.SetAllowSecurityFrame(true);
+ EXPECT_NE(settings1, settings2);
+ settings2.SetAllowSecurityFrame(true);
+ EXPECT_EQ(settings1, settings2);
+ settings2.SetAllowSecurityFrame(false);
+ EXPECT_NE(settings1, settings2);
+}
+
TEST(Http2SettingsTest, WireIdToNameWorks) {
EXPECT_EQ(Http2Settings::WireIdToName(1), "HEADER_TABLE_SIZE");
EXPECT_EQ(Http2Settings::WireIdToName(2), "ENABLE_PUSH");
@@ -369,7 +410,8 @@ TEST(Http2SettingsTest, WireIdToNameWorks) {
"GRPC_ALLOW_TRUE_BINARY_METADATA");
EXPECT_EQ(Http2Settings::WireIdToName(65028),
"GRPC_PREFERRED_RECEIVE_MESSAGE_SIZE");
- EXPECT_EQ(Http2Settings::WireIdToName(65029), "UNKNOWN (65029)");
+ EXPECT_EQ(Http2Settings::WireIdToName(65029), "GRPC_ALLOW_SECURITY_FRAME");
+ EXPECT_EQ(Http2Settings::WireIdToName(65030), "UNKNOWN (65030)");
}
TEST(Http2SettingsTest, ApplyHeaderTableSizeWorks) {
@@ -442,6 +484,15 @@ TEST(Http2SettingsTest, ApplyPreferredReceiveCryptoMessageSizeWorks) {
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu);
}
+TEST(Http2SettingsTest, ApplyAllowSecurityFrameWorks) {
+ Http2Settings settings;
+ EXPECT_EQ(settings.Apply(65029, 0), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.allow_security_frame(), false);
+ EXPECT_EQ(settings.Apply(65029, 1), GRPC_HTTP2_NO_ERROR);
+ EXPECT_EQ(settings.allow_security_frame(), true);
+ EXPECT_EQ(settings.Apply(65029, 2), GRPC_HTTP2_PROTOCOL_ERROR);
+}
+
namespace {
MATCHER_P(SettingsFrame, settings, "") {
if (!arg.has_value()) {
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index b205ff8cfda..5cce618c9f1 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1199,6 +1199,8 @@ src/core/ext/transport/chttp2/transport/frame_ping.cc \
src/core/ext/transport/chttp2/transport/frame_ping.h \
src/core/ext/transport/chttp2/transport/frame_rst_stream.cc \
src/core/ext/transport/chttp2/transport/frame_rst_stream.h \
+src/core/ext/transport/chttp2/transport/frame_security.cc \
+src/core/ext/transport/chttp2/transport/frame_security.h \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_settings.h \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index ab3e5dc3db6..8f03a2b34df 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1006,6 +1006,8 @@ src/core/ext/transport/chttp2/transport/frame_ping.cc \
src/core/ext/transport/chttp2/transport/frame_ping.h \
src/core/ext/transport/chttp2/transport/frame_rst_stream.cc \
src/core/ext/transport/chttp2/transport/frame_rst_stream.h \
+src/core/ext/transport/chttp2/transport/frame_security.cc \
+src/core/ext/transport/chttp2/transport/frame_security.h \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_settings.h \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \