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: