Send HTTP/3 GOAWAY frame when closing connection.
Protected by FLAGS_quic_reloadable_flag_quic_send_goaway_with_connection_close.
PiperOrigin-RevId: 337371228
Change-Id: Ic810995552c911a4ef978208c397237f2848cc82
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 345d1b5..76dba5c 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -23,6 +23,7 @@
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
@@ -3061,6 +3062,63 @@
session_.OnStreamFrame(data3);
}
+TEST_P(QuicSpdySessionTestServer, Http3GoAwayWhenClosingConnection) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_.set_debug_visitor(&debug_visitor);
+
+ EXPECT_CALL(debug_visitor, OnSettingsFrameSent(_));
+ CompleteHandshake();
+
+ QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
+
+ // Create stream by receiving some data (CreateIncomingStream() would not
+ // update the session's largest peer created stream ID).
+ const size_t headers_payload_length = 10;
+ std::unique_ptr<char[]> headers_buffer;
+ QuicByteCount headers_frame_header_length =
+ HttpEncoder::SerializeHeadersFrameHeader(headers_payload_length,
+ &headers_buffer);
+ absl::string_view headers_frame_header(headers_buffer.get(),
+ headers_frame_header_length);
+ EXPECT_CALL(debug_visitor,
+ OnHeadersFrameReceived(stream_id, headers_payload_length));
+ session_.OnStreamFrame(
+ QuicStreamFrame(stream_id, false, 0, headers_frame_header));
+
+ EXPECT_EQ(stream_id, QuicSessionPeer::GetLargestPeerCreatedStreamId(
+ &session_, /*unidirectional = */ false));
+
+ if (GetQuicReloadableFlag(quic_send_goaway_with_connection_close)) {
+ if (GetQuicReloadableFlag(quic_fix_http3_goaway_stream_id)) {
+ // Stream with stream_id is already received and potentially processed,
+ // therefore a GOAWAY frame is sent with the next stream ID.
+ EXPECT_CALL(debug_visitor,
+ OnGoAwayFrameSent(stream_id + QuicUtils::StreamIdDelta(
+ transport_version())));
+ } else {
+ // GOAWAY frame stream id is incorrect, ignore.
+ EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(_));
+ }
+ }
+
+ // Close connection.
+ EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
+ .WillRepeatedly(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_NO_ERROR, _, _))
+ .WillOnce(
+ Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
+ EXPECT_CALL(*connection_, SendConnectionClosePacket(QUIC_NO_ERROR, _))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::ReallySendConnectionClosePacket));
+ connection_->CloseConnection(
+ QUIC_NO_ERROR, "closing connection",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+}
+
TEST_P(QuicSpdySessionTestClient, SendInitialMaxPushIdIfSet) {
if (!VersionUsesHttp3(transport_version())) {
return;