Enable partial delivery of Push Promise Frame's push id.

gfe-relnote: v99 only, not protected.
PiperOrigin-RevId: 262578050
Change-Id: I738b7d5be49dfa07eeb5201eca21a6e144d5a3ca
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index 227a839..3a13300 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -23,6 +23,8 @@
       remaining_frame_length_(0),
       current_type_field_length_(0),
       remaining_type_field_length_(0),
+      current_push_id_length_(0),
+      remaining_push_id_length_(0),
       error_(QUIC_NO_ERROR),
       error_detail_("") {
   DCHECK(visitor_);
@@ -214,25 +216,57 @@
       break;
     }
     case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): {
+      PushId push_id;
       if (current_frame_length_ == remaining_frame_length_) {
-        QuicByteCount bytes_remaining = reader->BytesRemaining();
-        PushId push_id;
-        QuicByteCount push_id_length = reader->PeekVarInt62Length();
-        // TODO(rch): Handle partial delivery of this field.
-        if (!reader->ReadVarInt62(&push_id)) {
-          // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
-          RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read push_id");
+        // A new Push Promise frame just arrived.
+        DCHECK_EQ(0u, current_push_id_length_);
+        current_push_id_length_ = reader->PeekVarInt62Length();
+        if (current_push_id_length_ > remaining_frame_length_) {
+          RaiseError(QUIC_INVALID_FRAME_DATA, "PUSH_PROMISE frame malformed.");
           return false;
         }
-        remaining_frame_length_ -= bytes_remaining - reader->BytesRemaining();
-        if (!visitor_->OnPushPromiseFrameStart(
-                push_id,
-                    current_length_field_length_ + current_type_field_length_,
-                push_id_length)) {
-          continue_processing = false;
+        if (current_push_id_length_ > reader->BytesRemaining()) {
+          // Not all bytes of push id is present yet, buffer push id.
+          DCHECK_EQ(0u, remaining_push_id_length_);
+          remaining_push_id_length_ = current_push_id_length_;
+          BufferPushId(reader);
           break;
         }
+        bool success = reader->ReadVarInt62(&push_id);
+        DCHECK(success);
+        remaining_frame_length_ -= current_push_id_length_;
+        if (!visitor_->OnPushPromiseFrameStart(
+                push_id,
+                current_length_field_length_ + current_type_field_length_,
+                current_push_id_length_)) {
+          continue_processing = false;
+          current_push_id_length_ = 0;
+          break;
+        }
+        current_push_id_length_ = 0;
+      } else if (remaining_push_id_length_ > 0) {
+        // Waiting for more bytes on push id.
+        BufferPushId(reader);
+        if (remaining_push_id_length_ != 0) {
+          break;
+        }
+        QuicDataReader push_id_reader(push_id_buffer_.data(),
+                                      current_push_id_length_);
+
+        bool success = push_id_reader.ReadVarInt62(&push_id);
+        DCHECK(success);
+        if (!visitor_->OnPushPromiseFrameStart(
+                push_id,
+                current_length_field_length_ + current_type_field_length_,
+                current_push_id_length_)) {
+          continue_processing = false;
+          current_push_id_length_ = 0;
+          break;
+        }
+        current_push_id_length_ = 0;
       }
+
+      // Read Push Promise headers.
       DCHECK_LT(remaining_frame_length_, current_frame_length_);
       QuicByteCount bytes_to_read = std::min<QuicByteCount>(
           remaining_frame_length_, reader->BytesRemaining());
@@ -252,7 +286,6 @@
       break;
     }
     case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): {
-      // TODO(rch): Handle partial delivery.
       BufferFramePayload(reader);
       break;
     }
@@ -306,7 +339,6 @@
       break;
     }
     case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): {
-      // TODO(rch): Handle partial delivery.
       CancelPushFrame frame;
       QuicDataReader reader(buffer_.data(), current_frame_length_);
       if (!reader.ReadVarInt62(&frame.push_id)) {
@@ -336,7 +368,6 @@
       break;
     }
     case static_cast<uint64_t>(HttpFrameType::GOAWAY): {
-      // TODO(bnc): Handle partial delivery.
       QuicDataReader reader(buffer_.data(), current_frame_length_);
       GoAwayFrame frame;
       static_assert(!std::is_same<decltype(frame.stream_id), uint64_t>::value,
@@ -359,7 +390,6 @@
       break;
     }
     case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): {
-      // TODO(bnc): Handle partial delivery.
       QuicDataReader reader(buffer_.data(), current_frame_length_);
       MaxPushIdFrame frame;
       if (!reader.ReadVarInt62(&frame.push_id)) {
@@ -376,7 +406,6 @@
       break;
     }
     case static_cast<uint64_t>(HttpFrameType::DUPLICATE_PUSH): {
-      // TODO(bnc): Handle partial delivery.
       QuicDataReader reader(buffer_.data(), current_frame_length_);
       DuplicatePushFrame frame;
       if (!reader.ReadVarInt62(&frame.push_id)) {
@@ -433,9 +462,6 @@
 }
 
 void HttpDecoder::BufferFrameLength(QuicDataReader* reader) {
-  if (current_length_field_length_ == remaining_length_field_length_) {
-    length_buffer_.fill(0);
-  }
   QuicByteCount bytes_to_read = std::min<QuicByteCount>(
       remaining_length_field_length_, reader->BytesRemaining());
   bool success =
@@ -447,9 +473,6 @@
 }
 
 void HttpDecoder::BufferFrameType(QuicDataReader* reader) {
-  if (current_type_field_length_ == remaining_type_field_length_) {
-    type_buffer_.fill(0);
-  }
   QuicByteCount bytes_to_read = std::min<QuicByteCount>(
       remaining_type_field_length_, reader->BytesRemaining());
   bool success =
@@ -460,6 +483,19 @@
   remaining_type_field_length_ -= bytes_to_read;
 }
 
+void HttpDecoder::BufferPushId(QuicDataReader* reader) {
+  DCHECK_LE(remaining_push_id_length_, current_frame_length_);
+  QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+      reader->BytesRemaining(), remaining_push_id_length_);
+  bool success =
+      reader->ReadBytes(push_id_buffer_.data() + current_push_id_length_ -
+                            remaining_push_id_length_,
+                        bytes_to_read);
+  DCHECK(success);
+  remaining_push_id_length_ -= bytes_to_read;
+  remaining_frame_length_ -= bytes_to_read;
+}
+
 void HttpDecoder::RaiseError(QuicErrorCode error, std::string error_detail) {
   state_ = STATE_ERROR;
   error_ = error;