| Index: net/http2/hpack/decoder/hpack_block_decoder_test.cc
 | 
| diff --git a/net/http2/hpack/decoder/hpack_block_decoder_test.cc b/net/http2/hpack/decoder/hpack_block_decoder_test.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..421f0fc59dbbf15dfb3c595126fe0a16df803e4b
 | 
| --- /dev/null
 | 
| +++ b/net/http2/hpack/decoder/hpack_block_decoder_test.cc
 | 
| @@ -0,0 +1,315 @@
 | 
| +// 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/http2/hpack/decoder/hpack_block_decoder.h"
 | 
| +
 | 
| +// Tests of HpackBlockDecoder.
 | 
| +
 | 
| +#include <sstream>
 | 
| +
 | 
| +#include "base/bind.h"
 | 
| +#include "base/bind_helpers.h"
 | 
| +#include "net/http2/decoder/decode_buffer.h"
 | 
| +#include "net/http2/hpack/decoder/hpack_block_collector.h"
 | 
| +#include "net/http2/hpack/http2_hpack_constants.h"
 | 
| +#include "net/http2/hpack/tools/hpack_block_builder.h"
 | 
| +#include "net/http2/hpack/tools/hpack_example.h"
 | 
| +#include "net/http2/tools/failure.h"
 | 
| +#include "net/http2/tools/http2_random.h"
 | 
| +#include "net/http2/tools/random_decoder_test.h"
 | 
| +#include "testing/gtest/include/gtest/gtest.h"
 | 
| +
 | 
| +using ::testing::AssertionSuccess;
 | 
| +using std::string;
 | 
| +using base::StringPiece;
 | 
| +
 | 
