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 {