| // Copyright (c) 2018 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/huffman/hpack_huffman_encoder.h" |
| |
| #include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h" |
| #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" |
| #include "net/third_party/quiche/src/common/platform/api/quiche_test.h" |
| |
| namespace http2 { |
| namespace { |
| |
| class HuffmanEncoderTest : public ::testing::TestWithParam<bool> { |
| protected: |
| HuffmanEncoderTest() : use_fast_encoder_(GetParam()) {} |
| virtual ~HuffmanEncoderTest() = default; |
| |
| void Encode(quiche::QuicheStringPiece input, |
| size_t encoded_size, |
| std::string* output) { |
| use_fast_encoder_ ? HuffmanEncodeFast(input, encoded_size, output) |
| : HuffmanEncode(input, encoded_size, output); |
| } |
| |
| const bool use_fast_encoder_; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(TwoEncoders, HuffmanEncoderTest, ::testing::Bool()); |
| |
| TEST_P(HuffmanEncoderTest, Empty) { |
| std::string empty(""); |
| size_t encoded_size = ExactHuffmanSize(empty); |
| EXPECT_EQ(0u, encoded_size); |
| |
| std::string buffer; |
| Encode(empty, encoded_size, &buffer); |
| EXPECT_EQ("", buffer); |
| } |
| |
| TEST_P(HuffmanEncoderTest, SpecRequestExamples) { |
| std::string test_table[] = { |
| Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"), |
| "www.example.com", |
| Http2HexDecode("a8eb10649cbf"), |
| "no-cache", |
| Http2HexDecode("25a849e95ba97d7f"), |
| "custom-key", |
| Http2HexDecode("25a849e95bb8e8b4bf"), |
| "custom-value", |
| }; |
| for (size_t i = 0; i != QUICHE_ARRAYSIZE(test_table); i += 2) { |
| const std::string& huffman_encoded(test_table[i]); |
| const std::string& plain_string(test_table[i + 1]); |
| size_t encoded_size = ExactHuffmanSize(plain_string); |
| EXPECT_EQ(huffman_encoded.size(), encoded_size); |
| EXPECT_EQ(BoundedHuffmanSize(plain_string), encoded_size); |
| std::string buffer; |
| buffer.reserve(); |
| Encode(plain_string, encoded_size, &buffer); |
| EXPECT_EQ(buffer, huffman_encoded) << "Error encoding " << plain_string; |
| } |
| } |
| |
| TEST_P(HuffmanEncoderTest, SpecResponseExamples) { |
| // clang-format off |
| std::string test_table[] = { |
| Http2HexDecode("6402"), |
| "302", |
| Http2HexDecode("aec3771a4b"), |
| "private", |
| Http2HexDecode("d07abe941054d444a8200595040b8166" |
| "e082a62d1bff"), |
| "Mon, 21 Oct 2013 20:13:21 GMT", |
| Http2HexDecode("9d29ad171863c78f0b97c8e9ae82ae43" |
| "d3"), |
| "https://www.example.com", |
| Http2HexDecode("94e7821dd7f2e6c7b335dfdfcd5b3960" |
| "d5af27087f3672c1ab270fb5291f9587" |
| "316065c003ed4ee5b1063d5007"), |
| "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", |
| }; |
| // clang-format on |
| for (size_t i = 0; i != QUICHE_ARRAYSIZE(test_table); i += 2) { |
| const std::string& huffman_encoded(test_table[i]); |
| const std::string& plain_string(test_table[i + 1]); |
| size_t encoded_size = ExactHuffmanSize(plain_string); |
| EXPECT_EQ(huffman_encoded.size(), encoded_size); |
| EXPECT_EQ(BoundedHuffmanSize(plain_string), encoded_size); |
| std::string buffer; |
| Encode(plain_string, encoded_size, &buffer); |
| EXPECT_EQ(buffer, huffman_encoded) << "Error encoding " << plain_string; |
| } |
| } |
| |
| TEST_P(HuffmanEncoderTest, EncodedSizeAgreesWithEncodeString) { |
| std::string test_table[] = { |
| "", |
| "Mon, 21 Oct 2013 20:13:21 GMT", |
| "https://www.example.com", |
| "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", |
| std::string(1, '\0'), |
| std::string("foo\0bar", 7), |
| std::string(256, '\0'), |
| }; |
| // Modify last |test_table| entry to cover all codes. |
| for (size_t i = 0; i != 256; ++i) { |
| test_table[QUICHE_ARRAYSIZE(test_table) - 1][i] = static_cast<char>(i); |
| } |
| |
| for (size_t i = 0; i != QUICHE_ARRAYSIZE(test_table); ++i) { |
| const std::string& plain_string = test_table[i]; |
| size_t encoded_size = ExactHuffmanSize(plain_string); |
| std::string huffman_encoded; |
| Encode(plain_string, encoded_size, &huffman_encoded); |
| EXPECT_EQ(encoded_size, huffman_encoded.size()); |
| EXPECT_LE(BoundedHuffmanSize(plain_string), plain_string.size()); |
| EXPECT_LE(BoundedHuffmanSize(plain_string), ExactHuffmanSize(plain_string)); |
| } |
| } |
| |
| TEST_P(HuffmanEncoderTest, AppendToOutput) { |
| size_t encoded_size = ExactHuffmanSize("foo"); |
| std::string buffer; |
| Encode("foo", encoded_size, &buffer); |
| EXPECT_EQ(Http2HexDecode("94e7"), buffer); |
| |
| encoded_size = ExactHuffmanSize("bar"); |
| Encode("bar", encoded_size, &buffer); |
| |
| if (use_fast_encoder_) { |
| // HuffmanEncodeFast() appends to output allowing callers to eliminate copy. |
| EXPECT_EQ(Http2HexDecode("94e78c767f"), buffer); |
| } else { |
| // HuffmanEncode() clears output before encoding. |
| EXPECT_EQ(Http2HexDecode("8c767f"), buffer); |
| } |
| } |
| |
| } // namespace |
| } // namespace http2 |