Stop processing data in QuicSpdyStream::OnDataAvailable() if connection is closed. If the connection is closed, for example, QuicSpdyStream itself closes it because a frame of invalid type is received, or because a QPACK error occurs, then no more data should be fed into HttpDecoder. gfe-relnote: n/a, change to QUIC v99-only class. PiperOrigin-RevId: 258752154 Change-Id: Ibb60b00662160582a075e1a5353bab74e95490d5
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc index b55e928..11cc233 100644 --- a/quic/core/http/quic_spdy_stream.cc +++ b/quic/core/http/quic_spdy_stream.cc
@@ -661,7 +661,8 @@ } iovec iov; - while (!reading_stopped() && decoder_.error() == QUIC_NO_ERROR) { + while (session()->connection()->connected() && !reading_stopped() && + decoder_.error() == QUIC_NO_ERROR) { DCHECK_GE(sequencer_offset_, sequencer()->NumBytesConsumed()); if (!sequencer()->PeekRegion(sequencer_offset_, &iov)) { break;
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc index 43a14d9..f9777ec 100644 --- a/quic/core/http/quic_spdy_stream_test.cc +++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -2286,6 +2286,40 @@ stream_->OnStreamFrame(QuicStreamFrame(stream_->id(), false, offset, data2)); } +// SETTINGS frames are invalid on bidirectional streams. If one is received, +// the connection is closed. No more data should be processed. +TEST_P(QuicSpdyStreamTest, StopProcessingIfConnectionClosed) { + if (!VersionUsesQpack(GetParam().transport_version)) { + return; + } + + Initialize(kShouldProcessData); + + // SETTINGS frame with empty payload. + std::string settings = QuicTextUtils::HexDecode("0400"); + // HEADERS frame with QPACK encoded single header field "foo: bar". + // Since it arrives after a SETTINGS frame, it should never be read. + std::string headers = + HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172")); + + // Combine the two frames to make sure they are processed in a single + // QuicSpdyStream::OnDataAvailable() call. + std::string frames = QuicStrCat(settings, headers); + + EXPECT_EQ(0u, stream_->sequencer()->NumBytesConsumed()); + + EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)) + .WillOnce( + Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); + EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _)); + EXPECT_CALL(*session_, OnConnectionClosed(_, _)); + + stream_->OnStreamFrame(QuicStreamFrame(stream_->id(), /* fin = */ false, + /* offset = */ 0, frames)); + + EXPECT_EQ(0u, stream_->sequencer()->NumBytesConsumed()); +} + } // namespace } // namespace test } // namespace quic