Provide a way to get max datagram size for a WebTransport session.
This gives a conservative estimate (i.e. assumes largest possible packet number, etc), but it should work well for the Web API where the value is retrieved in a different process.
PiperOrigin-RevId: 400326269
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc
index e9df950..4b7ea68 100644
--- a/quic/core/http/quic_spdy_stream.cc
+++ b/quic/core/http/quic_spdy_stream.cc
@@ -1640,6 +1640,55 @@
HandleReceivedDatagram(context_id, payload);
}
+QuicByteCount QuicSpdyStream::GetMaxDatagramSize(
+ absl::optional<QuicDatagramContextId> context_id) const {
+ QuicByteCount prefix_size = 0;
+ switch (spdy_session_->http_datagram_support()) {
+ case HttpDatagramSupport::kDraft00:
+ if (!datagram_flow_id_.has_value()) {
+ QUIC_BUG(GetMaxDatagramSize with no flow ID)
+ << "GetMaxDatagramSize() called when no flow ID available";
+ break;
+ }
+ prefix_size = QuicDataWriter::GetVarInt62Len(*datagram_flow_id_);
+ break;
+ case HttpDatagramSupport::kDraft04:
+ prefix_size =
+ QuicDataWriter::GetVarInt62Len(id() / kHttpDatagramStreamIdDivisor);
+ break;
+ case HttpDatagramSupport::kNone:
+ case HttpDatagramSupport::kDraft00And04:
+ QUIC_BUG(GetMaxDatagramSize called with no datagram support)
+ << "GetMaxDatagramSize() called when no HTTP/3 datagram support has "
+ "been negotiated. Support value: "
+ << spdy_session_->http_datagram_support();
+ break;
+ }
+ // If the logic above fails, use the largest possible value as the safe one.
+ if (prefix_size == 0) {
+ prefix_size = 8;
+ }
+
+ if (context_id.has_value()) {
+ QUIC_BUG_IF(
+ context_id with draft00 in GetMaxDatagramSize,
+ spdy_session_->http_datagram_support() == HttpDatagramSupport::kDraft00)
+ << "GetMaxDatagramSize() called with a context ID specified, but "
+ "draft00 does not support contexts.";
+ prefix_size += QuicDataWriter::GetVarInt62Len(*context_id);
+ }
+
+ QuicByteCount max_datagram_size =
+ session()->GetGuaranteedLargestMessagePayload();
+ if (max_datagram_size < prefix_size) {
+ QUIC_BUG(max_datagram_size smaller than prefix_size)
+ << "GetGuaranteedLargestMessagePayload() returned a datagram size that "
+ "is not sufficient to fit stream and/or context ID into it.";
+ return 0;
+ }
+ return max_datagram_size - prefix_size;
+}
+
void QuicSpdyStream::RegisterHttp3DatagramFlowId(QuicDatagramStreamId flow_id) {
datagram_flow_id_ = flow_id;
spdy_session_->RegisterHttp3DatagramFlowId(datagram_flow_id_.value(), id());
diff --git a/quic/core/http/quic_spdy_stream.h b/quic/core/http/quic_spdy_stream.h
index 21dab65..5bdc09e 100644
--- a/quic/core/http/quic_spdy_stream.h
+++ b/quic/core/http/quic_spdy_stream.h
@@ -339,6 +339,9 @@
void RegisterHttp3DatagramFlowId(QuicDatagramStreamId flow_id);
+ QuicByteCount GetMaxDatagramSize(
+ absl::optional<QuicDatagramContextId> context_id) const;
+
protected:
// Called when the received headers are too large. By default this will
// reset the stream.
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index 594b92c..04343e0 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -3370,6 +3370,22 @@
MESSAGE_STATUS_SUCCESS);
}
+TEST_P(QuicSpdyStreamTest, GetMaxDatagramSize) {
+ if (!UsesHttp3()) {
+ return;
+ }
+ Initialize(kShouldProcessData);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft04);
+
+ QuicByteCount size = stream_->GetMaxDatagramSize(absl::nullopt);
+ QuicByteCount size_with_context =
+ stream_->GetMaxDatagramSize(/*context_id=*/1);
+ EXPECT_GT(size, 512u);
+ EXPECT_EQ(size - 1, size_with_context);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/http/web_transport_http3.cc b/quic/core/http/web_transport_http3.cc
index 9f5dd32..a575489 100644
--- a/quic/core/http/web_transport_http3.cc
+++ b/quic/core/http/web_transport_http3.cc
@@ -187,6 +187,10 @@
context_id_, absl::string_view(datagram.data(), datagram.length()));
}
+QuicByteCount WebTransportHttp3::GetMaxDatagramSize() const {
+ return connect_stream_->GetMaxDatagramSize(context_id_);
+}
+
void WebTransportHttp3::SetDatagramMaxTimeInQueue(
QuicTime::Delta max_time_in_queue) {
connect_stream_->SetMaxDatagramTimeInQueue(max_time_in_queue);
diff --git a/quic/core/http/web_transport_http3.h b/quic/core/http/web_transport_http3.h
index f2fdb5a..35f2726 100644
--- a/quic/core/http/web_transport_http3.h
+++ b/quic/core/http/web_transport_http3.h
@@ -68,6 +68,7 @@
WebTransportStream* OpenOutgoingUnidirectionalStream() override;
MessageStatus SendOrQueueDatagram(QuicMemSlice datagram) override;
+ QuicByteCount GetMaxDatagramSize() const override;
void SetDatagramMaxTimeInQueue(QuicTime::Delta max_time_in_queue) override;
// From QuicSpdyStream::Http3DatagramVisitor.
diff --git a/quic/core/web_transport_interface.h b/quic/core/web_transport_interface.h
index 8a1de3e..1240291 100644
--- a/quic/core/web_transport_interface.h
+++ b/quic/core/web_transport_interface.h
@@ -138,6 +138,9 @@
virtual WebTransportStream* OpenOutgoingUnidirectionalStream() = 0;
virtual MessageStatus SendOrQueueDatagram(QuicMemSlice datagram) = 0;
+ // Returns a conservative estimate of the largest datagram size that the
+ // session would be able to send.
+ virtual QuicByteCount GetMaxDatagramSize() const = 0;
// Sets the largest duration that a datagram can spend in the queue before
// being silently dropped.
virtual void SetDatagramMaxTimeInQueue(QuicTime::Delta max_time_in_queue) = 0;
diff --git a/quic/quic_transport/quic_transport_client_session.h b/quic/quic_transport/quic_transport_client_session.h
index 0a890f2..8785457 100644
--- a/quic/quic_transport/quic_transport_client_session.h
+++ b/quic/quic_transport/quic_transport_client_session.h
@@ -121,6 +121,10 @@
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
+ QuicByteCount GetMaxDatagramSize() const override {
+ return GetGuaranteedLargestMessagePayload();
+ }
+
protected:
class QUIC_EXPORT_PRIVATE ClientIndication : public QuicStream {
public: