Add HttpDecoder::OnPriorityFrameStart() so that QuicSpdyStream knows the size
of the priority frame and can consume correct amount of bytes.

gfe-relnote: v99 only, not in prod.
PiperOrigin-RevId: 254279623
Change-Id: Ic24fd04b055033c0735a224e76a949714b3ef268
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index 4513f04..179ab83 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -160,27 +160,32 @@
     return;
   }
 
-  // Calling the following two visitor methods does not require parsing of any
+  // Calling the following visitor methods does not require parsing of any
   // frame payload.
+  auto frame_meta = Http3FrameLengths(
+      current_length_field_length_ + current_type_field_length_,
+      current_frame_length_);
   if (current_frame_type_ == 0x0) {
-    if (!visitor_->OnDataFrameStart(Http3FrameLengths(
-            current_length_field_length_ + current_type_field_length_,
-            current_frame_length_))) {
-      RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+    if (!visitor_->OnDataFrameStart(frame_meta)) {
+      RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down on DATA frame start.");
       return;
     }
   } else if (current_frame_type_ == 0x1) {
-    if (!visitor_->OnHeadersFrameStart(Http3FrameLengths(
-            current_length_field_length_ + current_type_field_length_,
-            current_frame_length_))) {
-      RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+    if (!visitor_->OnHeadersFrameStart(frame_meta)) {
+      RaiseError(QUIC_INTERNAL_ERROR,
+                 "Visitor shut down on HEADERS frame start.");
       return;
     }
   } else if (current_frame_type_ == 0x4) {
-    if (!visitor_->OnSettingsFrameStart(Http3FrameLengths(
-            current_length_field_length_ + current_type_field_length_,
-            current_frame_length_))) {
-      RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+    if (!visitor_->OnSettingsFrameStart(frame_meta)) {
+      RaiseError(QUIC_INTERNAL_ERROR,
+                 "Visitor shut down on SETTINGS frame start.");
+      return;
+    }
+  } else if (current_frame_type_ == 0x2) {
+    if (!visitor_->OnPriorityFrameStart(frame_meta)) {
+      RaiseError(QUIC_INTERNAL_ERROR,
+                 "Visitor shut down on PRIORITY frame start.");
       return;
     }
   }
@@ -204,7 +209,7 @@
       }
       DCHECK(!payload.empty());
       if (!visitor_->OnDataFramePayload(payload)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down on DATA frame.");
         return;
       }
       remaining_frame_length_ -= payload.length();
@@ -220,7 +225,7 @@
       }
       DCHECK(!payload.empty());
       if (!visitor_->OnHeadersFramePayload(payload)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down on HEADERS frame.");
         return;
       }
       remaining_frame_length_ -= payload.length();
@@ -251,7 +256,8 @@
         }
         remaining_frame_length_ -= bytes_remaining - reader->BytesRemaining();
         if (!visitor_->OnPushPromiseFrameStart(push_id)) {
-          RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+          RaiseError(QUIC_INTERNAL_ERROR,
+                     "Visitor shut down on PUSH_PROMISE frame start.");
           return;
         }
       }
@@ -268,7 +274,8 @@
       }
       DCHECK(!payload.empty());
       if (!visitor_->OnPushPromiseFramePayload(payload)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR,
+                   "Visitor shut down on PUSH_PROMISE frame.");
         return;
       }
       remaining_frame_length_ -= payload.length();
@@ -323,14 +330,15 @@
   switch (current_frame_type_) {
     case 0x0: {  // DATA
       if (!visitor_->OnDataFrameEnd()) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down on DATA frame end.");
         return;
       }
       break;
     }
     case 0x1: {  // HEADERS
       if (!visitor_->OnHeadersFrameEnd()) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR,
+                   "Visitor shut down on HEADERS frame end.");
         return;
       }
       break;
@@ -344,7 +352,7 @@
         return;
       }
       if (!visitor_->OnPriorityFrame(frame)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down on PRIORITY frame.");
         return;
       }
       break;
@@ -358,7 +366,8 @@
         return;
       }
       if (!visitor_->OnCancelPushFrame(frame)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR,
+                   "Visitor shut down on CANCEL_PUSH frame.");
         return;
       }
       break;
@@ -370,14 +379,15 @@
         return;
       }
       if (!visitor_->OnSettingsFrame(frame)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down on SETTINGS frame.");
         return;
       }
       break;
     }
     case 0x5: {  // PUSH_PROMISE
       if (!visitor_->OnPushPromiseFrameEnd()) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR,
+                   "Visitor shut down on PUSH_PROMISE frame end.");
         return;
       }
       break;
@@ -396,7 +406,7 @@
       }
       frame.stream_id = static_cast<QuicStreamId>(stream_id);
       if (!visitor_->OnGoAwayFrame(frame)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down on GOAWAY frame.");
         return;
       }
       break;
@@ -410,7 +420,8 @@
         return;
       }
       if (!visitor_->OnMaxPushIdFrame(frame)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR,
+                   "Visitor shut down on MAX_PUSH_ID frame.");
         return;
       }
       break;
@@ -424,7 +435,8 @@
         return;
       }
       if (!visitor_->OnDuplicatePushFrame(frame)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Visitor shut down.");
+        RaiseError(QUIC_INTERNAL_ERROR,
+                   "Visitor shut down on DUPLICATE_PUSH frame.");
         return;
       }
       break;
diff --git a/quic/core/http/http_decoder.h b/quic/core/http/http_decoder.h
index 9f0db73..0304b56 100644
--- a/quic/core/http/http_decoder.h
+++ b/quic/core/http/http_decoder.h
@@ -40,6 +40,11 @@
     // Called if an error is detected.
     virtual void OnError(HttpDecoder* decoder) = 0;
 
