Create HTTP/3 unidirectional stream only when stream limit allows.

gfe-relnote: n/a, v99 only.
PiperOrigin-RevId: 260017164
Change-Id: Id0a7d8867eee873b182b78f1e30475f0c87d9fe0
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 6352d7b..50332ee 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -12,6 +12,7 @@
 #include "net/third_party/quiche/src/quic/core/http/http_constants.h"
 #include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
@@ -315,6 +316,8 @@
     const QuicConfig& config,
     const ParsedQuicVersionVector& supported_versions)
     : QuicSession(connection, visitor, config, supported_versions),
+      send_control_stream_(nullptr),
+      receive_control_stream_(nullptr),
       max_inbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
       max_outbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
       server_push_enabled_(true),
@@ -382,12 +385,7 @@
                        /*stream_already_counted = */ false);
 
   if (VersionHasStreamType(connection()->transport_version())) {
-    auto send_control = QuicMakeUnique<QuicSendControlStream>(
-        GetNextOutgoingUnidirectionalStreamId(), this,
-        max_inbound_header_list_size_);
-    send_control_stream_ = send_control.get();
-    RegisterStaticStream(std::move(send_control),
-                         /*stream_already_counted = */ false);
+    MaybeInitializeHttp3UnidirectionalStreams();
   }
 
   spdy_framer_visitor_->set_max_header_list_size(max_inbound_header_list_size_);
@@ -798,4 +796,23 @@
   return false;
 }
 
+void QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams() {
+  DCHECK(VersionHasStreamType(connection()->transport_version()));
+  if (!send_control_stream_ && CanOpenNextOutgoingUnidirectionalStream()) {
+    auto send_control = QuicMakeUnique<QuicSendControlStream>(
+        GetNextOutgoingUnidirectionalStreamId(), this,
+        max_inbound_header_list_size_);
+    send_control_stream_ = send_control.get();
+    RegisterStaticStream(std::move(send_control),
+                         /*stream_already_counted = */ false);
+  }
+}
+
+void QuicSpdySession::OnCanCreateNewOutgoingStream(bool unidirectional) {
+  if (unidirectional &&
+      VersionHasStreamType(connection()->transport_version())) {
+    MaybeInitializeHttp3UnidirectionalStreams();
+  }
+}
+
 }  // namespace quic
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 3fe5c66..1ce8166 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -175,6 +175,10 @@
   // Returns true if the session has active request streams.
   bool HasActiveRequestStreams() const;
 
+  // Initialze HTTP/3 unidirectional streams if |unidirectional| is true and
+  // those streams are not initialized yet.
+  void OnCanCreateNewOutgoingStream(bool unidirectional) override;
+
  protected:
   // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
   // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
@@ -261,6 +265,9 @@
   // Called when the size of the compressed frame payload is available.
   void OnCompressedFrameSize(size_t frame_len);
 
+  // Initializes HTTP/3 unidirectional streams if not yet initialzed.
+  void MaybeInitializeHttp3UnidirectionalStreams();
+
   std::unique_ptr<QpackEncoder> qpack_encoder_;
   std::unique_ptr<QpackDecoder> qpack_decoder_;
 
diff --git a/quic/tools/quic_simple_server_session.cc b/quic/tools/quic_simple_server_session.cc
index ef70fdb..19a5455 100644
--- a/quic/tools/quic_simple_server_session.cc
+++ b/quic/tools/quic_simple_server_session.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
 #include "net/third_party/quiche/src/quic/core/quic_connection.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -229,6 +230,7 @@
 
 void QuicSimpleServerSession::OnCanCreateNewOutgoingStream(
     bool unidirectional) {
+  QuicSpdySession::OnCanCreateNewOutgoingStream(unidirectional);
   if (unidirectional) {
     HandlePromisedPushRequests();
   }
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc
index fca04ff..75afb5d 100644
--- a/quic/tools/quic_simple_server_stream_test.cc
+++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -550,7 +550,7 @@
   // Create a stream with even stream id and test against this stream.
   const QuicStreamId kServerInitiatedStreamId =
       GetNthServerInitiatedUnidirectionalStreamId(
-          connection_->transport_version(), 0);
+          connection_->transport_version(), 1);
   // Create a server initiated stream and pass it to session_.
   auto server_initiated_stream =
       new StrictMock<TestStream>(kServerInitiatedStreamId, &session_,