Move flow control config validation logic from QuicSession to individual QuicStream. This prevents the session from accessing too much of stream's states. No behavior change. not protected PiperOrigin-RevId: 325467676 Change-Id: I80590b074f2fee31221cd5aefada8a58fc1c0d40
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc index b2ac3ab..926038a 100644 --- a/quic/core/quic_session.cc +++ b/quic/core/quic_session.cc
@@ -1397,7 +1397,8 @@ } QUIC_DVLOG(1) << ENDPOINT << "Informing unidirectional stream " << id << " of new stream flow control window " << new_window; - if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) { + if (!kv.second->ValidateFlowControlLimit(new_window, + was_zero_rtt_rejected_)) { return; } if (!kv.second->ConfigSendWindowOffset(new_window)) { @@ -1430,7 +1431,8 @@ } QUIC_DVLOG(1) << ENDPOINT << "Informing outgoing bidirectional stream " << id << " of new stream flow control window " << new_window; - if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) { + if (!kv.second->ValidateFlowControlLimit(new_window, + was_zero_rtt_rejected_)) { return; } if (!kv.second->ConfigSendWindowOffset(new_window)) { @@ -1463,7 +1465,8 @@ } QUIC_DVLOG(1) << ENDPOINT << "Informing incoming bidirectional stream " << id << " of new stream flow control window " << new_window; - if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) { + if (!kv.second->ValidateFlowControlLimit(new_window, + was_zero_rtt_rejected_)) { return; } if (!kv.second->ConfigSendWindowOffset(new_window)) { @@ -1472,41 +1475,6 @@ } } -bool QuicSession::ValidateStreamFlowControlLimit(QuicStreamOffset new_window, - const QuicStream* stream) { - if (was_zero_rtt_rejected_ && - new_window < stream->flow_controller()->bytes_sent()) { - QUIC_BUG_IF(perspective() == Perspective::IS_SERVER) - << "Server should never receive configs twice."; - connection_->CloseConnection( - QUIC_ZERO_RTT_UNRETRANSMITTABLE, - quiche::QuicheStrCat( - "Server rejected 0-RTT, aborting because new stream max data ", - new_window, " for stream ", stream->id(), - " is less than currently used: ", - stream->flow_controller()->bytes_sent()), - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; - } - - if (version().AllowsLowFlowControlLimits() && - new_window < stream->flow_controller()->send_window_offset()) { - QUIC_BUG_IF(perspective() == Perspective::IS_SERVER) - << "Server should never receive configs twice."; - connection_->CloseConnection( - was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED - : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, - quiche::QuicheStrCat( - was_zero_rtt_rejected_ ? "Server rejected 0-RTT, aborting because " - : "", - "new stream max data ", new_window, " decreases current limit: ", - stream->flow_controller()->send_window_offset()), - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; - } - return true; -} - void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) { QUIC_DVLOG(1) << ENDPOINT << "OnNewSessionFlowControlWindow " << new_window;
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h index 9bb05ff..54c3111 100644 --- a/quic/core/quic_session.h +++ b/quic/core/quic_session.h
@@ -736,12 +736,6 @@ QuicRstStreamErrorCode error, QuicStreamOffset bytes_written); - // Closes the connection and returns false if |new_window| is lower than - // |stream|'s current flow control window. - // Returns true otherwise. - bool ValidateStreamFlowControlLimit(QuicStreamOffset new_window, - const QuicStream* stream); - // Sends a STOP_SENDING frame if the stream type allows. void MaybeSendStopSendingFrame(QuicStreamId id, QuicRstStreamErrorCode error);
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc index ee3f983..b25a159 100644 --- a/quic/core/quic_stream.cc +++ b/quic/core/quic_stream.cc
@@ -1247,6 +1247,37 @@ } } +bool QuicStream::ValidateFlowControlLimit(QuicStreamOffset new_window, + bool was_zero_rtt_rejected) { + if (was_zero_rtt_rejected && new_window < flow_controller_->bytes_sent()) { + QUIC_BUG_IF(perspective_ == Perspective::IS_SERVER) + << "Server streams' flow control should never be configured twice."; + OnUnrecoverableError( + QUIC_ZERO_RTT_UNRETRANSMITTABLE, + quiche::QuicheStrCat( + "Server rejected 0-RTT, aborting because new stream max data ", + new_window, " for stream ", id_, + " is less than currently used: ", flow_controller_->bytes_sent())); + return false; + } + + if (VersionUsesHttp3(transport_version()) && + new_window < flow_controller_->send_window_offset()) { + QUIC_BUG_IF(perspective_ == Perspective::IS_SERVER) + << "Server streams' flow control should never be configured twice."; + OnUnrecoverableError( + was_zero_rtt_rejected ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED + : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, + quiche::QuicheStrCat( + was_zero_rtt_rejected ? "Server rejected 0-RTT, aborting because " + : "", + "new stream max data ", new_window, " decreases current limit: ", + flow_controller_->send_window_offset())); + return false; + } + return true; +} + bool QuicStream::MaybeSetTtl(QuicTime::Delta ttl) { if (is_static_) { QUIC_BUG << "Cannot set TTL of a static stream.";
diff --git a/quic/core/quic_stream.h b/quic/core/quic_stream.h index 12b1192..8d7ce19 100644 --- a/quic/core/quic_stream.h +++ b/quic/core/quic_stream.h
@@ -179,6 +179,12 @@ // Send PRIORITY_UPDATE frame if application protocol supports it. virtual void MaybeSendPriorityUpdateFrame() {} + // Closes the connection and returns false if |new_window| is lower than + // stream's current flow control window. + // Returns true otherwise. + bool ValidateFlowControlLimit(QuicStreamOffset new_window, + bool was_zero_rtt_rejected); + // Sets |priority_| to priority. This should only be called before bytes are // written to the server. For a server stream, this is called when a // PRIORITY_UPDATE frame is received. This calls