gfe-relnote: Close connection with H3_CLOSED_CRITICAL_STREAM if peer closes a critical stream. Protected by gfe2_reloadable_flag_quic_enable_version_draft_25_v3 and gfe2_reloadable_flag_quic_enable_version_draft_27.
Note that write (send) unidirectional streams can only receive STOP_SENDING, and
read (received) unidirectional streams can only receive RESET_STREAM. The wrong
kind of frame would not reach the stream object from the transport layer.
PiperOrigin-RevId: 300733944
Change-Id: I2780dc928b6f9ed093854329378c12dcd94ecb0a
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 0412a76..408b0fa 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -1187,6 +1187,7 @@
TEST_P(QuicSpdySessionTestServer, OnRstStreamStaticStreamId) {
QuicStreamId id;
+ QuicErrorCode expected_error;
std::string error_message;
// Initialize HTTP/3 control stream.
if (VersionUsesHttp3(transport_version())) {
@@ -1195,9 +1196,11 @@
QuicStreamFrame data1(id, false, 0, quiche::QuicheStringPiece(type, 1));
session_.OnStreamFrame(data1);
- error_message = "Attempt to reset receive control stream";
+ expected_error = QUIC_HTTP_CLOSED_CRITICAL_STREAM;
+ error_message = "RESET_STREAM received for receive control stream";
} else {
id = QuicUtils::GetHeadersStreamId(transport_version());
+ expected_error = QUIC_INVALID_STREAM_ID;
error_message = "Attempt to reset headers stream";
}
@@ -1206,7 +1209,7 @@
QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(
*connection_,
- CloseConnection(QUIC_INVALID_STREAM_ID, error_message,
+ CloseConnection(expected_error, error_message,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET));
session_.OnRstStream(rst1);
}
@@ -2879,6 +2882,82 @@
session_.OnStreamFrame(data);
}
+TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalReceiveStream) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ struct {
+ char type;
+ const char* error_details;
+ } kTestData[] = {
+ {kControlStream, "RESET_STREAM received for receive control stream"},
+ {kQpackEncoderStream, "RESET_STREAM received for QPACK receive stream"},
+ {kQpackDecoderStream, "RESET_STREAM received for QPACK receive stream"},
+ };
+ for (size_t i = 0; i < QUICHE_ARRAYSIZE(kTestData); ++i) {
+ QuicStreamId stream_id =
+ GetNthClientInitiatedUnidirectionalStreamId(transport_version(), i + 1);
+ const QuicByteCount data_length = 1;
+ QuicStreamFrame data(
+ stream_id, false, 0,
+ quiche::QuicheStringPiece(&kTestData[i].type, data_length));
+ session_.OnStreamFrame(data);
+
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM,
+ kTestData[i].error_details, _));
+
+ QuicRstStreamFrame rst(kInvalidControlFrameId, stream_id,
+ QUIC_STREAM_CANCELLED, data_length);
+ session_.OnRstStream(rst);
+ }
+}
+
+TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ QuicSendControlStream* control_stream =
+ QuicSpdySessionPeer::GetSendControlStream(&session_);
+ ASSERT_TRUE(control_stream);
+
+ QuicStopSendingFrame stop_sending_control_stream(
+ kInvalidControlFrameId, control_stream->id(),
+ static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM,
+ "STOP_SENDING received for send control stream", _));
+ session_.OnStopSendingFrame(stop_sending_control_stream);
+
+ QpackSendStream* decoder_stream =
+ QuicSpdySessionPeer::GetQpackDecoderSendStream(&session_);
+ ASSERT_TRUE(decoder_stream);
+
+ QuicStopSendingFrame stop_sending_decoder_stream(
+ kInvalidControlFrameId, decoder_stream->id(),
+ static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM,
+ "STOP_SENDING received for QPACK send stream", _));
+ session_.OnStopSendingFrame(stop_sending_decoder_stream);
+
+ QpackSendStream* encoder_stream =
+ QuicSpdySessionPeer::GetQpackEncoderSendStream(&session_);
+ ASSERT_TRUE(encoder_stream);
+
+ QuicStopSendingFrame stop_sending_encoder_stream(
+ kInvalidControlFrameId, encoder_stream->id(),
+ static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM,
+ "STOP_SENDING received for QPACK send stream", _));
+ session_.OnStopSendingFrame(stop_sending_encoder_stream);
+}
+
} // namespace
} // namespace test
} // namespace quic