Fix quicsession::willingandabletowrite to check connection level flow control for send control stream and qpack streams. protected by gfe2_reloadable_flag_quic_fix_willing_and_able_to_write.

PiperOrigin-RevId: 313853837
Change-Id: I3f2516d4ac11b8867ffafc45cbacb2b0ff0cbd9b
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 9e1280a..1e36258 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -2988,6 +2988,26 @@
   }
 }
 
+TEST_P(QuicSpdySessionTestServer,
+       H3ControlStreamsLimitedByConnectionFlowControl) {
+  if (!VersionUsesHttp3(transport_version())) {
+    return;
+  }
+  // Ensure connection level flow control blockage.
+  QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0);
+  EXPECT_TRUE(session_.IsConnectionFlowControlBlocked());
+
+  QuicSendControlStream* send_control_stream =
+      QuicSpdySessionPeer::GetSendControlStream(&session_);
+  // Mark send_control stream write blocked.
+  session_.MarkConnectionLevelWriteBlocked(send_control_stream->id());
+  if (GetQuicReloadableFlag(quic_fix_willing_and_able_to_write)) {
+    EXPECT_FALSE(session_.WillingAndAbleToWrite());
+  } else {
+    EXPECT_TRUE(session_.WillingAndAbleToWrite());
+  }
+}
+
 TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) {
   if (!VersionUsesHttp3(transport_version())) {
     return;
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 52cbd2b..76869a3 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -663,11 +663,26 @@
       HasPendingHandshake()) {
     return true;
   }
-  return control_frame_manager_.WillingToWrite() ||
-         !streams_with_pending_retransmission_.empty() ||
-         write_blocked_streams_.HasWriteBlockedSpecialStream() ||
-         (!flow_controller_.IsBlocked() &&
-          write_blocked_streams_.HasWriteBlockedDataStreams());
+  if (control_frame_manager_.WillingToWrite() ||
+      !streams_with_pending_retransmission_.empty()) {
+    return true;
+  }
+  if (!GetQuicReloadableFlag(quic_fix_willing_and_able_to_write)) {
+    return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
+           (!flow_controller_.IsBlocked() &&
+            write_blocked_streams_.HasWriteBlockedDataStreams());
+  }
+  QUIC_RELOADABLE_FLAG_COUNT(quic_fix_willing_and_able_to_write);
+  if (flow_controller_.IsBlocked()) {
+    if (VersionUsesHttp3(transport_version())) {
+      return false;
+    }
+    // Crypto and headers streams are not blocked by connection level flow
+    // control.
+    return write_blocked_streams_.HasWriteBlockedSpecialStream();
+  }
+  return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
+         write_blocked_streams_.HasWriteBlockedDataStreams();
 }
 
 bool QuicSession::HasPendingHandshake() const {