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