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