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;