Project import generated by Copybara.

PiperOrigin-RevId: 224614037
Change-Id: I14e53449d4aeccb328f86828c76b5f09dea0d4b8
diff --git a/http2/decoder/frame_decoder_state.cc b/http2/decoder/frame_decoder_state.cc
new file mode 100644
index 0000000..946a6ee
--- /dev/null
+++ b/http2/decoder/frame_decoder_state.cc
@@ -0,0 +1,81 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/http2/decoder/frame_decoder_state.h"
+
+namespace http2 {
+
+DecodeStatus FrameDecoderState::ReadPadLength(DecodeBuffer* db,
+                                              bool report_pad_length) {
+  DVLOG(2) << "ReadPadLength db->Remaining=" << db->Remaining()
+           << "; payload_length=" << frame_header().payload_length;
+  DCHECK(IsPaddable());
+  DCHECK(frame_header().IsPadded());
+
+  // Pad Length is always at the start of the frame, so remaining_payload_
+  // should equal payload_length at this point.
+  const uint32_t total_payload = frame_header().payload_length;
+  DCHECK_EQ(total_payload, remaining_payload_);
+  DCHECK_EQ(0u, remaining_padding_);
+
+  if (db->HasData()) {
+    const uint32_t pad_length = db->DecodeUInt8();
+    const uint32_t total_padding = pad_length + 1;
+    if (total_padding <= total_payload) {
+      remaining_padding_ = pad_length;
+      remaining_payload_ = total_payload - total_padding;
+      if (report_pad_length) {
+        listener()->OnPadLength(pad_length);
+      }
+      return DecodeStatus::kDecodeDone;
+    }
+    const uint32_t missing_length = total_padding - total_payload;
+    // To allow for the possibility of recovery, record the number of
+    // remaining bytes of the frame's payload (invalid though it is)
+    // in remaining_payload_.
+    remaining_payload_ = total_payload - 1;  // 1 for sizeof(Pad Length).
+    remaining_padding_ = 0;
+    listener()->OnPaddingTooLong(frame_header(), missing_length);
+    return DecodeStatus::kDecodeError;
+  }
+
+  if (total_payload == 0) {
+    remaining_payload_ = 0;
+    remaining_padding_ = 0;
+    listener()->OnPaddingTooLong(frame_header(), 1);
+    return DecodeStatus::kDecodeError;
+  }
+  // Need to wait for another buffer.
+  return DecodeStatus::kDecodeInProgress;
+}
+
+bool FrameDecoderState::SkipPadding(DecodeBuffer* db) {
+  DVLOG(2) << "SkipPadding remaining_padding_=" << remaining_padding_
+           << ", db->Remaining=" << db->Remaining()
+           << ", header: " << frame_header();
+  DCHECK_EQ(remaining_payload_, 0u);
+  DCHECK(IsPaddable()) << "header: " << frame_header();
+  DCHECK_GE(remaining_padding_, 0u);
+  DCHECK(remaining_padding_ == 0 || frame_header().IsPadded())
+      << "remaining_padding_=" << remaining_padding_
+      << ", header: " << frame_header();
+  const size_t avail = AvailablePadding(db);
+  if (avail > 0) {
+    listener()->OnPadding(db->cursor(), avail);
+    db->AdvanceCursor(avail);
+    remaining_padding_ -= avail;
+  }
+  return remaining_padding_ == 0;
+}
+
+DecodeStatus FrameDecoderState::ReportFrameSizeError() {
+  DVLOG(2) << "FrameDecoderState::ReportFrameSizeError: "
+           << " remaining_payload_=" << remaining_payload_
+           << "; remaining_padding_=" << remaining_padding_
+           << ", header: " << frame_header();
+  listener()->OnFrameSizeError(frame_header());
+  return DecodeStatus::kDecodeError;
+}
+
+}  // namespace http2