| +namespace net {
 | 
| +namespace test {
 | 
| +namespace {
 | 
| +
 | 
| +class HpackBlockDecoderTest : public RandomDecoderTest {
 | 
| + public:
 | 
| +  AssertionResult VerifyExpected(const HpackBlockCollector& expected) {
 | 
| +    VERIFY_AND_RETURN_SUCCESS(collector_.VerifyEq(expected));
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult ValidateForSpecExample_C_2_1() {
 | 
| +    VERIFY_AND_RETURN_SUCCESS(collector_.ValidateSoleLiteralNameValueHeader(
 | 
| +        HpackEntryType::kIndexedLiteralHeader, false, "custom-key", false,
 | 
| +        "custom-header"));
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult ValidateForSpecExample_C_2_2() {
 | 
| +    VERIFY_AND_RETURN_SUCCESS(collector_.ValidateSoleLiteralValueHeader(
 | 
| +        HpackEntryType::kUnindexedLiteralHeader, 4, false, "/sample/path"));
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult ValidateForSpecExample_C_2_3() {
 | 
| +    VERIFY_AND_RETURN_SUCCESS(collector_.ValidateSoleLiteralNameValueHeader(
 | 
| +        HpackEntryType::kNeverIndexedLiteralHeader, false, "password", false,
 | 
| +        "secret"));
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult ValidateForSpecExample_C_2_4() {
 | 
| +    VERIFY_AND_RETURN_SUCCESS(collector_.ValidateSoleIndexedHeader(2));
 | 
| +  }
 | 
| +
 | 
| + protected:
 | 
| +  HpackBlockDecoderTest() : listener_(&collector_), decoder_(&listener_) {
 | 
| +    stop_decode_on_done_ = false;
 | 
| +    decoder_.Reset();
 | 
| +    // Make sure logging doesn't crash. Not examining the result.
 | 
| +    std::ostringstream strm;
 | 
| +    strm << decoder_;
 | 
| +  }
 | 
| +
 | 
| +  DecodeStatus StartDecoding(DecodeBuffer* db) override {
 | 
| +    collector_.Clear();
 | 
| +    decoder_.Reset();
 | 
| +    return ResumeDecoding(db);
 | 
| +  }
 | 
| +
 | 
| +  DecodeStatus ResumeDecoding(DecodeBuffer* db) override {
 | 
| +    DecodeStatus status = decoder_.Decode(db);
 | 
| +
 | 
| +    // Make sure logging doesn't crash. Not examining the result.
 | 
| +    std::ostringstream strm;
 | 
| +    strm << decoder_;
 | 
| +
 | 
| +    return status;
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult DecodeAndValidateSeveralWays(DecodeBuffer* db,
 | 
| +                                               Validator validator) {
 | 
| +    bool return_non_zero_on_first = false;
 | 
| +    return RandomDecoderTest::DecodeAndValidateSeveralWays(
 | 
| +        db, return_non_zero_on_first, validator);
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult DecodeAndValidateSeveralWays(const HpackBlockBuilder& hbb,
 | 
| +                                               Validator validator) {
 | 
| +    DecodeBuffer db(hbb.buffer());
 | 
| +    return DecodeAndValidateSeveralWays(&db, validator);
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult DecodeHpackExampleAndValidateSeveralWays(
 | 
| +      StringPiece hpack_example,
 | 
| +      Validator validator) {
 | 
| +    string input = HpackExampleToStringOrDie(hpack_example);
 | 
| +    DecodeBuffer db(input);
 | 
| +    return DecodeAndValidateSeveralWays(&db, validator);
 | 
| +  }
 | 
| +
 | 
| +  uint8_t Rand8() { return Random().Rand8(); }
 | 
| +
 | 
| +  string Rand8String() { return Random().RandString(Rand8()); }
 | 
| +
 | 
| +  HpackBlockCollector collector_;
 | 
| +  HpackEntryDecoderVLoggingListener listener_;
 | 
| +  HpackBlockDecoder decoder_;
 | 
| +};
 | 
| +
 | 
| +// http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.1
 | 
| +TEST_F(HpackBlockDecoderTest, SpecExample_C_2_1) {
 | 
| +  NoArgValidator do_check =
 | 
| +      base::Bind(&HpackBlockDecoderTest::ValidateForSpecExample_C_2_1,
 | 
| +                 base::Unretained(this));
 | 
| +  EXPECT_TRUE(
 | 
| +      DecodeHpackExampleAndValidateSeveralWays(R"(
 | 
| +      40                                      | == Literal indexed ==
 | 
| +      0a                                      |   Literal name (len = 10)
 | 
| +      6375 7374 6f6d 2d6b 6579                | custom-key
 | 
| +      0d                                      |   Literal value (len = 13)
 | 
| +      6375 7374 6f6d 2d68 6561 6465 72        | custom-header
 | 
| +                                              | -> custom-key:
 | 
| +                                              |   custom-header
 | 
| +      )",
 | 
| +                                               ValidateDoneAndEmpty(do_check)));
 | 
| +  EXPECT_TRUE(do_check.Run());
 | 
| +}
 | 
| +
 | 
| +// http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.2
 | 
| +TEST_F(HpackBlockDecoderTest, SpecExample_C_2_2) {
 | 
| +  NoArgValidator do_check =
 | 
| +      base::Bind(&HpackBlockDecoderTest::ValidateForSpecExample_C_2_2,
 | 
| +                 base::Unretained(this));
 | 
| +  EXPECT_TRUE(
 | 
| +      DecodeHpackExampleAndValidateSeveralWays(R"(
 | 
| +      04                                      | == Literal not indexed ==
 | 
| +                                              |   Indexed name (idx = 4)
 | 
| +                                              |     :path
 | 
| +      0c                                      |   Literal value (len = 12)
 | 
| +      2f73 616d 706c 652f 7061 7468           | /sample/path
 | 
| +                                              | -> :path: /sample/path
 | 
| +      )",
 | 
| +                                               ValidateDoneAndEmpty(do_check)));
 | 
| +  EXPECT_TRUE(do_check.Run());
 | 
| +}
 | 
| +
 | 
| +// http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.3
 | 
| +TEST_F(HpackBlockDecoderTest, SpecExample_C_2_3) {
 | 
| +  NoArgValidator do_check =
 | 
| +      base::Bind(&HpackBlockDecoderTest::ValidateForSpecExample_C_2_3,
 | 
| +                 base::Unretained(this));
 | 
| +  EXPECT_TRUE(
 | 
| +      DecodeHpackExampleAndValidateSeveralWays(R"(
 | 
| +      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
 | 
| +      )",
 | 
| +                                               ValidateDoneAndEmpty(do_check)));
 | 
| +  EXPECT_TRUE(do_check.Run());
 | 
| +}
 | 
| +
 | 
| +// http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.4
 | 
| +TEST_F(HpackBlockDecoderTest, SpecExample_C_2_4) {
 | 
| +  NoArgValidator do_check =
 | 
| +      base::Bind(&HpackBlockDecoderTest::ValidateForSpecExample_C_2_4,
 | 
| +                 base::Unretained(this));
 | 
| +  EXPECT_TRUE(
 | 
| +      DecodeHpackExampleAndValidateSeveralWays(R"(
 | 
| +      82                                      | == Indexed - Add ==
 | 
| +                                              |   idx = 2
 | 
| +                                              | -> :method: GET
 | 
| +      )",
 | 
| +                                               ValidateDoneAndEmpty(do_check)));
 | 
| +  EXPECT_TRUE(do_check.Run());
 | 
| +}
 | 
| +// http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
 | 
| +TEST_F(HpackBlockDecoderTest, SpecExample_C_3_1) {
 | 
| +  string example = R"(
 | 
| +      82                                      | == Indexed - Add ==
 | 
| +                                              |   idx = 2
 | 
| +                                              | -> :method: GET
 | 
| +      86                                      | == Indexed - Add ==
 | 
| +                                              |   idx = 6
 | 
| +                                              | -> :scheme: http
 | 
| +      84                                      | == Indexed - Add ==
 | 
| +                                              |   idx = 4
 | 
| +                                              | -> :path: /
 | 
| +      41                                      | == Literal indexed ==
 | 
| +                                              |   Indexed name (idx = 1)
 | 
| +                                              |     :authority
 | 
| +      0f                                      |   Literal value (len = 15)
 | 
| +      7777 772e 6578 616d 706c 652e 636f 6d   | www.example.com
 | 
| +                                              | -> :authority:
 | 
| +                                              |   www.example.com
 | 
| +      )";
 | 
| +  HpackBlockCollector expected;
 | 
| +  expected.ExpectIndexedHeader(2);
 | 
| +  expected.ExpectIndexedHeader(6);
 | 
| +  expected.ExpectIndexedHeader(4);
 | 
| +  expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
 | 
| +                                          1, false, "www.example.com");
 | 
| +  NoArgValidator do_check = base::Bind(&HpackBlockDecoderTest::VerifyExpected,
 | 
| +                                       base::Unretained(this), expected);
 | 
| +  EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
 | 
| +      example, ValidateDoneAndEmpty(do_check)));
 | 
| +  EXPECT_TRUE(do_check.Run());
 | 
| +}
 | 
| +
 | 
| +// http://httpwg.org/specs/rfc7541.html#rfc.section.C.5.1
 | 
| +TEST_F(HpackBlockDecoderTest, SpecExample_C_5_1) {
 | 
| +  string example = R"(
 | 
| +      48                                      | == Literal indexed ==
 | 
| +                                              |   Indexed name (idx = 8)
 | 
| +                                              |     :status
 | 
| +      03                                      |   Literal value (len = 3)
 | 
| +      3330 32                                 | 302
 | 
| +                                              | -> :status: 302
 | 
| +      58                                      | == Literal indexed ==
 | 
| +                                              |   Indexed name (idx = 24)
 | 
| +                                              |     cache-control
 | 
| +      07                                      |   Literal value (len = 7)
 | 
| +      7072 6976 6174 65                       | private
 | 
| +                                              | -> cache-control: private
 | 
| +      61                                      | == Literal indexed ==
 | 
| +                                              |   Indexed name (idx = 33)
 | 
| +                                              |     date
 | 
| +      1d                                      |   Literal value (len = 29)
 | 
| +      4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
 | 
| +      2032 303a 3133 3a32 3120 474d 54        |  20:13:21 GMT
 | 
| +                                              | -> date: Mon, 21 Oct 2013
 | 
| +                                              |   20:13:21 GMT
 | 
| +      6e                                      | == Literal indexed ==
 | 
| +                                              |   Indexed name (idx = 46)
 | 
| +                                              |     location
 | 
| +      17                                      |   Literal value (len = 23)
 | 
| +      6874 7470 733a 2f2f 7777 772e 6578 616d | https://www.exam
 | 
| +      706c 652e 636f 6d                       | ple.com
 | 
| +                                              | -> location:
 | 
| +                                              |   https://www.example.com
 | 
| +      )";
 | 
| +  HpackBlockCollector expected;
 | 
| +  expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
 | 
| +                                          8, false, "302");
 | 
| +  expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
 | 
| +                                          24, false, "private");
 | 
