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 <cstddef>
8 #include <string>
9
10 #include "absl/base/macros.h"
11 #include "absl/strings/escaping.h"
12 #include "quiche/common/platform/api/quiche_test.h"
13
14 namespace http2 {
15 namespace {
16
17 class HuffmanEncoderTest : public quiche::test::QuicheTestWithParam<bool> {
18 protected:
HuffmanEncoderTest()19 HuffmanEncoderTest() : use_fast_encoder_(GetParam()) {}
20 virtual ~HuffmanEncoderTest() = default;
21
Encode(absl::string_view input,size_t encoded_size,std::string * output)22 void Encode(absl::string_view input, size_t encoded_size,
23 std::string* output) {
24 use_fast_encoder_ ? HuffmanEncodeFast(input, encoded_size, output)
25 : HuffmanEncode(input, encoded_size, output);
26 }
27
28 const bool use_fast_encoder_;
29 };
30
31 INSTANTIATE_TEST_SUITE_P(TwoEncoders, HuffmanEncoderTest, ::testing::Bool());
32
TEST_P(HuffmanEncoderTest,Empty)33 TEST_P(HuffmanEncoderTest, Empty) {
34 std::string empty("");
35 size_t encoded_size = HuffmanSize(empty);
36 EXPECT_EQ(0u, encoded_size);
37
38 std::string buffer;
39 Encode(empty, encoded_size, &buffer);
40 EXPECT_EQ("", buffer);
41 }
42
TEST_P(HuffmanEncoderTest,SpecRequestExamples)43 TEST_P(HuffmanEncoderTest, SpecRequestExamples) {
44 std::string test_table[] = {
45 "f1e3c2e5f23a6ba0ab90f4ff",
46 "www.example.com",
47
48 "a8eb10649cbf",
49 "no-cache",
50
51 "25a849e95ba97d7f",
52 "custom-key",
53
54 "25a849e95bb8e8b4bf",
55 "custom-value",
56 };
57 for (size_t i = 0; i != ABSL_ARRAYSIZE(test_table); i += 2) {
58 std::string huffman_encoded;
59 ASSERT_TRUE(absl::HexStringToBytes(test_table[i], &huffman_encoded));
60 const std::string& plain_string(test_table[i + 1]);
61 size_t encoded_size = HuffmanSize(plain_string);
62 EXPECT_EQ(huffman_encoded.size(), encoded_size);
63 std::string buffer;
64 buffer.reserve(huffman_encoded.size());
65 Encode(plain_string, encoded_size, &buffer);
66 EXPECT_EQ(buffer, huffman_encoded) << "Error encoding " << plain_string;
67 }
68 }
69
TEST_P(HuffmanEncoderTest,SpecResponseExamples)70 TEST_P(HuffmanEncoderTest, SpecResponseExamples) {
71 std::string test_table[] = {
72 "6402",
73 "302",
74
75 "aec3771a4b",
76 "private",
77
78 "d07abe941054d444a8200595040b8166e082a62d1bff",
79 "Mon, 21 Oct 2013 20:13:21 GMT",
80
81 "9d29ad171863c78f0b97c8e9ae82ae43d3",
82 "https://www.example.com",
83
84 "94e7821dd7f2e6c7b335dfdfcd5b3960d5af27087f3672c1ab270fb5291f9587316065c0"
85 "03ed4ee5b1063d5007",
86 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
87 };
88 for (size_t i = 0; i != ABSL_ARRAYSIZE(test_table); i += 2) {
89 std::string huffman_encoded;
90 ASSERT_TRUE(absl::HexStringToBytes(test_table[i], &huffman_encoded));
91 const std::string& plain_string(test_table[i + 1]);
92 size_t encoded_size = HuffmanSize(plain_string);
93 EXPECT_EQ(huffman_encoded.size(), encoded_size);
94 std::string buffer;
95 Encode(plain_string, encoded_size, &buffer);
96 EXPECT_EQ(buffer, huffman_encoded) << "Error encoding " << plain_string;
97 }
98 }
99
TEST_P(HuffmanEncoderTest,EncodedSizeAgreesWithEncodeString)100 TEST_P(HuffmanEncoderTest, EncodedSizeAgreesWithEncodeString) {
101 std::string test_table[] = {
102 "",
103 "Mon, 21 Oct 2013 20:13:21 GMT",
104 "https://www.example.com",
105 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
106 std::string(1, '\0'),
107 std::string("foo\0bar", 7),
108 std::string(256, '\0'),
109 };
110 // Modify last |test_table| entry to cover all codes.
111 for (size_t i = 0; i != 256; ++i) {
112 test_table[ABSL_ARRAYSIZE(test_table) - 1][i] = static_cast<char>(i);
113 }
114
115 for (size_t i = 0; i != ABSL_ARRAYSIZE(test_table); ++i) {
116 const std::string& plain_string = test_table[i];
117 size_t encoded_size = HuffmanSize(plain_string);
118 std::string huffman_encoded;
119 Encode(plain_string, encoded_size, &huffman_encoded);
120 EXPECT_EQ(encoded_size, huffman_encoded.size());
121 }
122 }
123
124 // Test that encoding appends to output without overwriting it.
TEST_P(HuffmanEncoderTest,AppendToOutput)125 TEST_P(HuffmanEncoderTest, AppendToOutput) {
126 size_t encoded_size = HuffmanSize("foo");
127 std::string buffer;
128 Encode("foo", encoded_size, &buffer);
129 std::string expected_encoding;
130 ASSERT_TRUE(absl::HexStringToBytes("94e7", &expected_encoding));
131 EXPECT_EQ(expected_encoding, buffer);
132
133 encoded_size = HuffmanSize("bar");
134 Encode("bar", encoded_size, &buffer);
135 ASSERT_TRUE(absl::HexStringToBytes("94e78c767f", &expected_encoding));
136 EXPECT_EQ(expected_encoding, buffer);
137 }
138
139 } // namespace
140 } // namespace http2
141