1 // Copyright 2016 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/decoder/hpack_block_decoder.h"
6
7 // Tests of HpackBlockDecoder.
8
9 #include <cstdint>
10 #include <string>
11
12 #include "absl/strings/string_view.h"
13 #include "quiche/http2/decoder/decode_buffer.h"
14 #include "quiche/http2/hpack/http2_hpack_constants.h"
15 #include "quiche/http2/test_tools/hpack_block_builder.h"
16 #include "quiche/http2/test_tools/hpack_block_collector.h"
17 #include "quiche/http2/test_tools/hpack_example.h"
18 #include "quiche/http2/test_tools/http2_random.h"
19 #include "quiche/http2/test_tools/random_decoder_test_base.h"
20 #include "quiche/common/platform/api/quiche_expect_bug.h"
21 #include "quiche/common/platform/api/quiche_test.h"
22
23 namespace http2 {
24 namespace test {
25 namespace {
26
27 class HpackBlockDecoderTest : public RandomDecoderTest {
28 protected:
HpackBlockDecoderTest()29 HpackBlockDecoderTest() : listener_(&collector_), decoder_(&listener_) {
30 stop_decode_on_done_ = false;
31 decoder_.Reset();
32 // Make sure logging doesn't crash. Not examining the result.
33 std::ostringstream strm;
34 strm << decoder_;
35 }
36
StartDecoding(DecodeBuffer * db)37 DecodeStatus StartDecoding(DecodeBuffer* db) override {
38 collector_.Clear();
39 decoder_.Reset();
40 return ResumeDecoding(db);
41 }
42
ResumeDecoding(DecodeBuffer * db)43 DecodeStatus ResumeDecoding(DecodeBuffer* db) override {
44 DecodeStatus status = decoder_.Decode(db);
45
46 // Make sure logging doesn't crash. Not examining the result.
47 std::ostringstream strm;
48 strm << decoder_;
49
50 return status;
51 }
52
DecodeAndValidateSeveralWays(DecodeBuffer * db,const Validator & validator)53 AssertionResult DecodeAndValidateSeveralWays(DecodeBuffer* db,
54 const Validator& validator) {
55 bool return_non_zero_on_first = false;
56 return RandomDecoderTest::DecodeAndValidateSeveralWays(
57 db, return_non_zero_on_first, validator);
58 }
59
DecodeAndValidateSeveralWays(const HpackBlockBuilder & hbb,const Validator & validator)60 AssertionResult DecodeAndValidateSeveralWays(const HpackBlockBuilder& hbb,
61 const Validator& validator) {
62 DecodeBuffer db(hbb.buffer());
63 return DecodeAndValidateSeveralWays(&db, validator);
64 }
65
DecodeHpackExampleAndValidateSeveralWays(absl::string_view hpack_example,Validator validator)66 AssertionResult DecodeHpackExampleAndValidateSeveralWays(
67 absl::string_view hpack_example, Validator validator) {
68 std::string input = HpackExampleToStringOrDie(hpack_example);
69 DecodeBuffer db(input);
70 return DecodeAndValidateSeveralWays(&db, validator);
71 }
72
Rand8()73 uint8_t Rand8() { return Random().Rand8(); }
74
Rand8String()75 std::string Rand8String() { return Random().RandString(Rand8()); }
76
77 HpackBlockCollector collector_;
78 HpackEntryDecoderVLoggingListener listener_;
79 HpackBlockDecoder decoder_;
80 };
81
82 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.1
TEST_F(HpackBlockDecoderTest,SpecExample_C_2_1)83 TEST_F(HpackBlockDecoderTest, SpecExample_C_2_1) {
84 auto do_check = [this]() {
85 return collector_.ValidateSoleLiteralNameValueHeader(
86 HpackEntryType::kIndexedLiteralHeader, false, "custom-key", false,
87 "custom-header");
88 };
89 const char hpack_example[] = R"(
90 40 | == Literal indexed ==
91 0a | Literal name (len = 10)
92 6375 7374 6f6d 2d6b 6579 | custom-key
93 0d | Literal value (len = 13)
94 6375 7374 6f6d 2d68 6561 6465 72 | custom-header
95 | -> custom-key:
96 | custom-header
97 )";
98 EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
99 hpack_example, ValidateDoneAndEmpty(do_check)));
100 EXPECT_TRUE(do_check());
101 }
102
103 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.2
TEST_F(HpackBlockDecoderTest,SpecExample_C_2_2)104 TEST_F(HpackBlockDecoderTest, SpecExample_C_2_2) {
105 auto do_check = [this]() {
106 return collector_.ValidateSoleLiteralValueHeader(
107 HpackEntryType::kUnindexedLiteralHeader, 4, false, "/sample/path");
108 };
109 const char hpack_example[] = R"(
110 04 | == Literal not indexed ==
111 | Indexed name (idx = 4)
112 | :path
113 0c | Literal value (len = 12)
114 2f73 616d 706c 652f 7061 7468 | /sample/path
115 | -> :path: /sample/path
116 )";
117 EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
118 hpack_example, ValidateDoneAndEmpty(do_check)));
119 EXPECT_TRUE(do_check());
120 }
121
122 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.3
TEST_F(HpackBlockDecoderTest,SpecExample_C_2_3)123 TEST_F(HpackBlockDecoderTest, SpecExample_C_2_3) {
124 auto do_check = [this]() {
125 return collector_.ValidateSoleLiteralNameValueHeader(
126 HpackEntryType::kNeverIndexedLiteralHeader, false, "password", false,
127 "secret");
128 };
129 const char hpack_example[] = R"(
130 10 | == Literal never indexed ==
131 08 | Literal name (len = 8)
132 7061 7373 776f 7264 | password
133 06 | Literal value (len = 6)
134 7365 6372 6574 | secret
135 | -> password: secret
136 )";
137 EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
138 hpack_example, ValidateDoneAndEmpty(do_check)));
139 EXPECT_TRUE(do_check());
140 }
141
142 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.4
TEST_F(HpackBlockDecoderTest,SpecExample_C_2_4)143 TEST_F(HpackBlockDecoderTest, SpecExample_C_2_4) {
144 auto do_check = [this]() { return collector_.ValidateSoleIndexedHeader(2); };
145 const char hpack_example[] = R"(
146 82 | == Indexed - Add ==
147 | idx = 2
148 | -> :method: GET
149 )";
150 EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
151 hpack_example, ValidateDoneAndEmpty(do_check)));
152 EXPECT_TRUE(do_check());
153 }
154 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
TEST_F(HpackBlockDecoderTest,SpecExample_C_3_1)155 TEST_F(HpackBlockDecoderTest, SpecExample_C_3_1) {
156 std::string example = R"(
157 82 | == Indexed - Add ==
158 | idx = 2
159 | -> :method: GET
160 86 | == Indexed - Add ==
161 | idx = 6
162 | -> :scheme: http
163 84 | == Indexed - Add ==
164 | idx = 4
165 | -> :path: /
166 41 | == Literal indexed ==
167 | Indexed name (idx = 1)
168 | :authority
169 0f | Literal value (len = 15)
170 7777 772e 6578 616d 706c 652e 636f 6d | www.example.com
171 | -> :authority:
172 | www.example.com
173 )";
174 HpackBlockCollector expected;
175 expected.ExpectIndexedHeader(2);
176 expected.ExpectIndexedHeader(6);
177 expected.ExpectIndexedHeader(4);
178 expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
179 1, false, "www.example.com");
180 EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
181 example,
182 ValidateDoneAndEmpty([&] { return collector_.VerifyEq(expected); })));
183 EXPECT_TRUE(collector_.VerifyEq(expected));
184 }
185
186 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.5.1
TEST_F(HpackBlockDecoderTest,SpecExample_C_5_1)187 TEST_F(HpackBlockDecoderTest, SpecExample_C_5_1) {
188 std::string example = R"(
189 48 | == Literal indexed ==
190 | Indexed name (idx = 8)
191 | :status
192 03 | Literal value (len = 3)
193 3330 32 | 302
194 | -> :status: 302
195 58 | == Literal indexed ==
196 | Indexed name (idx = 24)
197 | cache-control
198 07 | Literal value (len = 7)
199 7072 6976 6174 65 | private
200 | -> cache-control: private
201 61 | == Literal indexed ==
202 | Indexed name (idx = 33)
203 | date
204 1d | Literal value (len = 29)
205 4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
206 2032 303a 3133 3a32 3120 474d 54 | 20:13:21 GMT
207 | -> date: Mon, 21 Oct 2013
208 | 20:13:21 GMT
209 6e | == Literal indexed ==
210 | Indexed name (idx = 46)
211 | location
212 17 | Literal value (len = 23)
213 6874 7470 733a 2f2f 7777 772e 6578 616d | https://www.exam
214 706c 652e 636f 6d | ple.com
215 | -> location:
216 | https://www.example.com
217 )";
218 HpackBlockCollector expected;
219 expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
220 8, false, "302");
221 expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
222 24, false, "private");
223 expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
224 33, false,
225 "Mon, 21 Oct 2013 20:13:21 GMT");
226 expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
227 46, false, "https://www.example.com");
228 EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
229 example,
230 ValidateDoneAndEmpty([&] { return collector_.VerifyEq(expected); })));
231 EXPECT_TRUE(collector_.VerifyEq(expected));
232 }
233
234 // Generate a bunch of HPACK block entries to expect, use those expectations
235 // to generate an HPACK block, then decode it and confirm it matches those
236 // expectations. Some of these are invalid (such as Indexed, with index=0),
237 // but well-formed, and the decoder doesn't check for validity, just
238 // well-formedness. That includes the validity of the strings not being checked,
239 // such as lower-case ascii for the names, and valid Huffman encodings.
TEST_F(HpackBlockDecoderTest,Computed)240 TEST_F(HpackBlockDecoderTest, Computed) {
241 HpackBlockCollector expected;
242 expected.ExpectIndexedHeader(0);
243 expected.ExpectIndexedHeader(1);
244 expected.ExpectIndexedHeader(126);
245 expected.ExpectIndexedHeader(127);
246 expected.ExpectIndexedHeader(128);
247 expected.ExpectDynamicTableSizeUpdate(0);
248 expected.ExpectDynamicTableSizeUpdate(1);
249 expected.ExpectDynamicTableSizeUpdate(14);
250 expected.ExpectDynamicTableSizeUpdate(15);
251 expected.ExpectDynamicTableSizeUpdate(30);
252 expected.ExpectDynamicTableSizeUpdate(31);
253 expected.ExpectDynamicTableSizeUpdate(4095);
254 expected.ExpectDynamicTableSizeUpdate(4096);
255 expected.ExpectDynamicTableSizeUpdate(8192);
256 for (auto type : {HpackEntryType::kIndexedLiteralHeader,
257 HpackEntryType::kUnindexedLiteralHeader,
258 HpackEntryType::kNeverIndexedLiteralHeader}) {
259 for (bool value_huffman : {false, true}) {
260 // An entry with an index for the name. Ensure the name index
261 // is not zero by adding one to the Rand8() result.
262 expected.ExpectNameIndexAndLiteralValue(type, Rand8() + 1, value_huffman,
263 Rand8String());
264 // And two entries with literal names, one plain, one huffman encoded.
265 expected.ExpectLiteralNameAndValue(type, false, Rand8String(),
266 value_huffman, Rand8String());
267 expected.ExpectLiteralNameAndValue(type, true, Rand8String(),
268 value_huffman, Rand8String());
269 }
270 }
271 // Shuffle the entries and serialize them to produce an HPACK block.
272 expected.ShuffleEntries(RandomPtr());
273 HpackBlockBuilder hbb;
274 expected.AppendToHpackBlockBuilder(&hbb);
275
276 EXPECT_TRUE(DecodeAndValidateSeveralWays(
277 hbb,
278 ValidateDoneAndEmpty([&] { return collector_.VerifyEq(expected); })));
279 EXPECT_TRUE(collector_.VerifyEq(expected));
280 }
281
282 } // namespace
283 } // namespace test
284 } // namespace http2
285