| 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 |