| +  expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
 | 
| +                                          33, false,
 | 
| +                                          "Mon, 21 Oct 2013 20:13:21 GMT");
 | 
| +  expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
 | 
| +                                          46, false, "https://www.example.com");
 | 
| +  NoArgValidator do_check = base::Bind(&HpackBlockDecoderTest::VerifyExpected,
 | 
| +                                       base::Unretained(this), expected);
 | 
| +  EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
 | 
| +      example, ValidateDoneAndEmpty(do_check)));
 | 
| +  EXPECT_TRUE(do_check.Run());
 | 
| +}
 | 
| +
 | 
| +// Generate a bunch of HPACK block entries to expect, use those expectations
 | 
| +// to generate an HPACK block, then decode it and confirm it matches those
 | 
| +// expectations. Some of these are invalid (such as Indexed, with index=0),
 | 
| +// but well-formed, and the decoder doesn't check for validity, just
 | 
| +// well-formedness. That includes the validity of the strings not being checked,
 | 
| +// such as lower-case ascii for the names, and valid Huffman encodings.
 | 
| +TEST_F(HpackBlockDecoderTest, Computed) {
 | 
| +  HpackBlockCollector expected;
 | 
| +  expected.ExpectIndexedHeader(0);
 | 
| +  expected.ExpectIndexedHeader(1);
 | 
| +  expected.ExpectIndexedHeader(126);
 | 
| +  expected.ExpectIndexedHeader(127);
 | 
| +  expected.ExpectIndexedHeader(128);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(0);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(1);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(14);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(15);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(30);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(31);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(4095);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(4096);
 | 
| +  expected.ExpectDynamicTableSizeUpdate(8192);
 | 
| +  for (auto type : {HpackEntryType::kIndexedLiteralHeader,
 | 
| +                    HpackEntryType::kUnindexedLiteralHeader,
 | 
| +                    HpackEntryType::kNeverIndexedLiteralHeader}) {
 | 
| +    for (bool value_huffman : {false, true}) {
 | 
| +      // An entry with an index for the name. Ensure the name index
 | 
| +      // is not zero by adding one to the Rand8() result.
 | 
| +      expected.ExpectNameIndexAndLiteralValue(type, Rand8() + 1, value_huffman,
 | 
| +                                              Rand8String());
 | 
| +      // And two entries with literal names, one plain, one huffman encoded.
 | 
| +      expected.ExpectLiteralNameAndValue(type, false, Rand8String(),
 | 
| +                                         value_huffman, Rand8String());
 | 
| +      expected.ExpectLiteralNameAndValue(type, true, Rand8String(),
 | 
| +                                         value_huffman, Rand8String());
 | 
| +    }
 | 
| +  }
 | 
| +  // Shuffle the entries and serialize them to produce an HPACK block.
 | 
| +  expected.ShuffleEntries(RandomPtr());
 | 
| +  HpackBlockBuilder hbb;
 | 
| +  expected.AppendToHpackBlockBuilder(&hbb);
 | 
| +
 | 
| +  NoArgValidator do_check = base::Bind(&HpackBlockDecoderTest::VerifyExpected,
 | 
| +                                       base::Unretained(this), expected);
 | 
| +  EXPECT_TRUE(
 | 
| +      DecodeAndValidateSeveralWays(hbb, ValidateDoneAndEmpty(do_check)));
 | 
| +  EXPECT_TRUE(do_check.Run());
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +}  // namespace test
 | 
| +}  // namespace net
 | 
| 
 |