Add support for HTTP/3 datagram SETTING
The flag is marked as enabling_blocked_by until we fully support draft-ietf-masque-h3-datagram.
Protected by FLAGS_quic_reloadable_flag_quic_h3_datagram.
PiperOrigin-RevId: 359679117
Change-Id: Ica032348a93be9bafc75307c9d1e1e936c92cb4b
diff --git a/quic/core/http/http_constants.cc b/quic/core/http/http_constants.cc
index b3262d2..d7281a3 100644
--- a/quic/core/http/http_constants.cc
+++ b/quic/core/http/http_constants.cc
@@ -17,6 +17,7 @@
RETURN_STRING_LITERAL(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
RETURN_STRING_LITERAL(SETTINGS_MAX_FIELD_SECTION_SIZE);
RETURN_STRING_LITERAL(SETTINGS_QPACK_BLOCKED_STREAMS);
+ RETURN_STRING_LITERAL(SETTINGS_H3_DATAGRAM);
}
return absl::StrCat("UNSUPPORTED_SETTINGS_TYPE(", identifier, ")");
}
diff --git a/quic/core/http/http_constants.h b/quic/core/http/http_constants.h
index 8c68e74..27ce56b 100644
--- a/quic/core/http/http_constants.h
+++ b/quic/core/http/http_constants.h
@@ -34,6 +34,8 @@
// Same value as spdy::SETTINGS_MAX_HEADER_LIST_SIZE.
SETTINGS_MAX_FIELD_SECTION_SIZE = 0x06,
SETTINGS_QPACK_BLOCKED_STREAMS = 0x07,
+ // draft-ietf-masque-h3-datagram.
+ SETTINGS_H3_DATAGRAM = 0x276,
};
// Returns HTTP/3 SETTINGS identifier as a string.
diff --git a/quic/core/http/quic_send_control_stream_test.cc b/quic/core/http/quic_send_control_stream_test.cc
index fe84973..d1be0df 100644
--- a/quic/core/http/quic_send_control_stream_test.cc
+++ b/quic/core/http/quic_send_control_stream_test.cc
@@ -14,6 +14,7 @@
#include "quic/test_tools/quic_spdy_session_peer.h"
#include "quic/test_tools/quic_test_utils.h"
#include "common/platform/api/quiche_text_utils.h"
+#include "common/test_tools/quiche_test_utils.h"
namespace quic {
namespace test {
@@ -133,6 +134,25 @@
"4040" // 0x40 as the reserved frame type
"01" // 1 byte frame length
"61"); // payload "a"
+ if (GetQuicReloadableFlag(quic_h3_datagram)) {
+ expected_write_data = absl::HexStringToBytes(
+ "00" // stream type: control stream
+ "04" // frame type: SETTINGS frame
+ "0e" // frame length
+ "01" // SETTINGS_QPACK_MAX_TABLE_CAPACITY
+ "40ff" // 255
+ "06" // SETTINGS_MAX_HEADER_LIST_SIZE
+ "4400" // 1024
+ "07" // SETTINGS_QPACK_BLOCKED_STREAMS
+ "10" // 16
+ "4040" // 0x40 as the reserved settings id
+ "14" // 20
+ "4276" // SETTINGS_H3_DATAGRAM
+ "01" // 1
+ "4040" // 0x40 as the reserved frame type
+ "01" // 1 byte frame length
+ "61"); // payload "a"
+ }
auto buffer = std::make_unique<char[]>(expected_write_data.size());
QuicDataWriter writer(expected_write_data.size(), buffer.get());
@@ -158,8 +178,9 @@
.WillOnce(Invoke(save_write_data));
send_control_stream_->MaybeSendSettingsFrame();
- EXPECT_EQ(expected_write_data,
- absl::string_view(writer.data(), writer.length()));
+ quiche::test::CompareCharArraysWithHexError(
+ "settings", writer.data(), writer.length(), expected_write_data.data(),
+ expected_write_data.length());
}
TEST_P(QuicSendControlStreamTest, WriteSettingsOnlyOnce) {
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 346add8..8418bb2 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -569,6 +569,10 @@
qpack_maximum_blocked_streams_;
settings_.values[SETTINGS_MAX_FIELD_SECTION_SIZE] =
max_inbound_header_list_size_;
+ if (GetQuicReloadableFlag(quic_h3_datagram) && version().UsesHttp3()) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_h3_datagram);
+ settings_.values[SETTINGS_H3_DATAGRAM] = 1;
+ }
}
void QuicSpdySession::OnDecoderStreamError(QuicErrorCode error_code,
@@ -1204,6 +1208,26 @@
absl::StrCat("received HTTP/2 specific setting in HTTP/3 session: ",
id));
return false;
+ case SETTINGS_H3_DATAGRAM: {
+ if (!GetQuicReloadableFlag(quic_h3_datagram)) {
+ break;
+ }
+ QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_H3_DATAGRAM received with value "
+ << value;
+ if (!version().UsesHttp3()) {
+ break;
+ }
+ if (value != 0 && value != 1) {
+ std::string error_details = absl::StrCat(
+ "received SETTINGS_H3_DATAGRAM with invalid value ", value);
+ QUIC_PEER_BUG << ENDPOINT << error_details;
+ CloseConnectionWithDetails(QUIC_HTTP_RECEIVE_SPDY_SETTING,
+ error_details);
+ return false;
+ }
+ h3_datagram_supported_ = !!value;
+ 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 ad5fa02..7e13afa 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -420,6 +420,10 @@
// Generates a new HTTP/3 datagram flow ID.
QuicDatagramFlowId GetNextDatagramFlowId();
+ // Whether HTTP/3 datagrams are supported on this session, based on received
+ // SETTINGS.
+ bool h3_datagram_supported() const { return h3_datagram_supported_; }
+
protected:
// Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
// CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
@@ -629,6 +633,9 @@
// Value of the smallest unused HTTP/3 datagram flow ID that this endpoint's
// datagram flow ID allocation service will use next.
QuicDatagramFlowId next_available_datagram_flow_id_;
+
+ // Whether both this endpoint and our peer support HTTP/3 datagrams.
+ bool h3_datagram_supported_ = false;
};
} // namespace quic
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index d173917..848f215 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -3397,6 +3397,29 @@
EXPECT_EQ(session_.GetNextDatagramFlowId(), 7u);
}
+TEST_P(QuicSpdySessionTestClient, H3DatagramSetting) {
+ if (!version().UsesHttp3()) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_h3_datagram, true);
+ // HTTP/3 datagrams aren't supported before SETTINGS are received.
+ EXPECT_FALSE(session_.h3_datagram_supported());
+ // Receive SETTINGS.
+ SettingsFrame settings;
+ settings.values[SETTINGS_H3_DATAGRAM] = 1;
+ std::string data = std::string(1, kControlStream) + EncodeSettings(settings);
+ QuicStreamId stream_id =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 3);
+ QuicStreamFrame frame(stream_id, /*fin=*/false, /*offset=*/0, data);
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_.set_debug_visitor(&debug_visitor);
+ EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(stream_id));
+ EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(settings));
+ session_.OnStreamFrame(frame);
+ // HTTP/3 datagrams are now supported.
+ EXPECT_TRUE(session_.h3_datagram_supported());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index a3bc225..a9fa0cf 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -46,6 +46,7 @@
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_on_stream_reset, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_willing_and_able_to_write2, true)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_goaway_with_max_stream_id, true)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_h3_datagram, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_parse_accept_ch_frame, true)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_require_handshake_confirmation, false)