Call Visitor::OnError() from HttpDecoder::RaiseError().

This is to make sure connection is closed on error.

This bug was caught by ClusterFuzz at https://crbug.com/989416.

gfe-relnote: n/a, change to QUIC v99-only code.  Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99.
PiperOrigin-RevId: 262337299
Change-Id: Ib5241b0c53228dfe48356f5c03d9f4ffae499611
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index 550aa6f..e105fc6 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -126,7 +126,6 @@
   if (current_frame_length_ > MaxFrameLength(current_frame_type_)) {
     // TODO(bnc): Signal HTTP_EXCESSIVE_LOAD or similar to peer.
     RaiseError(QUIC_INTERNAL_ERROR, "Frame is too large");
-    visitor_->OnError(this);
     return false;
   }
 
@@ -440,6 +439,7 @@
   state_ = STATE_ERROR;
   error_ = error;
   error_detail_ = std::move(error_detail);
+  visitor_->OnError(this);
 }
 
 bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader,
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc
index 476c2c6..7cbe949 100644
--- a/quic/core/http/http_decoder_test.cc
+++ b/quic/core/http/http_decoder_test.cc
@@ -404,6 +404,7 @@
 
     HttpDecoder decoder(&visitor_);
     EXPECT_CALL(visitor_, OnPriorityFrameStart(header_length));
+    EXPECT_CALL(visitor_, OnError(&decoder));
 
     QuicByteCount processed_bytes =
         decoder.ProcessInput(input.data(), input.size());
@@ -460,6 +461,40 @@
   EXPECT_EQ("", decoder_.error_detail());
 }
 
+TEST_F(HttpDecoderTest, CorruptSettingsFrame) {
+  const char* const kPayload =
+      "\x42\x11"                           // two-byte id
+      "\x80\x22\x33\x44"                   // four-byte value
+      "\x58\x39"                           // two-byte id
+      "\xf0\x22\x33\x44\x55\x66\x77\x88";  // eight-byte value
+  struct {
+    size_t payload_length;
+    const char* const error_message;
+  } kTestData[] = {
+      {1, "Unable to read settings frame identifier"},
+      {5, "Unable to read settings frame content"},
+      {7, "Unable to read settings frame identifier"},
+      {12, "Unable to read settings frame content"},
+  };
+
+  for (const auto& test_data : kTestData) {
+    std::string input;
+    input.push_back(4u);  // type SETTINGS
+    input.push_back(test_data.payload_length);
+    const size_t header_length = input.size();
+    input.append(kPayload, test_data.payload_length);
+
+    HttpDecoder decoder(&visitor_);
+    EXPECT_CALL(visitor_, OnSettingsFrameStart(header_length));
+    EXPECT_CALL(visitor_, OnError(&decoder));
+
+    QuicByteCount processed_bytes =
+        decoder.ProcessInput(input.data(), input.size());
+    EXPECT_EQ(input.size(), processed_bytes);
+    EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder.error());
+    EXPECT_EQ(test_data.error_message, decoder.error_detail());
+  }
+}
 TEST_F(HttpDecoderTest, DataFrame) {
   InSequence s;
   std::string input(
@@ -792,6 +827,57 @@
   EXPECT_EQ("", decoder_.error_detail());
 }
 
+TEST_F(HttpDecoderTest, CorruptFrame) {
+  InSequence s;
+
+  struct {
+    const char* const input;
+    const char* const error_message;
+  } kTestData[] = {{"\x03"   // type (CANCEL_PUSH)
+                    "\x01"   // length
+                    "\x40",  // first byte of two-byte varint push id
+                    "Unable to read push_id"},
+                   {"\x05"   // type (PUSH_PROMISE)
+                    "\x01"   // length
+                    "\x40",  // first byte of two-byte varint push id
+                    "Unable to read push_id"},
+                   {"\x0D"   // type (MAX_PUSH_ID)
+                    "\x01"   // length
+                    "\x40",  // first byte of two-byte varint push id
+                    "Unable to read push_id"},
+                   {"\x0E"   // type (DUPLICATE_PUSH)
+                    "\x01"   // length
+                    "\x40",  // first byte of two-byte varint push id
+                    "Unable to read push_id"},
+                   {"\x07"   // type (GOAWAY)
+                    "\x01"   // length
+                    "\x40",  // first byte of two-byte varint stream id
+                    "Unable to read GOAWAY stream_id"}};
+
+  for (const auto& test_data : kTestData) {
+    {
+      HttpDecoder decoder(&visitor_);
+      EXPECT_CALL(visitor_, OnError(&decoder));
+
+      QuicStringPiece input(test_data.input);
+      decoder.ProcessInput(input.data(), input.size());
+      EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder.error());
+      EXPECT_EQ(test_data.error_message, decoder.error_detail());
+    }
+    {
+      HttpDecoder decoder(&visitor_);
+      EXPECT_CALL(visitor_, OnError(&decoder));
+
+      QuicStringPiece input(test_data.input);
+      for (auto c : input) {
+        decoder.ProcessInput(&c, 1);
+      }
+      EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder.error());
+      EXPECT_EQ(test_data.error_message, decoder.error_detail());
+    }
+  }
+}  // namespace test
+
 }  // namespace test
 
 }  // namespace quic