Treat HTTP/2 specific SETTING identifiers as errors in HTTP/3.
This is specified in https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-30#appendix-A.3
Protected by quic_reloadable_flag_quic_reject_spdy_settings.
PiperOrigin-RevId: 333116208
Change-Id: I946f35ec70c490efb8ca10dbfb1bf9799240daf8
diff --git a/quic/core/http/quic_receive_control_stream_test.cc b/quic/core/http/quic_receive_control_stream_test.cc
index af80654..5ee5f50 100644
--- a/quic/core/http/quic_receive_control_stream_test.cc
+++ b/quic/core/http/quic_receive_control_stream_test.cc
@@ -156,7 +156,7 @@
TEST_P(QuicReceiveControlStreamTest, ReceiveSettings) {
SettingsFrame settings;
- settings.values[3] = 2;
+ settings.values[10] = 2;
settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] = 12;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 37;
@@ -223,7 +223,7 @@
TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsFragments) {
SettingsFrame settings;
- settings.values[3] = 2;
+ settings.values[10] = 2;
settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
std::string data = EncodeSettings(settings);
std::string data1 = data.substr(0, 1);
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 50be81d..7065c3b 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -404,7 +404,8 @@
server_push_enabled_(true),
ietf_server_push_enabled_(
GetQuicFlag(FLAGS_quic_enable_http3_server_push)),
- http3_max_push_id_sent_(false) {
+ http3_max_push_id_sent_(false),
+ reject_spdy_settings_(GetQuicReloadableFlag(quic_reject_spdy_settings)) {
h2_deframer_.set_visitor(spdy_framer_visitor_.get());
h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
@@ -970,6 +971,9 @@
bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
if (VersionUsesHttp3(transport_version())) {
+ if (reject_spdy_settings_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_reject_spdy_settings);
+ }
// SETTINGS frame received on the control stream.
switch (id) {
case SETTINGS_QPACK_MAX_TABLE_CAPACITY: {
@@ -1044,6 +1048,21 @@
}
break;
}
+ case spdy::SETTINGS_ENABLE_PUSH:
+ QUIC_FALLTHROUGH_INTENDED;
+ case spdy::SETTINGS_MAX_CONCURRENT_STREAMS:
+ QUIC_FALLTHROUGH_INTENDED;
+ case spdy::SETTINGS_INITIAL_WINDOW_SIZE:
+ QUIC_FALLTHROUGH_INTENDED;
+ case spdy::SETTINGS_MAX_FRAME_SIZE:
+ if (reject_spdy_settings_) {
+ CloseConnectionWithDetails(
+ QUIC_HTTP_RECEIVE_SPDY_SETTING,
+ quiche::QuicheStrCat(
+ "received HTTP/2 specific setting in HTTP/3 session: ", id));
+ return false;
+ }
+ break;
default:
QUIC_DVLOG(1) << ENDPOINT << "Unknown setting identifier " << id
<< " received with value " << value;
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 0a71e48..db8fc6b 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -598,6 +598,9 @@
// has been sent, in which case |max_push_id_| has the value sent in the most
// recent MAX_PUSH_ID frame. Once true, never goes back to false.
bool http3_max_push_id_sent_;
+
+ // Latched value of reloadable flag quic_reject_spdy_settings.
+ const bool reject_spdy_settings_;
};
} // namespace quic
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 7ce419a..b0e2c0c 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -2447,7 +2447,7 @@
GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3);
char type[] = {kControlStream};
SettingsFrame settings;
- settings.values[3] = 2;
+ settings.values[10] = 2;
settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
std::string data = EncodeSettings(settings);
@@ -3104,6 +3104,25 @@
CompleteHandshake();
}
+TEST_P(QuicSpdySessionTestClient, ReceiveSpdySettingInHttp3) {
+ if (!VersionUsesHttp3(transport_version()) ||
+ !GetQuicReloadableFlag(quic_reject_spdy_settings)) {
+ return;
+ }
+
+ SettingsFrame frame;
+ frame.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5;
+ // https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-30#appendix-A.3
+ // specifies the presence of HTTP/2 setting as error.
+ frame.values[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 100;
+
+ CompleteHandshake();
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_HTTP_RECEIVE_SPDY_SETTING, _, _));
+ session_.OnSettingsFrame(frame);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_error_codes.cc b/quic/core/quic_error_codes.cc
index 304f2f2..54e4569 100644
--- a/quic/core/quic_error_codes.cc
+++ b/quic/core/quic_error_codes.cc
@@ -208,6 +208,7 @@
RETURN_STRING_LITERAL(QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH);
RETURN_STRING_LITERAL(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID);
RETURN_STRING_LITERAL(QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS);
+ RETURN_STRING_LITERAL(QUIC_HTTP_RECEIVE_SPDY_SETTING);
RETURN_STRING_LITERAL(QUIC_HPACK_INDEX_VARINT_ERROR);
RETURN_STRING_LITERAL(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR);
RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR);
@@ -586,6 +587,8 @@
return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR)};
case QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS:
return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR)};
+ case QUIC_HTTP_RECEIVE_SPDY_SETTING:
+ return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR)};
case QUIC_HPACK_INDEX_VARINT_ERROR:
return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR:
diff --git a/quic/core/quic_error_codes.h b/quic/core/quic_error_codes.h
index efeaa7c..0a415ef 100644
--- a/quic/core/quic_error_codes.h
+++ b/quic/core/quic_error_codes.h
@@ -442,6 +442,9 @@
QUIC_HTTP_GOAWAY_INVALID_STREAM_ID = 166,
// Received GOAWAY frame with ID that is greater than previously received ID.
QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS = 167,
+ // HTTP/3 session received SETTINGS frame which contains HTTP/2 specific
+ // settings.
+ QUIC_HTTP_RECEIVE_SPDY_SETTING = 169,
// HPACK header block decoding errors.
// Index varint beyond implementation limit.
@@ -493,7 +496,7 @@
QUIC_SILENT_IDLE_TIMEOUT = 168,
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 169,
+ QUIC_LAST_ERROR = 170,
};
// QuicErrorCodes is encoded as four octets on-the-wire when doing Google QUIC,
// or a varint62 when doing IETF QUIC. Ensure that its value does not exceed