Allow HttpDecoder visitor to return bool upon receiving HTTP/3 frames.

The prevents decoder from reading after the stream has already freed its
sequencer.

gfe-relnote: Version 99 only. Not in prod.
PiperOrigin-RevId: 251257525
Change-Id: Ia2bd1cc0073d45df60b91dc4fcfed327b31ec369
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index c59e8b0..7f0cc68 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -165,17 +165,26 @@
   // Calling the following two visitor methods does not require parsing of any
   // frame payload.
   if (current_frame_type_ == 0x0) {
-    visitor_->OnDataFrameStart(Http3FrameLengths(
-        current_length_field_length_ + current_type_field_length_,
-        current_frame_length_));
+    if (!visitor_->OnDataFrameStart(Http3FrameLengths(
+            current_length_field_length_ + current_type_field_length_,
+            current_frame_length_))) {
+      RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+      return;
+    }
   } else if (current_frame_type_ == 0x1) {
-    visitor_->OnHeadersFrameStart(Http3FrameLengths(
-        current_length_field_length_ + current_type_field_length_,
-        current_frame_length_));
+    if (!visitor_->OnHeadersFrameStart(Http3FrameLengths(
+            current_length_field_length_ + current_type_field_length_,
+            current_frame_length_))) {
+      RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+      return;
+    }
   } else if (current_frame_type_ == 0x4) {
-    visitor_->OnSettingsFrameStart(Http3FrameLengths(
-        current_length_field_length_ + current_type_field_length_,
-        current_frame_length_));
+    if (!visitor_->OnSettingsFrameStart(Http3FrameLengths(
+            current_length_field_length_ + current_type_field_length_,
+            current_frame_length_))) {
+      RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+      return;
+    }
   }
 
   remaining_frame_length_ = current_frame_length_;
@@ -196,7 +205,10 @@
         return;
       }
       DCHECK(!payload.empty());
-      visitor_->OnDataFramePayload(payload);
+      if (!visitor_->OnDataFramePayload(payload)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       remaining_frame_length_ -= payload.length();
       break;
     }
@@ -209,7 +221,10 @@
         return;
       }
       DCHECK(!payload.empty());
-      visitor_->OnHeadersFramePayload(payload);
+      if (!visitor_->OnHeadersFramePayload(payload)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       remaining_frame_length_ -= payload.length();
       break;
     }
@@ -237,7 +252,10 @@
           return;
         }
         remaining_frame_length_ -= bytes_remaining - reader->BytesRemaining();
-        visitor_->OnPushPromiseFrameStart(push_id);
+        if (!visitor_->OnPushPromiseFrameStart(push_id)) {
+          RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+          return;
+        }
       }
       DCHECK_LT(remaining_frame_length_, current_frame_length_);
       QuicByteCount bytes_to_read = std::min<QuicByteCount>(
@@ -251,7 +269,10 @@
         return;
       }
       DCHECK(!payload.empty());
-      visitor_->OnPushPromiseFramePayload(payload);
+      if (!visitor_->OnPushPromiseFramePayload(payload)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       remaining_frame_length_ -= payload.length();
       break;
     }
