Use maximum stream ID in GOAWAY frame for graceful shutdown.
We are aware of HTTP/2 clients that fail outstanding requests upon GOAWAY
instead of retrying them, and because of this we send max stream ID instead of
largest processed stream ID in HTTP/2. In case a similar issue exists or will
develop for QUIC, the only time a GOAWAY frame with a stream ID less than the
maximum possible stream ID is sent should be right before closing the
connection. This also allows us not to implement resetting incoming streams
with stream ID larger than sent in a GOAWAY frame.
Protected by FLAGS_quic_reloadable_flag_quic_goaway_with_max_stream_id.
PiperOrigin-RevId: 341835202
Change-Id: I8a45511d2d8f617de32ba3b5e55eb93bce26e75b
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 4eb3e5c..434178d 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -1110,17 +1110,27 @@
EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- // No client-initiated stream has been received, therefore a GOAWAY frame with
- // stream ID = 0 is sent to notify the client that all requests can be retried
- // on a different connection.
- EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 0));
+ if (GetQuicReloadableFlag(quic_goaway_with_max_stream_id)) {
+ // Send max stream id (currently 32 bits).
+ EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 0xfffffffc));
+ } else {
+ // No client-initiated stream has been received, therefore a GOAWAY frame
+ // with stream ID = 0 is sent to notify the client that all requests can be
+ // retried on a different connection.
+ EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 0));
+ }
session_.SendHttp3GoAway();
EXPECT_TRUE(session_.goaway_sent());
+ // New incoming stream is not reset.
const QuicStreamId kTestStreamId =
GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0);
EXPECT_CALL(*connection_, OnStreamReset(kTestStreamId, _)).Times(0);
EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId));
+
+ // No more GOAWAY frames are sent because they could not convey new
+ // information to the client.
+ session_.SendHttp3GoAway();
}
TEST_P(QuicSpdySessionTestServer, SendHttp3GoAwayAfterStreamIsCreated) {
@@ -1142,10 +1152,15 @@
EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- // The first stream, of kTestStreamId = 0, could already have been processed.
- // A GOAWAY frame is sent to notify the client that requests starting with
- // stream ID = 4 can be retried on a different connection.
- EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 4));
+ if (GetQuicReloadableFlag(quic_goaway_with_max_stream_id)) {
+ // Send max stream id (currently 32 bits).
+ EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 0xfffffffc));
+ } else {
+ // The first stream, of kTestStreamId = 0, could already have been
+ // processed. A GOAWAY frame is sent to notify the client that requests
+ // starting with stream ID = 4 can be retried on a different connection.
+ EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 4));
+ }
session_.SendHttp3GoAway();
EXPECT_TRUE(session_.goaway_sent());
@@ -1155,6 +1170,10 @@
}
TEST_P(QuicSpdySessionTestServer, SendHttp3Shutdown) {
+ if (GetQuicReloadableFlag(quic_goaway_with_max_stream_id)) {
+ return;
+ }
+
if (!VersionUsesHttp3(transport_version())) {
return;
}
@@ -1176,6 +1195,10 @@
}
TEST_P(QuicSpdySessionTestServer, SendHttp3GoAwayAfterShutdownNotice) {
+ if (GetQuicReloadableFlag(quic_goaway_with_max_stream_id)) {
+ return;
+ }
+
if (!VersionUsesHttp3(transport_version())) {
return;
}