Support WebTransport negotiation in HTTP/3.
PiperOrigin-RevId: 360499528
Change-Id: I1ca3ee42d10991704994f14fb009a56b91e3e63c
diff --git a/quic/core/http/http_constants.cc b/quic/core/http/http_constants.cc
index dbf49df..f3ed523 100644
--- a/quic/core/http/http_constants.cc
+++ b/quic/core/http/http_constants.cc
@@ -18,6 +18,7 @@
RETURN_STRING_LITERAL(SETTINGS_MAX_FIELD_SECTION_SIZE);
RETURN_STRING_LITERAL(SETTINGS_QPACK_BLOCKED_STREAMS);
RETURN_STRING_LITERAL(SETTINGS_H3_DATAGRAM);
+ RETURN_STRING_LITERAL(SETTINGS_WEBTRANS_DRAFT00);
}
return absl::StrCat("UNSUPPORTED_SETTINGS_TYPE(", identifier, ")");
}
diff --git a/quic/core/http/http_constants.h b/quic/core/http/http_constants.h
index 9757e72..a5409b5 100644
--- a/quic/core/http/http_constants.h
+++ b/quic/core/http/http_constants.h
@@ -38,6 +38,8 @@
SETTINGS_QPACK_BLOCKED_STREAMS = 0x07,
// draft-ietf-masque-h3-datagram.
SETTINGS_H3_DATAGRAM = 0x276,
+ // draft-ietf-webtrans-http3-00
+ SETTINGS_WEBTRANS_DRAFT00 = 0x2b603742,
};
// Returns HTTP/3 SETTINGS identifier as a string.
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 3bce452..42ae554 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -570,6 +570,9 @@
QUIC_RELOADABLE_FLAG_COUNT(quic_h3_datagram);
settings_.values[SETTINGS_H3_DATAGRAM] = 1;
}
+ if (WillNegotiateWebTransport()) {
+ settings_.values[SETTINGS_WEBTRANS_DRAFT00] = 1;
+ }
}
void QuicSpdySession::OnDecoderStreamError(QuicErrorCode error_code,
@@ -948,6 +951,15 @@
}
}
+bool QuicSpdySession::ShouldNegotiateWebTransport() {
+ return false;
+}
+
+bool QuicSpdySession::WillNegotiateWebTransport() {
+ return GetQuicReloadableFlag(quic_h3_datagram) && version().UsesHttp3() &&
+ ShouldNegotiateWebTransport();
+}
+
// True if there are open HTTP requests.
bool QuicSpdySession::ShouldKeepConnectionAlive() const {
QUICHE_DCHECK(VersionUsesHttp3(transport_version()) ||
@@ -1176,6 +1188,9 @@
h3_datagram_supported_ = !!value;
break;
}
+ case SETTINGS_WEBTRANS_DRAFT00:
+ peer_supports_webtransport_ = true;
+ break;
default:
QUIC_DVLOG(1) << ENDPOINT << "Unknown setting identifier " << id
<< " received with value " << value;
@@ -1738,6 +1753,11 @@
it->second->OnHttp3Datagram(flow_id, payload);
}
+bool QuicSpdySession::SupportsWebTransport() {
+ return WillNegotiateWebTransport() && h3_datagram_supported_ &&
+ peer_supports_webtransport_;
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 6a47b5d..157b035 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -448,6 +448,9 @@
// Override from QuicSession to support HTTP/3 datagrams.
void OnMessageReceived(absl::string_view message) override;
+ // Indicates whether the HTTP/3 session supports WebTransport.
+ bool SupportsWebTransport();
+
protected:
// Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
// CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
@@ -467,6 +470,11 @@
virtual bool ShouldCreateOutgoingBidirectionalStream() = 0;
virtual bool ShouldCreateOutgoingUnidirectionalStream() = 0;
+ // Indicates whether the underlying backend can accept and process
+ // WebTransport sessions over HTTP/3.
+ virtual bool ShouldNegotiateWebTransport();
+ bool WillNegotiateWebTransport();
+
// Returns true if there are open HTTP requests.
bool ShouldKeepConnectionAlive() const override;
@@ -658,6 +666,9 @@
// Whether both this endpoint and our peer support HTTP/3 datagrams.
bool h3_datagram_supported_ = false;
+ // Whether the peer has indicated WebTransport support.
+ bool peer_supports_webtransport_ = false;
+
absl::flat_hash_map<QuicDatagramFlowId, Http3DatagramVisitor*>
h3_datagram_registrations_;
};
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 2cf98ab..7e34ac4 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -353,6 +353,9 @@
GetEncryptionLevelToSendApplicationData());
}
+ bool ShouldNegotiateWebTransport() override { return supports_webtransport_; }
+ void set_supports_webtransport(bool value) { supports_webtransport_ = value; }
+
MOCK_METHOD(void, OnAcceptChFrame, (const AcceptChFrame&), (override));
using QuicSession::closed_streams;
@@ -364,6 +367,7 @@
StrictMock<TestCryptoStream> crypto_stream_;
bool writev_consumes_all_data_;
+ bool supports_webtransport_ = false;
};
class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
@@ -3388,6 +3392,36 @@
MESSAGE_STATUS_SUCCESS);
}
+TEST_P(QuicSpdySessionTestClient, WebTransportSetting) {
+ if (!version().UsesHttp3()) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_h3_datagram, true);
+ session_.set_supports_webtransport(true);
+
+ EXPECT_FALSE(session_.SupportsWebTransport());
+
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ // Note that this does not actually fill out correct settings because the
+ // settings are filled in at the construction time.
+ EXPECT_CALL(debug_visitor, OnSettingsFrameSent(_));
+ session_.set_debug_visitor(&debug_visitor);
+ CompleteHandshake();
+
+ SettingsFrame server_settings;
+ server_settings.values[SETTINGS_H3_DATAGRAM] = 1;
+ server_settings.values[SETTINGS_WEBTRANS_DRAFT00] = 1;
+ std::string data =
+ std::string(1, kControlStream) + EncodeSettings(server_settings);
+ QuicStreamId stream_id =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 3);
+ QuicStreamFrame frame(stream_id, /*fin=*/false, /*offset=*/0, data);
+ EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(stream_id));
+ EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(server_settings));
+ session_.OnStreamFrame(frame);
+ EXPECT_TRUE(session_.SupportsWebTransport());
+}
+
} // namespace
} // namespace test
} // namespace quic