@@ -303,11 +324,17 @@
   DCHECK_EQ(0u, remaining_frame_length_);
   switch (current_frame_type_) {
     case 0x0: {  // DATA
-      visitor_->OnDataFrameEnd();
+      if (!visitor_->OnDataFrameEnd()) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
     case 0x1: {  // HEADERS
-      visitor_->OnHeadersFrameEnd();
+      if (!visitor_->OnHeadersFrameEnd()) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
     case 0x2: {  // PRIORITY
@@ -318,7 +345,10 @@
       if (!ParsePriorityFrame(&reader, &frame)) {
         return;
       }
-      visitor_->OnPriorityFrame(frame);
+      if (!visitor_->OnPriorityFrame(frame)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
     case 0x3: {  // CANCEL_PUSH
@@ -329,7 +359,10 @@
         RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
         return;
       }
-      visitor_->OnCancelPushFrame(frame);
+      if (!visitor_->OnCancelPushFrame(frame)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
     case 0x4: {  // SETTINGS
@@ -338,11 +371,17 @@
       if (!ParseSettingsFrame(&reader, &frame)) {
         return;
       }
-      visitor_->OnSettingsFrame(frame);
+      if (!visitor_->OnSettingsFrame(frame)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
     case 0x5: {  // PUSH_PROMISE
-      visitor_->OnPushPromiseFrameEnd();
+      if (!visitor_->OnPushPromiseFrameEnd()) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
     case 0x7: {  // GOAWAY
@@ -358,7 +397,10 @@
         return;
       }
       frame.stream_id = static_cast<QuicStreamId>(stream_id);
-      visitor_->OnGoAwayFrame(frame);
+      if (!visitor_->OnGoAwayFrame(frame)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
 
@@ -369,7 +411,10 @@
         RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
         return;
       }
-      visitor_->OnMaxPushIdFrame(frame);
+      if (!visitor_->OnMaxPushIdFrame(frame)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
 
@@ -380,7 +425,10 @@
         RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
         return;
       }
-      visitor_->OnDuplicatePushFrame(frame);
+      if (!visitor_->OnDuplicatePushFrame(frame)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        return;
+      }
       break;
     }
   }
diff --git a/quic/core/http/http_decoder.h b/quic/core/http/http_decoder.h
index a392962..4ed4c66 100644
--- a/quic/core/http/http_decoder.h
+++ b/quic/core/http/http_decoder.h
@@ -45,55 +45,71 @@
     virtual void OnError(HttpDecoder* decoder) = 0;
 
     // Called when a PRIORITY frame has been successfully parsed.
-    virtual void OnPriorityFrame(const PriorityFrame& frame) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnPriorityFrame(const PriorityFrame& frame) = 0;
 
     // Called when a CANCEL_PUSH frame has been successfully parsed.
-    virtual void OnCancelPushFrame(const CancelPushFrame& frame) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnCancelPushFrame(const CancelPushFrame& frame) = 0;
 
     // Called when a MAX_PUSH_ID frame has been successfully parsed.
-    virtual void OnMaxPushIdFrame(const MaxPushIdFrame& frame) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnMaxPushIdFrame(const MaxPushIdFrame& frame) = 0;
 
     // Called when a GOAWAY frame has been successfully parsed.
-    virtual void OnGoAwayFrame(const GoAwayFrame& frame) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnGoAwayFrame(const GoAwayFrame& frame) = 0;
 
     // Called when a SETTINGS frame has been received.
-    virtual void OnSettingsFrameStart(Http3FrameLengths frame_length) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnSettingsFrameStart(Http3FrameLengths frame_length) = 0;
 
     // Called when a SETTINGS frame has been successfully parsed.
-    virtual void OnSettingsFrame(const SettingsFrame& frame) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnSettingsFrame(const SettingsFrame& frame) = 0;
 
     // Called when a DUPLICATE_PUSH frame has been successfully parsed.
-    virtual void OnDuplicatePushFrame(const DuplicatePushFrame& frame) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnDuplicatePushFrame(const DuplicatePushFrame& frame) = 0;
 
     // Called when a DATA frame has been received.
     // |frame_length| contains DATA frame length and payload length.
-    virtual void OnDataFrameStart(Http3FrameLengths frame_length) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnDataFrameStart(Http3FrameLengths frame_length) = 0;
     // Called when part of the payload of a DATA frame has been read.  May be
     // called multiple times for a single frame.  |payload| is guaranteed to be
     // non-empty.
-    virtual void OnDataFramePayload(QuicStringPiece payload) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnDataFramePayload(QuicStringPiece payload) = 0;
     // Called when a DATA frame has been completely processed.
-    virtual void OnDataFrameEnd() = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnDataFrameEnd() = 0;
 
     // Called when a HEADERS frame has been received.
     // |frame_length| contains HEADERS frame length and payload length.
-    virtual void OnHeadersFrameStart(Http3FrameLengths frame_length) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnHeadersFrameStart(Http3FrameLengths frame_length) = 0;
     // Called when part of the payload of a HEADERS frame has been read.  May be
     // called multiple times for a single frame.  |payload| is guaranteed to be
     // non-empty.
-    virtual void OnHeadersFramePayload(QuicStringPiece payload) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnHeadersFramePayload(QuicStringPiece payload) = 0;
     // Called when a HEADERS frame has been completely processed.
     // |frame_len| is the length of the HEADERS frame payload.
-    virtual void OnHeadersFrameEnd() = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnHeadersFrameEnd() = 0;
 
     // Called when a PUSH_PROMISE frame has been received for |push_id|.
-    virtual void OnPushPromiseFrameStart(PushId push_id) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnPushPromiseFrameStart(PushId push_id) = 0;
     // Called when part of the payload of a PUSH_PROMISE frame has been read.
     // May be called multiple times for a single frame.  |payload| is guaranteed
     // to be non-empty.
-    virtual void OnPushPromiseFramePayload(QuicStringPiece payload) = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnPushPromiseFramePayload(QuicStringPiece payload) = 0;
     // Called when a PUSH_PROMISE frame has been completely processed.
-    virtual void OnPushPromiseFrameEnd() = 0;
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnPushPromiseFrameEnd() = 0;
 
     // TODO(rch): Consider adding methods like:
     // OnUnknownFrame{Start,Payload,End}()
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc
index a4903b5..b99689f 100644
--- a/quic/core/http/http_decoder_test.cc
+++ b/quic/core/http/http_decoder_test.cc
@@ -10,7 +10,9 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 
-using testing::InSequence;
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
 
 namespace quic {
 
@@ -21,30 +23,49 @@
   // Called if an error is detected.
   MOCK_METHOD1(OnError, void(HttpDecoder* decoder));
 
-  MOCK_METHOD1(OnPriorityFrame, void(const PriorityFrame& frame));
-  MOCK_METHOD1(OnCancelPushFrame, void(const CancelPushFrame& frame));
-  MOCK_METHOD1(OnMaxPushIdFrame, void(const MaxPushIdFrame& frame));
-  MOCK_METHOD1(OnGoAwayFrame, void(const GoAwayFrame& frame));
-  MOCK_METHOD1(OnSettingsFrameStart, void(Http3FrameLengths frame_lengths));
-  MOCK_METHOD1(OnSettingsFrame, void(const SettingsFrame& frame));
-  MOCK_METHOD1(OnDuplicatePushFrame, void(const DuplicatePushFrame& frame));
+  MOCK_METHOD1(OnPriorityFrame, bool(const PriorityFrame& frame));
+  MOCK_METHOD1(OnCancelPushFrame, bool(const CancelPushFrame& frame));
+  MOCK_METHOD1(OnMaxPushIdFrame, bool(const MaxPushIdFrame& frame));
+  MOCK_METHOD1(OnGoAwayFrame, bool(const GoAwayFrame& frame));
+  MOCK_METHOD1(OnSettingsFrameStart, bool(Http3FrameLengths frame_lengths));
+  MOCK_METHOD1(OnSettingsFrame, bool(const SettingsFrame& frame));
+  MOCK_METHOD1(OnDuplicatePushFrame, bool(const DuplicatePushFrame& frame));
 
-  MOCK_METHOD1(OnDataFrameStart, void(Http3FrameLengths frame_lengths));
-  MOCK_METHOD1(OnDataFramePayload, void(QuicStringPiece payload));
-  MOCK_METHOD0(OnDataFrameEnd, void());
+  MOCK_METHOD1(OnDataFrameStart, bool(Http3FrameLengths frame_lengths));
+  MOCK_METHOD1(OnDataFramePayload, bool(QuicStringPiece payload));
+  MOCK_METHOD0(OnDataFrameEnd, bool());
 
-  MOCK_METHOD1(OnHeadersFrameStart, void(Http3FrameLengths frame_lengths));
-  MOCK_METHOD1(OnHeadersFramePayload, void(QuicStringPiece payload));
-  MOCK_METHOD0(OnHeadersFrameEnd, void());
+  MOCK_METHOD1(OnHeadersFrameStart, bool(Http3FrameLengths frame_lengths));
+  MOCK_METHOD1(OnHeadersFramePayload, bool(QuicStringPiece payload));
+  MOCK_METHOD0(OnHeadersFrameEnd, bool());
 
-  MOCK_METHOD1(OnPushPromiseFrameStart, void(PushId push_id));
-  MOCK_METHOD1(OnPushPromiseFramePayload, void(QuicStringPiece payload));
-  MOCK_METHOD0(OnPushPromiseFrameEnd, void());
+  MOCK_METHOD1(OnPushPromiseFrameStart, bool(PushId push_id));
+  MOCK_METHOD1(OnPushPromiseFramePayload, bool(QuicStringPiece payload));
+  MOCK_METHOD0(OnPushPromiseFrameEnd, bool());
 };
 
 class HttpDecoderTest : public QuicTest {
  public:
-  HttpDecoderTest() { decoder_.set_visitor(&visitor_); }
+  HttpDecoderTest() {
+    ON_CALL(visitor_, OnPriorityFrame(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnCancelPushFrame(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnMaxPushIdFrame(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnGoAwayFrame(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnSettingsFrameStart(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnSettingsFrame(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnDuplicatePushFrame(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnDataFrameStart(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnDataFramePayload(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnDataFrameEnd()).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnHeadersFrameStart(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnHeadersFramePayload(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnHeadersFrameEnd()).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnPushPromiseFrameStart(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnPushPromiseFramePayload(_)).WillByDefault(Return(true));
+    ON_CALL(visitor_, OnPushPromiseFrameEnd()).WillByDefault(Return(true));
+    decoder_.set_visitor(&visitor_);
+  }
+
   HttpDecoder decoder_;
   testing::StrictMock<MockVisitor> visitor_;
 };
@@ -172,6 +193,13 @@
   }
   EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
   EXPECT_EQ("", decoder_.error_detail());
+
+  // Test on the situation when the visitor wants to stop processing.
+  EXPECT_CALL(visitor_, OnCancelPushFrame(CancelPushFrame({1})))
+      .WillOnce(Return(false));
+  EXPECT_EQ(0u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+  EXPECT_EQ("Visitor shut down.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, PushPromiseFrame) {
@@ -209,6 +237,12 @@
   }
   EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
   EXPECT_EQ("", decoder_.error_detail());
+
+  // Test on the situation when the visitor wants to stop processing.
+  EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1)).WillOnce(Return(false));
+  EXPECT_EQ(0u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+  EXPECT_EQ("Visitor shut down.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, MaxPushId) {
@@ -233,6 +267,13 @@
   }
   EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
   EXPECT_EQ("", decoder_.error_detail());
+
+  // Test on the situation when the visitor wants to stop processing.
+  EXPECT_CALL(visitor_, OnMaxPushIdFrame(MaxPushIdFrame({1})))
+      .WillOnce(Return(false));
+  EXPECT_EQ(0u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+  EXPECT_EQ("Visitor shut down.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, DuplicatePush) {
@@ -256,6 +297,13 @@
   }
   EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
   EXPECT_EQ("", decoder_.error_detail());
+
+  // Test on the situation when the visitor wants to stop processing.
+  EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1})))
+      .WillOnce(Return(false));
+  EXPECT_EQ(0u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+  EXPECT_EQ("Visitor shut down.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, PriorityFrame) {
@@ -287,7 +335,6 @@
   EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
   EXPECT_EQ("", decoder_.error_detail());
 
-  /*
   // Process the frame incremently.
   EXPECT_CALL(visitor_, OnPriorityFrame(frame));
   for (char c : input) {
@@ -295,7 +342,12 @@
   }
   EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
   EXPECT_EQ("", decoder_.error_detail());
-  */
+
+  // Test on the situation when the visitor wants to stop processing.
+  EXPECT_CALL(visitor_, OnPriorityFrame(frame)).WillOnce(Return(false));
+  EXPECT_EQ(0u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+  EXPECT_EQ("Visitor shut down.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, SettingsFrame) {
@@ -341,6 +393,13 @@
   }
   EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
   EXPECT_EQ("", decoder_.error_detail());
+
+  // Test on the situation when the visitor wants to stop processing.
+  EXPECT_CALL(visitor_, OnSettingsFrameStart(Http3FrameLengths(2, 7)))
+      .WillOnce(Return(false));
+  EXPECT_EQ(0u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+  EXPECT_EQ("Visitor shut down.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, DataFrame) {
@@ -374,6 +433,13 @@
   }
   EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
   EXPECT_EQ("", decoder_.error_detail());
+
+  // Test on the situation when the visitor wants to stop processing.
+  EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)))
+      .WillOnce(Return(false));
+  EXPECT_EQ(0u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+  EXPECT_EQ("Visitor shut down.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, FrameHeaderPartialDelivery) {
diff --git a/quic/core/http/quic_receive_control_stream.cc b/quic/core/http/quic_receive_control_stream.cc
index 87476e6..5941189 100644
--- a/quic/core/http/quic_receive_control_stream.cc
+++ b/quic/core/http/quic_receive_control_stream.cc
@@ -30,64 +30,82 @@
         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
   }
 
-  void OnPriorityFrame(const PriorityFrame& frame) override {
+  bool OnPriorityFrame(const PriorityFrame& frame) override {
     CloseConnectionOnWrongFrame("Priority");
+    return false;
   }
 
-  void OnCancelPushFrame(const CancelPushFrame& frame) override {
+  bool OnCancelPushFrame(const CancelPushFrame& frame) override {
     CloseConnectionOnWrongFrame("Cancel Push");
+    return false;
   }
 
-  void OnMaxPushIdFrame(const MaxPushIdFrame& frame) override {
+  bool OnMaxPushIdFrame(const MaxPushIdFrame& frame) override {
     CloseConnectionOnWrongFrame("Max Push Id");
+    return false;
   }
 
-  void OnGoAwayFrame(const GoAwayFrame& frame) override {
+  bool OnGoAwayFrame(const GoAwayFrame& frame) override {
     CloseConnectionOnWrongFrame("Goaway");
+    return false;
   }
 
-  void OnSettingsFrameStart(Http3FrameLengths frame_lengths) override {
-    stream_->OnSettingsFrameStart(frame_lengths);
+  bool OnSettingsFrameStart(Http3FrameLengths frame_lengths) override {
+    return stream_->OnSettingsFrameStart(frame_lengths);
   }
 
-  void OnSettingsFrame(const SettingsFrame& frame) override {
-    stream_->OnSettingsFrame(frame);
+  bool OnSettingsFrame(const SettingsFrame& frame) override {
+    return stream_->OnSettingsFrame(frame);
   }
 
-  void OnDuplicatePushFrame(const DuplicatePushFrame& frame) override {
+  bool OnDuplicatePushFrame(const DuplicatePushFrame& frame) override {
     CloseConnectionOnWrongFrame("Duplicate Push");
+    return false;
   }
 
-  void OnDataFrameStart(Http3FrameLengths frame_lengths) override {
+  bool OnDataFrameStart(Http3FrameLengths frame_lengths) override {
     CloseConnectionOnWrongFrame("Data");
+    return false;
   }
 
-  void OnDataFramePayload(QuicStringPiece payload) override {
+  bool OnDataFramePayload(QuicStringPiece payload) override {
     CloseConnectionOnWrongFrame("Data");
+    return false;
   }
 
-  void OnDataFrameEnd() override { CloseConnectionOnWrongFrame("Data"); }
+  bool OnDataFrameEnd() override {
+    CloseConnectionOnWrongFrame("Data");
+    return false;
+  }
 
-  void OnHeadersFrameStart(Http3FrameLengths frame_length) override {
+  bool OnHeadersFrameStart(Http3FrameLengths frame_length) override {
     CloseConnectionOnWrongFrame("Headers");
+    return false;
   }
 
-  void OnHeadersFramePayload(QuicStringPiece payload) override {
+  bool OnHeadersFramePayload(QuicStringPiece payload) override {
     CloseConnectionOnWrongFrame("Headers");
+    return false;
   }
 
-  void OnHeadersFrameEnd() override { CloseConnectionOnWrongFrame("Headers"); }
-
-  void OnPushPromiseFrameStart(PushId push_id) override {
-    CloseConnectionOnWrongFrame("Push Promise");
+  bool OnHeadersFrameEnd() override {
+    CloseConnectionOnWrongFrame("Headers");
+    return false;
   }
 
-  void OnPushPromiseFramePayload(QuicStringPiece payload) override {
+  bool OnPushPromiseFrameStart(PushId push_id) override {
     CloseConnectionOnWrongFrame("Push Promise");
+    return false;
   }
 
-  void OnPushPromiseFrameEnd() override {
+  bool OnPushPromiseFramePayload(QuicStringPiece payload) override {
     CloseConnectionOnWrongFrame("Push Promise");
+    return false;
+  }
+
+  bool OnPushPromiseFrameEnd() override {
+    CloseConnectionOnWrongFrame("Push Promise");
+    return false;
   }
 
  private:
@@ -137,20 +155,21 @@
   }
 }
 
-void QuicReceiveControlStream::OnSettingsFrameStart(
+bool QuicReceiveControlStream::OnSettingsFrameStart(
     Http3FrameLengths frame_lengths) {
   if (received_settings_length_ != 0) {
     // TODO(renjietang): Change error code to HTTP_UNEXPECTED_FRAME.
     session()->connection()->CloseConnection(
         QUIC_INVALID_STREAM_ID, "Settings frames are received twice.",
         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-    return;
+    return false;
   }
   received_settings_length_ +=
       frame_lengths.header_length + frame_lengths.payload_length;
+  return true;
 }
 
-void QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& settings) {
+bool QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& settings) {
   QuicSpdySession* spdy_session = static_cast<QuicSpdySession*>(session());
   for (auto& it : settings.values) {
     uint16_t setting_id = it.first;
@@ -166,6 +185,7 @@
     }
   }
   sequencer()->MarkConsumed(received_settings_length_);
+  return true;
 }
 
 }  // namespace quic
diff --git a/quic/core/http/quic_receive_control_stream.h b/quic/core/http/quic_receive_control_stream.h
index 818a1e8..a977f63 100644
--- a/quic/core/http/quic_receive_control_stream.h
+++ b/quic/core/http/quic_receive_control_stream.h
@@ -36,8 +36,8 @@
 
  protected:
   // Called from HttpDecoderVisitor.
-  void OnSettingsFrameStart(Http3FrameLengths frame_lengths);
-  void OnSettingsFrame(const SettingsFrame& settings);
+  bool OnSettingsFrameStart(Http3FrameLengths frame_lengths);
+  bool OnSettingsFrame(const SettingsFrame& settings);
 
  private:
   class HttpDecoderVisitor;
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc
index bd15918..b025fd8 100644
--- a/quic/core/http/quic_spdy_stream.cc
+++ b/quic/core/http/quic_spdy_stream.cc
@@ -45,84 +45,94 @@
         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
   }
 
-  void OnPriorityFrame(const PriorityFrame& frame) override {
+  bool OnPriorityFrame(const PriorityFrame& frame) override {
     CloseConnectionOnWrongFrame("Priority");
+    return false;
   }
 
-  void OnCancelPushFrame(const CancelPushFrame& frame) override {
+  bool OnCancelPushFrame(const CancelPushFrame& frame) override {
     CloseConnectionOnWrongFrame("Cancel Push");
+    return false;
   }
 
-  void OnMaxPushIdFrame(const MaxPushIdFrame& frame) override {
+  bool OnMaxPushIdFrame(const MaxPushIdFrame& frame) override {
     CloseConnectionOnWrongFrame("Max Push Id");
+    return false;
   }
 
-  void OnGoAwayFrame(const GoAwayFrame& frame) override {
+  bool OnGoAwayFrame(const GoAwayFrame& frame) override {
     CloseConnectionOnWrongFrame("Goaway");
+    return false;
   }
 
-  void OnSettingsFrameStart(Http3FrameLengths frame_lengths) override {
+  bool OnSettingsFrameStart(Http3FrameLengths frame_lengths) override {
     CloseConnectionOnWrongFrame("Settings");
+    return false;
   }
 
-  void OnSettingsFrame(const SettingsFrame& frame) override {
+  bool OnSettingsFrame(const SettingsFrame& frame) override {
     CloseConnectionOnWrongFrame("Settings");
+    return false;
   }
 
-  void OnDuplicatePushFrame(const DuplicatePushFrame& frame) override {
+  bool OnDuplicatePushFrame(const DuplicatePushFrame& frame) override {
     CloseConnectionOnWrongFrame("Duplicate Push");
+    return false;
   }
 
-  void OnDataFrameStart(Http3FrameLengths frame_lengths) override {
-    stream_->OnDataFrameStart(frame_lengths);
+  bool OnDataFrameStart(Http3FrameLengths frame_lengths) override {
+    return stream_->OnDataFrameStart(frame_lengths);
   }
 
-  void OnDataFramePayload(QuicStringPiece payload) override {
+  bool OnDataFramePayload(QuicStringPiece payload) override {
     DCHECK(!payload.empty());
-    stream_->OnDataFramePayload(payload);
+    return stream_->OnDataFramePayload(payload);
   }
 
-  void OnDataFrameEnd() override { stream_->OnDataFrameEnd(); }
+  bool OnDataFrameEnd() override { return stream_->OnDataFrameEnd(); }
 
-  void OnHeadersFrameStart(Http3FrameLengths frame_length) override {
+  bool OnHeadersFrameStart(Http3FrameLengths frame_length) override {
     if (!VersionUsesQpack(
             stream_->session()->connection()->transport_version())) {
       CloseConnectionOnWrongFrame("Headers");
-      return;
+      return false;
     }
-    stream_->OnHeadersFrameStart(frame_length);
+    return stream_->OnHeadersFrameStart(frame_length);
   }
 
-  void OnHeadersFramePayload(QuicStringPiece payload) override {
+  bool OnHeadersFramePayload(QuicStringPiece payload) override {
     DCHECK(!payload.empty());
     if (!VersionUsesQpack(
             stream_->session()->connection()->transport_version())) {
       CloseConnectionOnWrongFrame("Headers");
-      return;
+      return false;
     }
-    stream_->OnHeadersFramePayload(payload);
+    return stream_->OnHeadersFramePayload(payload);
   }
 
-  void OnHeadersFrameEnd() override {
+  bool OnHeadersFrameEnd() override {
     if (!VersionUsesQpack(
             stream_->session()->connection()->transport_version())) {
       CloseConnectionOnWrongFrame("Headers");
-      return;
+      return false;
     }
-    stream_->OnHeadersFrameEnd();
+    return stream_->OnHeadersFrameEnd();
   }
 
-  void OnPushPromiseFrameStart(PushId push_id) override {
+  bool OnPushPromiseFrameStart(PushId push_id) override {
     CloseConnectionOnWrongFrame("Push Promise");
+    return false;
   }
 
-  void OnPushPromiseFramePayload(QuicStringPiece payload) override {
+  bool OnPushPromiseFramePayload(QuicStringPiece payload) override {
     DCHECK(!payload.empty());
     CloseConnectionOnWrongFrame("Push Promise");
+    return false;
   }
 
-  void OnPushPromiseFrameEnd() override {
+  bool OnPushPromiseFrameEnd() override {
     CloseConnectionOnWrongFrame("Push Promise");
+    return false;
   }
 
  private:
@@ -470,7 +480,7 @@
   SetPriority(priority);
 }
 
-void QuicSpdyStream::OnStreamHeaderList(bool fin,
+bool QuicSpdyStream::OnStreamHeaderList(bool fin,
                                         size_t frame_len,
                                         const QuicHeaderList& header_list) {
   // The headers list avoid infinite buffering by clearing the headers list
@@ -482,7 +492,7 @@
   if (header_list.empty()) {
     OnHeadersTooLarge();
     if (IsDoneReading()) {
-      return;
+      return false;
     }
   }
   if (!headers_decompressed_) {
@@ -490,6 +500,7 @@
   } else {
     OnTrailingHeadersComplete(fin, frame_len, header_list);
   }
+  return !reading_stopped();
 }
 
 void QuicSpdyStream::OnHeadersTooLarge() {
@@ -701,25 +712,27 @@
   spdy_session_ = nullptr;
 }
 
-void QuicSpdyStream::OnDataFrameStart(Http3FrameLengths frame_lengths) {
+bool QuicSpdyStream::OnDataFrameStart(Http3FrameLengths frame_lengths) {
   DCHECK(
       VersionHasDataFrameHeader(session()->connection()->transport_version()));
-
   body_buffer_.OnDataHeader(frame_lengths);
+  return true;
 }
 
-void QuicSpdyStream::OnDataFramePayload(QuicStringPiece payload) {
+bool QuicSpdyStream::OnDataFramePayload(QuicStringPiece payload) {
   DCHECK(
       VersionHasDataFrameHeader(session()->connection()->transport_version()));
 
   body_buffer_.OnDataPayload(payload);
+  return true;
 }
 
-void QuicSpdyStream::OnDataFrameEnd() {
+bool QuicSpdyStream::OnDataFrameEnd() {
   DCHECK(
       VersionHasDataFrameHeader(session()->connection()->transport_version()));
   QUIC_DVLOG(1) << "Reaches the end of a data frame. Total bytes received are "
                 << body_buffer_.total_body_bytes_received();
+  return true;
 }
 
 bool QuicSpdyStream::OnStreamFrameAcked(QuicStreamOffset offset,
@@ -769,7 +782,7 @@
   return header_acked_length;
 }
 
-void QuicSpdyStream::OnHeadersFrameStart(Http3FrameLengths frame_length) {
+bool QuicSpdyStream::OnHeadersFrameStart(Http3FrameLengths frame_length) {
   DCHECK(VersionUsesQpack(spdy_session_->connection()->transport_version()));
   DCHECK(!qpack_decoded_headers_accumulator_);
 
@@ -783,9 +796,10 @@
       QuicMakeUnique<QpackDecodedHeadersAccumulator>(
           id(), spdy_session_->qpack_decoder(),
           spdy_session_->max_inbound_header_list_size());
+  return true;
 }
 
-void QuicSpdyStream::OnHeadersFramePayload(QuicStringPiece payload) {
+bool QuicSpdyStream::OnHeadersFramePayload(QuicStringPiece payload) {
   DCHECK(VersionUsesQpack(spdy_session_->connection()->transport_version()));
 
   if (!qpack_decoded_headers_accumulator_->Decode(payload)) {
@@ -794,11 +808,12 @@
         QuicStrCat("Error decompressing header block on stream ", id(), ": ",
                    qpack_decoded_headers_accumulator_->error_message());
     CloseConnectionWithDetails(QUIC_DECOMPRESSION_FAILURE, error_message);
-    return;
+    return false;
   }
+  return true;
 }
 
-void QuicSpdyStream::OnHeadersFrameEnd() {
+bool QuicSpdyStream::OnHeadersFrameEnd() {
   DCHECK(VersionUsesQpack(spdy_session_->connection()->transport_version()));
 
   if (!qpack_decoded_headers_accumulator_->EndHeaderBlock()) {
@@ -807,16 +822,18 @@
         QuicStrCat("Error decompressing header block on stream ", id(), ": ",
                    qpack_decoded_headers_accumulator_->error_message());
     CloseConnectionWithDetails(QUIC_DECOMPRESSION_FAILURE, error_message);
-    return;
+    return false;
   }
 
   const QuicByteCount frame_length = headers_decompressed_
                                          ? trailers_length_.payload_length
                                          : headers_length_.payload_length;
-  OnStreamHeaderList(/* fin = */ false, frame_length,
-                     qpack_decoded_headers_accumulator_->quic_header_list());
+  bool result = OnStreamHeaderList(
+      /* fin = */ false, frame_length,
+      qpack_decoded_headers_accumulator_->quic_header_list());
 
   qpack_decoded_headers_accumulator_.reset();
+  return result;
 }
 
 size_t QuicSpdyStream::WriteHeadersImpl(
diff --git a/quic/core/http/quic_spdy_stream.h b/quic/core/http/quic_spdy_stream.h
index 2182d28..76c252d 100644
--- a/quic/core/http/quic_spdy_stream.h
+++ b/quic/core/http/quic_spdy_stream.h
@@ -80,8 +80,9 @@
 
   // Called by the session when decompressed headers have been completely
   // delivered to this stream.  If |fin| is true, then this stream
-  // should be closed; no more data will be sent by the peer.
-  virtual void OnStreamHeaderList(bool fin,
+  // should be closed; no more data will be sent by the peer. Returns true if
+  // the headers are processed successfully without error.
+  virtual bool OnStreamHeaderList(bool fin,
                                   size_t frame_len,
                                   const QuicHeaderList& header_list);
 
@@ -207,12 +208,12 @@
 
  protected:
   // HTTP/3
-  void OnDataFrameStart(Http3FrameLengths frame_lengths);
-  void OnDataFramePayload(QuicStringPiece payload);
-  void OnDataFrameEnd();
-  void OnHeadersFrameStart(Http3FrameLengths frame_length);
-  void OnHeadersFramePayload(QuicStringPiece payload);
-  void OnHeadersFrameEnd();
+  bool OnDataFrameStart(Http3FrameLengths frame_lengths);
+  bool OnDataFramePayload(QuicStringPiece payload);
+  bool OnDataFrameEnd();
+  bool OnHeadersFrameStart(Http3FrameLengths frame_length);
+  bool OnHeadersFramePayload(QuicStringPiece payload);
+  bool OnHeadersFrameEnd();
 
   // Called when the received headers are too large. By default this will
   // reset the stream.
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index 7c423b4..7ecbbf5 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -1863,6 +1863,63 @@
   EXPECT_EQ("some data", data);
 }
 
+TEST_P(QuicSpdyStreamTest, MalformedHeadersStopHttpDecoder) {
+  // The test stream will receive a stream frame containing malformed headers
+  // and normal body. Make sure the http decoder stops processing body after the
+  // connection shuts down.
+  testing::InSequence s;
+  if (!VersionUsesQpack(GetParam().transport_version)) {
+    return;
+  }
+
+  Initialize(kShouldProcessData);
+  connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+
+  // Random bad headers.
+  std::string headers_frame_payload =
+      QuicTextUtils::HexDecode("00002a94e7036261");
+  std::unique_ptr<char[]> headers_buffer;
+  QuicByteCount headers_frame_header_length =
+      encoder_.SerializeHeadersFrameHeader(headers_frame_payload.length(),
+                                           &headers_buffer);
+  QuicStringPiece headers_frame_header(headers_buffer.get(),
+                                       headers_frame_header_length);
+
+  std::string data_frame_payload = "some data";
+  std::unique_ptr<char[]> data_buffer;
+  QuicByteCount data_frame_header_length = encoder_.SerializeDataFrameHeader(
+      data_frame_payload.length(), &data_buffer);
+  QuicStringPiece data_frame_header(data_buffer.get(),
+                                    data_frame_header_length);
+
+  std::string stream_frame_payload =
+      QuicStrCat(headers_frame_header, headers_frame_payload, data_frame_header,
+                 data_frame_payload);
+  QuicStreamFrame frame(stream_->id(), false, 0, stream_frame_payload);
+
+  EXPECT_CALL(*connection_,
+              CloseConnection(QUIC_DECOMPRESSION_FAILURE,
+                              "Error decompressing header block on stream 4: "
+                              "Incomplete header block.",
+                              _))
+      .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);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic