Project import generated by Copybara.

PiperOrigin-RevId: 224614037
Change-Id: I14e53449d4aeccb328f86828c76b5f09dea0d4b8
diff --git a/http2/hpack/tools/hpack_block_builder.cc b/http2/hpack/tools/hpack_block_builder.cc
new file mode 100644
index 0000000..7a7d348
--- /dev/null
+++ b/http2/hpack/tools/hpack_block_builder.cc
@@ -0,0 +1,80 @@
+// 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/hpack/tools/hpack_block_builder.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_bug_tracker.h"
+
+namespace http2 {
+namespace test {
+
+void HpackBlockBuilder::AppendHighBitsAndVarint(uint8_t high_bits,
+                                                uint8_t prefix_length,
+                                                uint64_t varint) {
+  EXPECT_LE(3, prefix_length);
+  EXPECT_LE(prefix_length, 7);
+
+  HpackVarintEncoder varint_encoder;
+
+  unsigned char c =
+      varint_encoder.StartEncoding(high_bits, prefix_length, varint);
+  buffer_.push_back(c);
+
+  if (!varint_encoder.IsEncodingInProgress()) {
+    return;
+  }
+
+  // After the prefix, at most 63 bits can remain to be encoded.
+  // Each octet holds 7 bits, so at most 9 octets are necessary.
+  // TODO(bnc): Move this into a constant in HpackVarintEncoder.
+  varint_encoder.ResumeEncoding(/* max_encoded_bytes = */ 10, &buffer_);
+  DCHECK(!varint_encoder.IsEncodingInProgress());
+}
+
+void HpackBlockBuilder::AppendEntryTypeAndVarint(HpackEntryType entry_type,
+                                                 uint64_t varint) {
+  uint8_t high_bits;
+  uint8_t prefix_length;  // Bits of the varint prefix in the first byte.
+  switch (entry_type) {
+    case HpackEntryType::kIndexedHeader:
+      high_bits = 0x80;
+      prefix_length = 7;
+      break;
+    case HpackEntryType::kDynamicTableSizeUpdate:
+      high_bits = 0x20;
+      prefix_length = 5;
+      break;
+    case HpackEntryType::kIndexedLiteralHeader:
+      high_bits = 0x40;
+      prefix_length = 6;
+      break;
+    case HpackEntryType::kUnindexedLiteralHeader:
+      high_bits = 0x00;
+      prefix_length = 4;
+      break;
+    case HpackEntryType::kNeverIndexedLiteralHeader:
+      high_bits = 0x10;
+      prefix_length = 4;
+      break;
+    default:
+      HTTP2_BUG << "Unreached, entry_type=" << entry_type;
+      high_bits = 0;
+      prefix_length = 0;
+      break;
+  }
+  AppendHighBitsAndVarint(high_bits, prefix_length, varint);
+}
+
+void HpackBlockBuilder::AppendString(bool is_huffman_encoded,
+                                     Http2StringPiece str) {
+  uint8_t high_bits = is_huffman_encoded ? 0x80 : 0;
+  uint8_t prefix_length = 7;
+  AppendHighBitsAndVarint(high_bits, prefix_length, str.size());
+  buffer_.append(str.data(), str.size());
+}
+
+}  // namespace test
+}  // namespace http2
diff --git a/http2/hpack/tools/hpack_block_builder.h b/http2/hpack/tools/hpack_block_builder.h
new file mode 100644
index 0000000..560953c
--- /dev/null
+++ b/http2/hpack/tools/hpack_block_builder.h
@@ -0,0 +1,96 @@
+// 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.
+
+#ifndef QUICHE_HTTP2_HPACK_TOOLS_HPACK_BLOCK_BUILDER_H_
+#define QUICHE_HTTP2_HPACK_TOOLS_HPACK_BLOCK_BUILDER_H_
+
+// HpackBlockBuilder builds wire-format HPACK blocks (or fragments thereof)
+// from components.
+
+// Supports very large varints to enable tests to create HPACK blocks with
+// values that the decoder should reject. For now, this is only intended for
+// use in tests, and thus has EXPECT* in the code. If desired to use it in an
+// encoder, it will need optimization work, especially w.r.t memory mgmt, and
+// the EXPECT* will need to be removed or replaced with DCHECKs. And of course
+// the support for very large varints will not be needed in production code.
+
+#include <stddef.h>
+
+#include <cstdint>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
+
+namespace http2 {
+namespace test {
+
+class HpackBlockBuilder {
+ public:
+  explicit HpackBlockBuilder(Http2StringPiece initial_contents)
+      : buffer_(initial_contents.data(), initial_contents.size()) {}
+  HpackBlockBuilder() {}
+  ~HpackBlockBuilder() {}
+
+  size_t size() const { return buffer_.size(); }
+  const Http2String& buffer() const { return buffer_; }
+
+  //----------------------------------------------------------------------------
+  // Methods for appending a valid HPACK entry.
+
+  void AppendIndexedHeader(uint64_t index) {
+    AppendEntryTypeAndVarint(HpackEntryType::kIndexedHeader, index);
+  }
+
+  void AppendDynamicTableSizeUpdate(uint64_t size) {
+    AppendEntryTypeAndVarint(HpackEntryType::kDynamicTableSizeUpdate, size);
+  }
+
+  void AppendNameIndexAndLiteralValue(HpackEntryType entry_type,
+                                      uint64_t name_index,
+                                      bool value_is_huffman_encoded,
+                                      Http2StringPiece value) {
+    // name_index==0 would indicate that the entry includes a literal name.
+    // Call AppendLiteralNameAndValue in that case.
+    EXPECT_NE(0u, name_index);
+    AppendEntryTypeAndVarint(entry_type, name_index);
+    AppendString(value_is_huffman_encoded, value);
+  }
+
+  void AppendLiteralNameAndValue(HpackEntryType entry_type,
+                                 bool name_is_huffman_encoded,
+                                 Http2StringPiece name,
+                                 bool value_is_huffman_encoded,
+                                 Http2StringPiece value) {
+    AppendEntryTypeAndVarint(entry_type, 0);
+    AppendString(name_is_huffman_encoded, name);
+    AppendString(value_is_huffman_encoded, value);
+  }
+
+  //----------------------------------------------------------------------------
+  // Primitive methods that are not guaranteed to write a valid HPACK entry.
+
+  // Appends a varint, with the specified high_bits above the prefix of the
+  // varint.
+  void AppendHighBitsAndVarint(uint8_t high_bits,
+                               uint8_t prefix_length,
+                               uint64_t varint);
+
+  // Append the start of an HPACK entry for the specified type, with the
+  // specified varint.
+  void AppendEntryTypeAndVarint(HpackEntryType entry_type, uint64_t varint);
+
+  // Append a header string (i.e. a header name or value) in HPACK format.
+  // Does NOT perform Huffman encoding.
+  void AppendString(bool is_huffman_encoded, Http2StringPiece str);
+
+ private:
+  Http2String buffer_;
+};
+
+}  // namespace test
+}  // namespace http2
+
+#endif  // QUICHE_HTTP2_HPACK_TOOLS_HPACK_BLOCK_BUILDER_H_
diff --git a/http2/hpack/tools/hpack_block_builder_test.cc b/http2/hpack/tools/hpack_block_builder_test.cc
new file mode 100644
index 0000000..a7b8064
--- /dev/null
+++ b/http2/hpack/tools/hpack_block_builder_test.cc
@@ -0,0 +1,169 @@
+// 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/hpack/tools/hpack_block_builder.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
+
+namespace http2 {
+namespace test {
+namespace {
+const bool kUncompressed = false;
+const bool kCompressed = true;
+
+// TODO(jamessynge): Once static table code is checked in, switch to using
+// constants from there.
+const uint32_t kStaticTableMethodGET = 2;
+const uint32_t kStaticTablePathSlash = 4;
+const uint32_t kStaticTableSchemeHttp = 6;
+
+// Tests of encoding per the RFC. See:
+//   http://httpwg.org/specs/rfc7541.html#header.field.representation.examples
+// The expected values have been copied from the RFC.
+TEST(HpackBlockBuilderTest, ExamplesFromSpecC2) {
+  {
+    HpackBlockBuilder b;
+    b.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader,
+                                kUncompressed, "custom-key", kUncompressed,
+                                "custom-header");
+    EXPECT_EQ(26u, b.size());
+
+    const char kExpected[] =
+        "\x40"            // == Literal indexed ==
+        "\x0a"            // Name length (10)
+        "custom-key"      // Name
+        "\x0d"            // Value length (13)
+        "custom-header";  // Value
+    EXPECT_EQ(kExpected, b.buffer());
+  }
+  {
+    HpackBlockBuilder b;
+    b.AppendNameIndexAndLiteralValue(HpackEntryType::kUnindexedLiteralHeader, 4,
+                                     kUncompressed, "/sample/path");
+    EXPECT_EQ(14u, b.size());
+
+    const char kExpected[] =
+        "\x04"           // == Literal unindexed, name index 0x04 ==
+        "\x0c"           // Value length (12)
+        "/sample/path";  // Value
+    EXPECT_EQ(kExpected, b.buffer());
+  }
+  {
+    HpackBlockBuilder b;
+    b.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
+                                kUncompressed, "password", kUncompressed,
+                                "secret");
+    EXPECT_EQ(17u, b.size());
+
+    const char kExpected[] =
+        "\x10"      // == Literal never indexed ==
+        "\x08"      // Name length (8)
+        "password"  // Name
+        "\x06"      // Value length (6)
+        "secret";   // Value
+    EXPECT_EQ(kExpected, b.buffer());
+  }
+  {
+    HpackBlockBuilder b;
+    b.AppendIndexedHeader(2);
+    EXPECT_EQ(1u, b.size());
+
+    const char kExpected[] = "\x82";  // == Indexed (2) ==
+    EXPECT_EQ(kExpected, b.buffer());
+  }
+}
+
+// Tests of encoding per the RFC. See:
+//  http://httpwg.org/specs/rfc7541.html#request.examples.without.huffman.coding
+TEST(HpackBlockBuilderTest, ExamplesFromSpecC3) {
+  {
+    // Header block to encode:
+    //   :method: GET
+    //   :scheme: http
+    //   :path: /
+    //   :authority: www.example.com
+    HpackBlockBuilder b;
+    b.AppendIndexedHeader(2);  // :method: GET
+    b.AppendIndexedHeader(6);  // :scheme: http
+    b.AppendIndexedHeader(4);  // :path: /
+    b.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 1,
+                                     kUncompressed, "www.example.com");
+    EXPECT_EQ(20u, b.size());
+
+    // Hex dump of encoded data (copied from RFC):
+    // 0x0000:  8286 8441 0f77 7777 2e65 7861 6d70 6c65  ...A.www.example
+    // 0x0010:  2e63 6f6d                                .com
+
+    const Http2String expected =
+        Http2HexDecode("828684410f7777772e6578616d706c652e636f6d");
+    EXPECT_EQ(expected, b.buffer());
+  }
+}
+
+// Tests of encoding per the RFC. See:
+//   http://httpwg.org/specs/rfc7541.html#request.examples.with.huffman.coding
+TEST(HpackBlockBuilderTest, ExamplesFromSpecC4) {
+  {
+    // Header block to encode:
+    //   :method: GET
+    //   :scheme: http
+    //   :path: /
+    //   :authority: www.example.com  (Huffman encoded)
+    HpackBlockBuilder b;
+    b.AppendIndexedHeader(kStaticTableMethodGET);
+    b.AppendIndexedHeader(kStaticTableSchemeHttp);
+    b.AppendIndexedHeader(kStaticTablePathSlash);
+    const char kHuffmanWwwExampleCom[] = {'\xf1', '\xe3', '\xc2', '\xe5',
+                                          '\xf2', '\x3a', '\x6b', '\xa0',
+                                          '\xab', '\x90', '\xf4', '\xff'};
+    b.AppendNameIndexAndLiteralValue(
+        HpackEntryType::kIndexedLiteralHeader, 1, kCompressed,
+        Http2StringPiece(kHuffmanWwwExampleCom, sizeof kHuffmanWwwExampleCom));
+    EXPECT_EQ(17u, b.size());
+
+    // Hex dump of encoded data (copied from RFC):
+    // 0x0000:  8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4  ...A......:k....
+    // 0x0010:  ff                                       .
+
+    const Http2String expected =
+        Http2HexDecode("828684418cf1e3c2e5f23a6ba0ab90f4ff");
+    EXPECT_EQ(expected, b.buffer());
+  }
+}
+
+TEST(HpackBlockBuilderTest, DynamicTableSizeUpdate) {
+  {
+    HpackBlockBuilder b;
+    b.AppendDynamicTableSizeUpdate(0);
+    EXPECT_EQ(1u, b.size());
+
+    const char kData[] = {'\x20'};
+    Http2StringPiece expected(kData, sizeof kData);
+    EXPECT_EQ(expected, b.buffer());
+  }
+  {
+    HpackBlockBuilder b;
+    b.AppendDynamicTableSizeUpdate(4096);  // The default size.
+    EXPECT_EQ(3u, b.size());
+
+    const char kData[] = {'\x3f', '\xe1', '\x1f'};
+    Http2StringPiece expected(kData, sizeof kData);
+    EXPECT_EQ(expected, b.buffer());
+  }
+  {
+    HpackBlockBuilder b;
+    b.AppendDynamicTableSizeUpdate(1000000000000);  // A very large value.
+    EXPECT_EQ(7u, b.size());
+
+    const char kData[] = {'\x3f', '\xe1', '\x9f', '\x94',
+                          '\xa5', '\x8d', '\x1d'};
+    Http2StringPiece expected(kData, sizeof kData);
+    EXPECT_EQ(expected, b.buffer());
+  }
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace http2
diff --git a/http2/hpack/tools/hpack_example.cc b/http2/hpack/tools/hpack_example.cc
new file mode 100644
index 0000000..d20eb35
--- /dev/null
+++ b/http2/hpack/tools/hpack_example.cc
@@ -0,0 +1,58 @@
+// 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/hpack/tools/hpack_example.h"
+
+#include <ctype.h>
+
+#include "base/logging.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_bug_tracker.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
+
+namespace http2 {
+namespace test {
+namespace {
+
+void HpackExampleToStringOrDie(Http2StringPiece example, Http2String* output) {
+  while (!example.empty()) {
+    const char c0 = example[0];
+    if (isxdigit(c0)) {
+      CHECK_GT(example.size(), 1u) << "Truncated hex byte?";
+      const char c1 = example[1];
+      CHECK(isxdigit(c1)) << "Found half a byte?";
+      *output += Http2HexDecode(example.substr(0, 2));
+      example.remove_prefix(2);
+      continue;
+    }
+    if (isspace(c0)) {
+      example.remove_prefix(1);
+      continue;
+    }
+    if (!example.empty() && example[0] == '|') {
+      // Start of a comment. Skip to end of line or of input.
+      auto pos = example.find('\n');
+      if (pos == Http2StringPiece::npos) {
+        // End of input.
+        break;
+      }
+      example.remove_prefix(pos + 1);
+      continue;
+    }
+    HTTP2_BUG << "Can't parse byte " << static_cast<int>(c0)
+              << Http2StrCat(" (0x", Http2Hex(c0), ")")
+              << "\nExample: " << example;
+  }
+  CHECK_LT(0u, output->size()) << "Example is empty.";
+}
+
+}  // namespace
+
+Http2String HpackExampleToStringOrDie(Http2StringPiece example) {
+  Http2String output;
+  HpackExampleToStringOrDie(example, &output);
+  return output;
+}
+
+}  // namespace test
+}  // namespace http2
diff --git a/http2/hpack/tools/hpack_example.h b/http2/hpack/tools/hpack_example.h
new file mode 100644
index 0000000..ddb22a3
--- /dev/null
+++ b/http2/hpack/tools/hpack_example.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef QUICHE_HTTP2_HPACK_TOOLS_HPACK_EXAMPLE_H_
+#define QUICHE_HTTP2_HPACK_TOOLS_HPACK_EXAMPLE_H_
+
+#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
+
+// Parses HPACK examples in the format seen in the HPACK specification,
+// RFC 7541. For example:
+//
+//       10                                      | == Literal never indexed ==
+//       08                                      |   Literal name (len = 8)
+//       7061 7373 776f 7264                     | password
+//       06                                      |   Literal value (len = 6)
+//       7365 6372 6574                          | secret
+//                                               | -> password: secret
+//
+// (excluding the leading "//").
+
+namespace http2 {
+namespace test {
+
+Http2String HpackExampleToStringOrDie(Http2StringPiece example);
+
+}  // namespace test
+}  // namespace http2
+
+#endif  // QUICHE_HTTP2_HPACK_TOOLS_HPACK_EXAMPLE_H_