Return false from QuicSpdyStream::OnMetadataFrameEnd if the
stream has been reset.
PiperOrigin-RevId: 615572236
diff --git a/quiche/quic/core/http/quic_spdy_stream.cc b/quiche/quic/core/http/quic_spdy_stream.cc
index 77233fd..4a5c2ed 100644
--- a/quiche/quic/core/http/quic_spdy_stream.cc
+++ b/quiche/quic/core/http/quic_spdy_stream.cc
@@ -1293,7 +1293,7 @@
metadata_visitor_->OnMetadataComplete(received_metadata_payload_->frame_len,
decoder.headers());
received_metadata_payload_.reset();
- return true;
+ return !sequencer()->IsClosed() && !reading_stopped();
}
bool QuicSpdyStream::OnUnknownFrameStart(uint64_t frame_type,
diff --git a/quiche/quic/core/http/quic_spdy_stream_test.cc b/quiche/quic/core/http/quic_spdy_stream_test.cc
index 73d145f..d693c9f 100644
--- a/quiche/quic/core/http/quic_spdy_stream_test.cc
+++ b/quiche/quic/core/http/quic_spdy_stream_test.cc
@@ -2822,6 +2822,51 @@
OnStreamFrame(metadata_frame);
}
+TEST_P(QuicSpdyStreamIncrementalConsumptionTest,
+ ResetDuringMultipleMetadataFrames) {
+ if (!UsesHttp3() ||
+ !GetQuicReloadableFlag(quic_enable_http3_metadata_decoding)) {
+ return;
+ }
+ StrictMock<MockMetadataVisitor> metadata_visitor;
+ Initialize(kShouldProcessData);
+ stream_->RegisterMetadataVisitor(&metadata_visitor);
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_->set_debug_visitor(&debug_visitor);
+
+ quiche::HttpHeaderBlock headers;
+ headers.AppendValueOrAddHeader("key1", "val1");
+ headers.AppendValueOrAddHeader("key2", "val2");
+ quic::NoopDecoderStreamErrorDelegate delegate;
+ QpackEncoder qpack_encoder(&delegate, quic::HuffmanEncoding::kDisabled);
+ std::string metadata_frame_payload = qpack_encoder.EncodeHeaderList(
+ stream_->id(), headers,
+ /* encoder_stream_sent_byte_count = */ nullptr);
+ std::string metadata_frame_header =
+ quic::HttpEncoder::SerializeMetadataFrameHeader(
+ metadata_frame_payload.size());
+ std::string metadata_frame = metadata_frame_header + metadata_frame_payload;
+
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*session_, MaybeSendStopSendingFrame(_, _));
+ EXPECT_CALL(*session_, MaybeSendRstStreamFrame(_, _, _));
+ // Reset the stream while processing the first frame and do not
+ // receive a callback about the second.
+ EXPECT_CALL(metadata_visitor, OnMetadataComplete(metadata_frame.size(), _))
+ .WillOnce(testing::WithArgs<1>(
+ Invoke([&headers, this](const QuicHeaderList& header_list) {
+ quiche::HttpHeaderBlock actual_headers;
+ for (const auto& header : header_list) {
+ actual_headers.AppendValueOrAddHeader(header.first,
+ header.second);
+ }
+ EXPECT_EQ(headers, actual_headers);
+ stream_->Reset(QUIC_STREAM_CANCELLED);
+ })));
+ std::string data = metadata_frame + metadata_frame;
+ OnStreamFrame(data);
+}
+
TEST_P(QuicSpdyStreamIncrementalConsumptionTest, UnknownFramesInterleaved) {
if (!UsesHttp3()) {
return;