Make sure the read side is not closed when QuicSpdyStream tries to read from sequencer. gfe-relnote: protected by version 99. PiperOrigin-RevId: 239422550 Change-Id: If5791c996fe1e617e936339c66dc22a3886734a2
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc index 012250a..20330eb 100644 --- a/quic/core/http/quic_spdy_stream.cc +++ b/quic/core/http/quic_spdy_stream.cc
@@ -497,7 +497,7 @@ } iovec iov; - while (sequencer()->PrefetchNextRegion(&iov)) { + while (!reading_stopped() && sequencer()->PrefetchNextRegion(&iov)) { decoder_.ProcessInput(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len); }
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc index d218571..7cff575 100644 --- a/quic/core/http/quic_spdy_stream_test.cc +++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -304,6 +304,46 @@ EXPECT_EQ(QuicHeaderList(), stream_->header_list()); } +TEST_P(QuicSpdyStreamTest, ProcessWrongFramesOnSpdyStream) { + testing::InSequence s; + Initialize(kShouldProcessData); + if (!HasFrameHeader()) { + return; + } + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); + GoAwayFrame goaway; + goaway.stream_id = 0x1; + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = encoder_.SerializeGoAwayFrame(goaway, &buffer); + std::string data = std::string(buffer.get(), header_length); + + EXPECT_EQ("", stream_->data()); + QuicHeaderList headers = ProcessHeaders(false, headers_); + EXPECT_EQ(headers, stream_->header_list()); + stream_->ConsumeHeaderList(); + QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, + QuicStringPiece(data)); + + EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)) + .WillOnce( + (Invoke([this](QuicErrorCode error, const std::string& error_details, + ConnectionCloseBehavior connection_close_behavior) { + connection_->ReallyCloseConnection(error, error_details, + connection_close_behavior); + }))); + EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _, _)); + EXPECT_CALL(*session_, OnConnectionClosed(_, _, _)) + .WillOnce( + Invoke([this](QuicErrorCode error, const std::string& error_details, + ConnectionCloseSource source) { + session_->ReallyOnConnectionClosed(error, error_details, source); + })); + EXPECT_CALL(*session_, SendRstStream(_, _, _)); + EXPECT_CALL(*session_, SendRstStream(_, _, _)); + + stream_->OnStreamFrame(frame); +} + TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBody) { Initialize(kShouldProcessData); @@ -404,6 +444,7 @@ vec.iov_len = QUIC_ARRAYSIZE(buffer); size_t bytes_read = stream_->Readv(&vec, 1); + QuicStreamPeer::CloseReadSide(stream_); EXPECT_EQ(body.length(), bytes_read); EXPECT_EQ(body, std::string(buffer, bytes_read)); }
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index 5c70c64..965082b 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -686,6 +686,12 @@ const QuicCryptoStream* GetCryptoStream() const override; void SetCryptoStream(QuicCryptoStream* crypto_stream); + void ReallyOnConnectionClosed(QuicErrorCode error, + const std::string& error_details, + ConnectionCloseSource source) { + QuicSession::OnConnectionClosed(error, error_details, source); + } + // From QuicSession. MOCK_METHOD3(OnConnectionClosed, void(QuicErrorCode error,