gfe-relnote: Abandons HPACK decompression for overly large header blocks. Protected by default-true --gfe2_reloadable_flag_http2_reject_too_large_header_blocks.

PiperOrigin-RevId: 259607264
Change-Id: I718fc440535289e1d8fb6d6e4febdbf8ed8d9d75
diff --git a/spdy/core/hpack/hpack_decoder_adapter.cc b/spdy/core/hpack/hpack_decoder_adapter.cc
index ad05b1f..278eaab 100644
--- a/spdy/core/hpack/hpack_decoder_adapter.cc
+++ b/spdy/core/hpack/hpack_decoder_adapter.cc
@@ -21,6 +21,7 @@
 HpackDecoderAdapter::HpackDecoderAdapter()
     : hpack_decoder_(&listener_adapter_, kMaxDecodeBufferSizeBytes),
       max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes),
+      max_header_block_bytes_(0),
       header_block_started_(false) {}
 
 HpackDecoderAdapter::~HpackDecoderAdapter() = default;
@@ -64,6 +65,10 @@
       return false;
     }
     listener_adapter_.AddToTotalHpackBytes(headers_data_length);
+    if (max_header_block_bytes_ != 0 &&
+        listener_adapter_.total_hpack_bytes() > max_header_block_bytes_) {
+      return false;
+    }
     http2::DecodeBuffer db(headers_data, headers_data_length);
     bool ok = hpack_decoder_.DecodeFragment(&db);
     DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining();
@@ -109,6 +114,11 @@
   hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes);
 }
 
+void HpackDecoderAdapter::set_max_header_block_bytes(
+    size_t max_header_block_bytes) {
+  max_header_block_bytes_ = max_header_block_bytes;
+}
+
 size_t HpackDecoderAdapter::EstimateMemoryUsage() const {
   return SpdyEstimateMemoryUsage(hpack_decoder_);
 }
diff --git a/spdy/core/hpack/hpack_decoder_adapter.h b/spdy/core/hpack/hpack_decoder_adapter.h
index d54cf1e..17c4461 100644
--- a/spdy/core/hpack/hpack_decoder_adapter.h
+++ b/spdy/core/hpack/hpack_decoder_adapter.h
@@ -79,6 +79,10 @@
   // of individual transport buffers.
   void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes);
 
+  // Specifies the maximum size of an on-the-wire header block that will be
+  // accepted.
+  void set_max_header_block_bytes(size_t max_header_block_bytes);
+
   size_t EstimateMemoryUsage() const;
 
  private:
@@ -147,6 +151,9 @@
   // How much encoded data this decoder is willing to buffer.
   size_t max_decode_buffer_size_bytes_;
 
+  // How much encoded data this decoder is willing to process.
+  size_t max_header_block_bytes_;
+
   // Flag to keep track of having seen the header block start. Needed at the
   // moment because HandleControlFrameHeadersStart won't be called if a handler
   // is not being provided by the caller.
diff --git a/spdy/core/hpack/hpack_decoder_adapter_test.cc b/spdy/core/hpack/hpack_decoder_adapter_test.cc
index 335920e..d016841 100644
--- a/spdy/core/hpack/hpack_decoder_adapter_test.cc
+++ b/spdy/core/hpack/hpack_decoder_adapter_test.cc
@@ -331,6 +331,33 @@
   EXPECT_FALSE(HandleControlFrameHeadersData(fragment));
 }
 
+// Verify that a header block that exceeds the maximum length is rejected.
+TEST_P(HpackDecoderAdapterTest, HeaderBlockTooLong) {
+  const SpdyString name = "some-key";
+  const SpdyString value = "some-value";
+  const size_t kMaxBufferSizeBytes = 1024;
+
+  HpackBlockBuilder hbb;
+  hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false,
+                                name, false, value);
+  while (hbb.size() < kMaxBufferSizeBytes) {
+    hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false,
+                                  "", false, "");
+  }
+  // With no limit on the maximum header block size, the decoder handles the
+  // entire block successfully.
+  HandleControlFrameHeadersStart();
+  EXPECT_TRUE(HandleControlFrameHeadersData(hbb.buffer()));
+  size_t total_bytes;
+  EXPECT_TRUE(HandleControlFrameHeadersComplete(&total_bytes));
+
+  // When a total byte limit is imposed, the decoder bails before the end of the
+  // block.
+  decoder_.set_max_header_block_bytes(kMaxBufferSizeBytes);
+  HandleControlFrameHeadersStart();
+  EXPECT_FALSE(HandleControlFrameHeadersData(hbb.buffer()));
+}
+
 // Decode with incomplete data in buffer.
 TEST_P(HpackDecoderAdapterTest, DecodeWithIncompleteData) {
   HandleControlFrameHeadersStart();