+    // Called when a PRIORITY frame has been received.
+    // |frame_length| contains PRIORITY frame length and payload length.
+    // Returns true to permit furthuring decoding, and false to prevent it.
+    virtual bool OnPriorityFrameStart(Http3FrameLengths frame_length) = 0;
+
     // Called when a PRIORITY frame has been successfully parsed.
     // Returns true to permit furthuring decoding, and false to prevent it.
     virtual bool OnPriorityFrame(const PriorityFrame& frame) = 0;
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc
index c25d086..b74918a 100644
--- a/quic/core/http/http_decoder_test.cc
+++ b/quic/core/http/http_decoder_test.cc
@@ -23,6 +23,7 @@
   // Called if an error is detected.
   MOCK_METHOD1(OnError, void(HttpDecoder* decoder));
 
+  MOCK_METHOD1(OnPriorityFrameStart, bool(Http3FrameLengths frame_lengths));
   MOCK_METHOD1(OnPriorityFrame, bool(const PriorityFrame& frame));
   MOCK_METHOD1(OnCancelPushFrame, bool(const CancelPushFrame& frame));
   MOCK_METHOD1(OnMaxPushIdFrame, bool(const MaxPushIdFrame& frame));
@@ -47,6 +48,7 @@
 class HttpDecoderTest : public QuicTest {
  public:
   HttpDecoderTest() {
+    ON_CALL(visitor_, OnPriorityFrameStart(_)).WillByDefault(Return(true));
     ON_CALL(visitor_, OnPriorityFrame(_)).WillByDefault(Return(true));
     ON_CALL(visitor_, OnCancelPushFrame(_)).WillByDefault(Return(true));
     ON_CALL(visitor_, OnMaxPushIdFrame(_)).WillByDefault(Return(true));
@@ -199,7 +201,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());
+  EXPECT_EQ("Visitor shut down on CANCEL_PUSH frame.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, PushPromiseFrame) {
@@ -242,7 +244,8 @@
   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());
+  EXPECT_EQ("Visitor shut down on PUSH_PROMISE frame start.",
+            decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, MaxPushId) {
@@ -273,7 +276,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());
+  EXPECT_EQ("Visitor shut down on MAX_PUSH_ID frame.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, DuplicatePush) {
@@ -303,7 +306,8 @@
       .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());
+  EXPECT_EQ("Visitor shut down on DUPLICATE_PUSH frame.",
+            decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, PriorityFrame) {
@@ -329,6 +333,7 @@
   frame.weight = 0xFF;
 
   // Process the full frame.
+  EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(2, 4)));
   EXPECT_CALL(visitor_, OnPriorityFrame(frame));
   EXPECT_EQ(QUIC_ARRAYSIZE(input),
             decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
@@ -336,6 +341,7 @@
   EXPECT_EQ("", decoder_.error_detail());
 
   // Process the frame incremently.
+  EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(2, 4)));
   EXPECT_CALL(visitor_, OnPriorityFrame(frame));
   for (char c : input) {
     EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
@@ -357,6 +363,7 @@
   frame2.exclusive = true;
   frame2.weight = 0xFF;
 
+  EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(2, 2)));
   EXPECT_CALL(visitor_, OnPriorityFrame(frame2));
   EXPECT_EQ(QUIC_ARRAYSIZE(input2),
             decoder_.ProcessInput(input2, QUIC_ARRAYSIZE(input2)));
@@ -364,10 +371,11 @@
   EXPECT_EQ("", decoder_.error_detail());
 
   // Test on the situation when the visitor wants to stop processing.
+  EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(2, 4)));
   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());
+  EXPECT_EQ("Visitor shut down on PRIORITY frame.", decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, SettingsFrame) {
@@ -419,7 +427,8 @@
       .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());
+  EXPECT_EQ("Visitor shut down on SETTINGS frame start.",
+            decoder_.error_detail());
 }
 
 TEST_F(HttpDecoderTest, DataFrame) {
@@ -459,7 +468,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());
+  EXPECT_EQ("Visitor shut down on DATA frame start.", 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 986c4e4..e7efad1 100644
--- a/quic/core/http/quic_receive_control_stream.cc
+++ b/quic/core/http/quic_receive_control_stream.cc
@@ -4,6 +4,7 @@
 
 #include "net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h"
 
+#include "net/third_party/quiche/src/quic/core/http/http_decoder.h"
 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
 
 namespace quic {
@@ -24,6 +25,11 @@
         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
   }
 
+  bool OnPriorityFrameStart(Http3FrameLengths /*frame_lengths*/) override {
+    CloseConnectionOnWrongFrame("Priority");
+    return false;
+  }
+
   bool OnPriorityFrame(const PriorityFrame& /*frame*/) override {
     CloseConnectionOnWrongFrame("Priority");
     return false;
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc
index aa20771..02601ba 100644
--- a/quic/core/http/quic_spdy_stream.cc
+++ b/quic/core/http/quic_spdy_stream.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "net/third_party/quiche/src/quic/core/http/http_decoder.h"
 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
 #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h"
@@ -45,6 +46,11 @@
         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
   }
 
+  bool OnPriorityFrameStart(Http3FrameLengths /*frame_lengths*/) override {
+    CloseConnectionOnWrongFrame("Priority");
+    return false;
+  }
+
   bool OnPriorityFrame(const PriorityFrame& /*frame*/) override {
     CloseConnectionOnWrongFrame("Priority");
     return false;