Project import generated by Copybara.

PiperOrigin-RevId: 229942388
Change-Id: Ib5a23c152c95ed4294cece9f902227c21ce531ef
diff --git a/spdy/core/hpack/hpack_decoder_adapter.cc b/spdy/core/hpack/hpack_decoder_adapter.cc
new file mode 100644
index 0000000..309af39
--- /dev/null
+++ b/spdy/core/hpack/hpack_decoder_adapter.cc
@@ -0,0 +1,201 @@
+// Copyright 2017 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/spdy/core/hpack/hpack_decoder_adapter.h"
+
+#include "base/logging.h"
+#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
+#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
+
+using ::http2::DecodeBuffer;
+using ::http2::HpackEntryType;
+using ::http2::HpackString;
+
+namespace spdy {
+namespace {
+const size_t kMaxDecodeBufferSizeBytes = 32 * 1024;  // 32 KB
+}  // namespace
+
+HpackDecoderAdapter::HpackDecoderAdapter()
+    : hpack_decoder_(&listener_adapter_, kMaxDecodeBufferSizeBytes),
+      max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes),
+      header_block_started_(false) {}
+
+HpackDecoderAdapter::~HpackDecoderAdapter() = default;
+
+void HpackDecoderAdapter::ApplyHeaderTableSizeSetting(size_t size_setting) {
+  DVLOG(2) << "HpackDecoderAdapter::ApplyHeaderTableSizeSetting";
+  hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting);
+}
+
+void HpackDecoderAdapter::HandleControlFrameHeadersStart(
+    SpdyHeadersHandlerInterface* handler) {
+  DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersStart";
+  DCHECK(!header_block_started_);
+  listener_adapter_.set_handler(handler);
+}
+
+bool HpackDecoderAdapter::HandleControlFrameHeadersData(
+    const char* headers_data,
+    size_t headers_data_length) {
+  DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersData: len="
+           << headers_data_length;
+  if (!header_block_started_) {
+    // Initialize the decoding process here rather than in
+    // HandleControlFrameHeadersStart because that method is not always called.
+    header_block_started_ = true;
+    if (!hpack_decoder_.StartDecodingBlock()) {
+      header_block_started_ = false;
+      return false;
+    }
+  }
+
+  // Sometimes we get a call with headers_data==nullptr and
+  // headers_data_length==0, in which case we need to avoid creating
+  // a DecodeBuffer, which would otherwise complain.
+  if (headers_data_length > 0) {
+    DCHECK_NE(headers_data, nullptr);
+    if (headers_data_length > max_decode_buffer_size_bytes_) {
+      DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: "
+               << max_decode_buffer_size_bytes_ << " < " << headers_data_length;
+      return false;
+    }
+    listener_adapter_.AddToTotalHpackBytes(headers_data_length);
+    http2::DecodeBuffer db(headers_data, headers_data_length);
+    bool ok = hpack_decoder_.DecodeFragment(&db);
+    DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining();
+    return ok;
+  }
+  return true;
+}
+
+bool HpackDecoderAdapter::HandleControlFrameHeadersComplete(
+    size_t* compressed_len) {
+  DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersComplete";
+  if (compressed_len != nullptr) {
+    *compressed_len = listener_adapter_.total_hpack_bytes();
+  }
+  if (!hpack_decoder_.EndDecodingBlock()) {
+    DVLOG(3) << "EndDecodingBlock returned false";
+    return false;
+  }
+  header_block_started_ = false;
+  return true;
+}
+
+const SpdyHeaderBlock& HpackDecoderAdapter::decoded_block() const {
+  return listener_adapter_.decoded_block();
+}
+
+void HpackDecoderAdapter::SetHeaderTableDebugVisitor(
+    std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
+  DVLOG(2) << "HpackDecoderAdapter::SetHeaderTableDebugVisitor";
+  if (visitor != nullptr) {
+    listener_adapter_.SetHeaderTableDebugVisitor(std::move(visitor));
+    hpack_decoder_.set_tables_debug_listener(&listener_adapter_);
+  } else {
+    hpack_decoder_.set_tables_debug_listener(nullptr);
+    listener_adapter_.SetHeaderTableDebugVisitor(nullptr);
+  }
+}
+
+void HpackDecoderAdapter::set_max_decode_buffer_size_bytes(
+    size_t max_decode_buffer_size_bytes) {
+  DVLOG(2) << "HpackDecoderAdapter::set_max_decode_buffer_size_bytes";
+  max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes;
+  hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes);
+}
+
+size_t HpackDecoderAdapter::EstimateMemoryUsage() const {
+  return SpdyEstimateMemoryUsage(hpack_decoder_);
+}
+
+HpackDecoderAdapter::ListenerAdapter::ListenerAdapter() : handler_(nullptr) {}
+HpackDecoderAdapter::ListenerAdapter::~ListenerAdapter() = default;
+
+void HpackDecoderAdapter::ListenerAdapter::set_handler(
+    SpdyHeadersHandlerInterface* handler) {
+  handler_ = handler;
+}
+
+void HpackDecoderAdapter::ListenerAdapter::SetHeaderTableDebugVisitor(
+    std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
+  visitor_ = std::move(visitor);
+}
+
+void HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart() {
+  DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart";
+  total_hpack_bytes_ = 0;
+  total_uncompressed_bytes_ = 0;
+  decoded_block_.clear();
+  if (handler_ != nullptr) {
+    handler_->OnHeaderBlockStart();
+  }
+}
+
+void HpackDecoderAdapter::ListenerAdapter::OnHeader(HpackEntryType entry_type,
+                                                    const HpackString& name,
+                                                    const HpackString& value) {
+  DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeader:\n name: " << name
+           << "\n value: " << value;
+  total_uncompressed_bytes_ += name.size() + value.size();
+  if (handler_ == nullptr) {
+    DVLOG(3) << "Adding to decoded_block";
+    decoded_block_.AppendValueOrAddHeader(name.ToStringPiece(),
+                                          value.ToStringPiece());
+  } else {
+    DVLOG(3) << "Passing to handler";
+    handler_->OnHeader(name.ToStringPiece(), value.ToStringPiece());
+  }
+}
+
+void HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd() {
+  DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd";
+  // We don't clear the SpdyHeaderBlock here to allow access to it until the
+  // next HPACK block is decoded.
+  if (handler_ != nullptr) {
+    handler_->OnHeaderBlockEnd(total_uncompressed_bytes_, total_hpack_bytes_);
+    handler_ = nullptr;
+  }
+}
+
+void HpackDecoderAdapter::ListenerAdapter::OnHeaderErrorDetected(
+    SpdyStringPiece error_message) {
+  VLOG(1) << error_message;
+}
+
+int64_t HpackDecoderAdapter::ListenerAdapter::OnEntryInserted(
+    const http2::HpackStringPair& sp,
+    size_t insert_count) {
+  DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnEntryInserted: " << sp
+           << ",  insert_count=" << insert_count;
+  if (visitor_ == nullptr) {
+    return 0;
+  }
+  HpackEntry entry(sp.name.ToStringPiece(), sp.value.ToStringPiece(),
+                   /*is_static*/ false, insert_count);
+  int64_t time_added = visitor_->OnNewEntry(entry);
+  DVLOG(2)
+      << "HpackDecoderAdapter::ListenerAdapter::OnEntryInserted: time_added="
+      << time_added;
+  return time_added;
+}
+
+void HpackDecoderAdapter::ListenerAdapter::OnUseEntry(
+    const http2::HpackStringPair& sp,
+    size_t insert_count,
+    int64_t time_added) {
+  DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnUseEntry: " << sp
+           << ",  insert_count=" << insert_count
+           << ",  time_added=" << time_added;
+  if (visitor_ != nullptr) {
+    HpackEntry entry(sp.name.ToStringPiece(), sp.value.ToStringPiece(),
+                     /*is_static*/ false, insert_count);
+    entry.set_time_added(time_added);
+    visitor_->OnUseEntry(entry);
+  }
+}
+
+}  // namespace spdy