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