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