1 // Copyright (c) 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/http2/hpack/huffman/hpack_huffman_encoder.h"
6
7 #include "absl/base/macros.h"
8 #include "absl/strings/escaping.h"
9 #include "quiche/common/platform/api/quiche_test.h"
10
11 namespace http2 {
12 namespace {
13
14 class HuffmanEncoderTest : public quiche::test::QuicheTestWithParam<bool> {
15 protected:
HuffmanEncoderTest()16 HuffmanEncoderTest() : use_fast_encoder_(GetParam()) {}
17 virtual ~HuffmanEncoderTest() = default;
18
Encode(absl::string_view input,size_t encoded_size,std::string * output)19 void Encode(absl::string_view input, size_t encoded_size,
20 std::string* output) {
21 use_fast_encoder_ ? HuffmanEncodeFast(input, encoded_size, output)
22 : HuffmanEncode(input, encoded_size, output);
23 }
24
25 const bool use_fast_encoder_;
26 };
27
28 INSTANTIATE_TEST_SUITE_P(TwoEncoders, HuffmanEncoderTest, ::testing::Bool());
29
TEST_P(HuffmanEncoderTest,Empty)30 TEST_P(HuffmanEncoderTest, Empty) {
31 std::string empty("");
32 size_t encoded_size = HuffmanSize(empty);
33 EXPECT_EQ(0u, encoded_size);
34
35 std::string buffer;
36 Encode(empty, encoded_size, &buffer);
37 EXPECT_EQ("", buffer);
38 }
39
TEST_P(HuffmanEncoderTest,SpecRequestExamples)40 TEST_P(HuffmanEncoderTest, SpecRequestExamples) {
41 std::string test_table[] = {
42 absl::HexStringToBytes("f1e3c2e5f23a6ba0ab90f4ff"),
43 "www.example.com",
44 absl::HexStringToBytes("a8eb10649cbf"),
45 "no-cache",
46 absl::HexStringToBytes("25a849e95ba97d7f"),
47 "custom-key",
48 absl::HexStringToBytes("25a849e95bb8e8b4bf"),
49 "custom-value",
50 };
51 for (size_t i = 0; i != ABSL_ARRAYSIZE(test_table); i += 2) {
52 const std::string& huffman_encoded(test_table[i]);
53 const std::string& plain_string(test_table[i + 1]);
54 size_t encoded_size = HuffmanSize(plain_string);
55 EXPECT_EQ(huffman_encoded.size(), encoded_size);
56 std::string buffer;
57 buffer.reserve(huffman_encoded.size());
58 Encode(plain_string, encoded_size, &buffer);
59 EXPECT_EQ(buffer, huffman_encoded) << "Error encoding " << plain_string;
60 }
61 }
62
TEST_P(HuffmanEncoderTest,SpecResponseExamples)63 TEST_P(HuffmanEncoderTest, SpecResponseExamples) {
64 // clang-format off
65 std::string test_table[] = {
66 absl::HexStringToBytes("6402"),
67 "302",
68 absl::HexStringToBytes("aec3771a4b"),
69 "private",
70 absl::HexStringToBytes("d07abe941054d444a8200595040b8166"
71 "e082a62d1bff"),
72 "Mon, 21 Oct 2013 20:13:21 GMT",
73 absl::HexStringToBytes("9d29ad171863c78f0b97c8e9ae82ae43"
74 "d3"),
75 "https://www.example.com",
76 absl::HexStringToBytes("94e7821dd7f2e6c7b335dfdfcd5b3960"
77 "d5af27087f3672c1ab270fb5291f9587"
78 "316065c003ed4ee5b1063d5007"),
79 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
80 };
81 // clang-format on
82 for (size_t i = 0; i != ABSL_ARRAYSIZE(test_table); i += 2) {
83 const std::string& huffman_encoded(test_table[i]);
84 const std::string& plain_string(test_table[i + 1]);
85 size_t encoded_size = HuffmanSize(plain_string);
86 EXPECT_EQ(huffman_encoded.size(), encoded_size);
87 std::string buffer;
88 Encode(plain_string, encoded_size, &buffer);
89 EXPECT_EQ(buffer, huffman_encoded) << "Error encoding " << plain_string;
90 }
91 }
92
TEST_P(HuffmanEncoderTest,EncodedSizeAgreesWithEncodeString)93 TEST_P(HuffmanEncoderTest, EncodedSizeAgreesWithEncodeString) {
94 std::string test_table[] = {
95 "",
96 "Mon, 21 Oct 2013 20:13:21 GMT",
97 "https://www.example.com",
98 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
99 std::string(1, '\0'),
100 std::string("foo\0bar", 7),
101 std::string(256, '\0'),
102 };
103 // Modify last |test_table| entry to cover all codes.
104 for (size_t i = 0; i != 256; ++i) {
105 test_table[ABSL_ARRAYSIZE(test_table) - 1][i] = static_cast<char>(i);
106 }
107
108 for (size_t i = 0; i != ABSL_ARRAYSIZE(test_table); ++i) {
109 const std::string& plain_string = test_table[i];
110 size_t encoded_size = HuffmanSize(plain_string);
111 std::string huffman_encoded;
112 Encode(plain_string, encoded_size, &huffman_encoded);
113 EXPECT_EQ(encoded_size, huffman_encoded.size());
114 }
115 }
116
117 // Test that encoding appends to output without overwriting it.
TEST_P(HuffmanEncoderTest,AppendToOutput)118 TEST_P(HuffmanEncoderTest, AppendToOutput) {
119 size_t encoded_size = HuffmanSize("foo");
120 std::string buffer;
121 Encode("foo", encoded_size, &buffer);
122 EXPECT_EQ(absl::HexStringToBytes("94e7"), buffer);
123
124 encoded_size = HuffmanSize("bar");
125 Encode("bar", encoded_size, &buffer);
126 EXPECT_EQ(absl::HexStringToBytes("94e78c767f"), buffer);
127 }
128
129 } // namespace
130 } // namespace http2
131