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 |