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,