Add a new StopIncreasingIncomingMaxStreams() method to QuicStreamIdManager
which prevents the incoming max streams limit from being increased.

PiperOrigin-RevId: 571114450
diff --git a/quiche/quic/core/quic_stream_id_manager.cc b/quiche/quic/core/quic_stream_id_manager.cc
index 1443211..91e8e9d 100644
--- a/quiche/quic/core/quic_stream_id_manager.cc
+++ b/quiche/quic/core/quic_stream_id_manager.cc
@@ -37,7 +37,8 @@
       incoming_initial_max_open_streams_(max_allowed_incoming_streams),
       incoming_stream_count_(0),
       largest_peer_created_stream_id_(
-          QuicUtils::GetInvalidStreamId(version.transport_version)) {}
+          QuicUtils::GetInvalidStreamId(version.transport_version)),
+      stop_increasing_incoming_max_streams_(false) {}
 
 QuicStreamIdManager::~QuicStreamIdManager() {}
 
@@ -129,9 +130,11 @@
     // supports. Nothing can be done here.
     return;
   }
-  // One stream closed, and another one can be opened.
-  incoming_actual_max_streams_++;
-  MaybeSendMaxStreamsFrame();
+  if (!stop_increasing_incoming_max_streams_) {
+    // One stream closed, and another one can be opened.
+    incoming_actual_max_streams_++;
+    MaybeSendMaxStreamsFrame();
+  }
 }
 
 QuicStreamId QuicStreamIdManager::GetNextOutgoingStreamId() {
diff --git a/quiche/quic/core/quic_stream_id_manager.h b/quiche/quic/core/quic_stream_id_manager.h
index 45c7666..922c09a 100644
--- a/quiche/quic/core/quic_stream_id_manager.h
+++ b/quiche/quic/core/quic_stream_id_manager.h
@@ -91,6 +91,11 @@
   // Returns true if |id| is still available.
   bool IsAvailableStream(QuicStreamId id) const;
 
+  // Once called, the incoming max streams limit will never be increased.
+  void StopIncreasingIncomingMaxStreams() {
+    stop_increasing_incoming_max_streams_ = true;
+  }
+
   QuicStreamCount incoming_initial_max_open_streams() const {
     return incoming_initial_max_open_streams_;
   }
@@ -178,6 +183,9 @@
   absl::flat_hash_set<QuicStreamId> available_streams_;
 
   QuicStreamId largest_peer_created_stream_id_;
+
+  // If true, then the stream limit will never be increased.
+  bool stop_increasing_incoming_max_streams_;
 };
 }  // namespace quic
 
diff --git a/quiche/quic/core/quic_stream_id_manager_test.cc b/quiche/quic/core/quic_stream_id_manager_test.cc
index 5b13112..d1e8137 100644
--- a/quiche/quic/core/quic_stream_id_manager_test.cc
+++ b/quiche/quic/core/quic_stream_id_manager_test.cc
@@ -377,6 +377,44 @@
   stream_id_manager_.OnStreamClosed(stream_id);
 }
 
+TEST_P(QuicStreamIdManagerTest, MaxStreamsWindowStopsIncreasing) {
+  // Verify that the incoming stream limit does not increase after
+  // StopIncreasingIncomingMaxStreams() is called, even when streams ar closed.
+
+  QuicStreamId stream_count =
+      stream_id_manager_.incoming_initial_max_open_streams();
+  // Open up to the stream limit.
+  QuicStreamId stream_id = GetNthIncomingStreamId(0);
+  for (QuicStreamCount i = 0; i < stream_count; ++i) {
+    EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id,
+                                                                    nullptr));
+
+    stream_id += QuicUtils::StreamIdDelta(transport_version());
+  }
+
+  // Prevent max streams from increasing.
+  stream_id_manager_.StopIncreasingIncomingMaxStreams();
+
+  // Since the limit does not increase, a MAX_STREAMS frame will not be sent.
+  EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
+
+  // Now close them.
+  stream_id = GetNthIncomingStreamId(0);
+  QuicStreamCount expected_actual_max =
+      stream_id_manager_.incoming_actual_max_streams();
+  QuicStreamCount expected_advertised_max_streams =
+      stream_id_manager_.incoming_advertised_max_streams();
+  for (QuicStreamCount i = 0; i < stream_count; ++i) {
+    stream_id_manager_.OnStreamClosed(stream_id);
+    stream_id += QuicUtils::StreamIdDelta(transport_version());
+    // Limits should not change.
+    EXPECT_EQ(expected_actual_max,
+              stream_id_manager_.incoming_actual_max_streams());
+    EXPECT_EQ(expected_advertised_max_streams,
+              stream_id_manager_.incoming_advertised_max_streams());
+  }
+}
+
 TEST_P(QuicStreamIdManagerTest, StreamsBlockedEdgeConditions) {
   QuicStreamsBlockedFrame frame;
   frame.unidirectional = IsUnidirectional();