| 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/huffman/http2_hpack_huffman_decoder.h" | |
| 6 | |
| 7 // Tests of HpackHuffmanDecoder and HuffmanBitBuffer. | |
| 8 | |
| 9 #include <iostream> | |
| 10 #include <string> | |
| 11 | |
| 12 #include "base/bind.h" | |
| 13 #include "base/bind_helpers.h" | |
| 14 #include "base/macros.h" | |
| 15 #include "base/strings/string_piece.h" | |
| 16 #include "net/http2/decoder/decode_buffer.h" | |
| 17 #include "net/http2/decoder/decode_status.h" | |
| 18 #include "net/http2/tools/failure.h" | |
| 19 #include "net/http2/tools/random_decoder_test.h" | |
| 20 #include "net/spdy/spdy_test_utils.h" | |
| 21 #include "testing/gtest/include/gtest/gtest.h" | |
| 22 | |
| 23 using ::testing::AssertionResult; | |
| 24 using ::testing::AssertionSuccess; | |
| 25 using base::StringPiece; | |
| 26 using std::string; | |
| 27 | |
| 28 namespace net { | |
| 29 namespace test { | |
| 30 namespace { | |
| 31 | |
| 32 TEST(HuffmanBitBufferTest, Reset) { | |
| 33 HuffmanBitBuffer bb; | |
| 34 EXPECT_TRUE(bb.IsEmpty()); | |
| 35 EXPECT_TRUE(bb.InputProperlyTerminated()); | |
| 36 EXPECT_EQ(bb.count(), 0u); | |
| 37 EXPECT_EQ(bb.free_count(), 64u); | |
| 38 EXPECT_EQ(bb.value(), 0u); | |
| 39 } | |
| 40 | |
| 41 TEST(HuffmanBitBufferTest, AppendBytesAligned) { | |
| 42 string s; | |
| 43 s.push_back('\x11'); | |
| 44 s.push_back('\x22'); | |
| 45 s.push_back('\x33'); | |
| 46 StringPiece sp(s); | |
| 47 | |
| 48 HuffmanBitBuffer bb; | |
| 49 sp.remove_prefix(bb.AppendBytes(sp)); | |
| 50 EXPECT_TRUE(sp.empty()); | |
| 51 EXPECT_FALSE(bb.IsEmpty()) << bb; | |
| 52 EXPECT_FALSE(bb.InputProperlyTerminated()); | |
| 53 EXPECT_EQ(bb.count(), 24u) << bb; | |
| 54 EXPECT_EQ(bb.free_count(), 40u) << bb; | |
| 55 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x112233) << 40) << bb; | |
| 56 | |
| 57 s.clear(); | |
| 58 s.push_back('\x44'); | |
| 59 sp = s; | |
| 60 | |
| 61 sp.remove_prefix(bb.AppendBytes(sp)); | |
| 62 EXPECT_TRUE(sp.empty()); | |
| 63 EXPECT_EQ(bb.count(), 32u) << bb; | |
| 64 EXPECT_EQ(bb.free_count(), 32u) << bb; | |
| 65 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x11223344) << 32) << bb; | |
| 66 | |
| 67 s.clear(); | |
| 68 s.push_back('\x55'); | |
| 69 s.push_back('\x66'); | |
| 70 s.push_back('\x77'); | |
| 71 s.push_back('\x88'); | |
| 72 s.push_back('\x99'); | |
| 73 sp = s; | |
| 74 | |
| 75 sp.remove_prefix(bb.AppendBytes(sp)); | |
| 76 EXPECT_EQ(sp.size(), 1u); | |
| 77 EXPECT_EQ('\x99', sp[0]); | |
| 78 EXPECT_EQ(bb.count(), 64u) << bb; | |
| 79 EXPECT_EQ(bb.free_count(), 0u) << bb; | |
| 80 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x1122334455667788LL)) << bb; | |
| 81 | |
| 82 sp.remove_prefix(bb.AppendBytes(sp)); | |
| 83 EXPECT_EQ(sp.size(), 1u); | |
| 84 EXPECT_EQ('\x99', sp[0]); | |
| 85 EXPECT_EQ(bb.count(), 64u) << bb; | |
| 86 EXPECT_EQ(bb.free_count(), 0u) << bb; | |
| 87 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x1122334455667788LL)) << bb; | |
| 88 } | |
| 89 | |
| 90 TEST(HuffmanBitBufferTest, ConsumeBits) { | |
| 91 string s; | |
| 92 s.push_back('\x11'); | |
| 93 s.push_back('\x22'); | |
| 94 s.push_back('\x33'); | |
| 95 StringPiece sp(s); | |
| 96 | |
| 97 HuffmanBitBuffer bb; | |
| 98 sp.remove_prefix(bb.AppendBytes(sp)); | |
| 99 EXPECT_TRUE(sp.empty()); | |
| 100 | |
| 101 bb.ConsumeBits(1); | |
| 102 EXPECT_EQ(bb.count(), 23u) << bb; | |
| 103 EXPECT_EQ(bb.free_count(), 41u) << bb; | |
| 104 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x112233) << 41) << bb; | |
| 105 | |
| 106 bb.ConsumeBits(20); | |
| 107 EXPECT_EQ(bb.count(), 3u) << bb; | |
| 108 EXPECT_EQ(bb.free_count(), 61u) << bb; | |
| 109 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x3) << 61) << bb; | |
| 110 } | |
| 111 | |
| 112 TEST(HuffmanBitBufferTest, AppendBytesUnaligned) { | |
| 113 string s; | |
| 114 s.push_back('\x11'); | |
| 115 s.push_back('\x22'); | |
| 116 s.push_back('\x33'); | |
| 117 s.push_back('\x44'); | |
| 118 s.push_back('\x55'); | |
| 119 s.push_back('\x66'); | |
| 120 s.push_back('\x77'); | |
| 121 s.push_back('\x88'); | |
| 122 s.push_back('\x99'); | |
| 123 s.push_back('\xaa'); | |
| 124 s.push_back('\xbb'); | |
| 125 s.push_back('\xcc'); | |
| 126 s.push_back('\xdd'); | |
| 127 StringPiece sp(s); | |
| 128 | |
| 129 HuffmanBitBuffer bb; | |
| 130 sp.remove_prefix(bb.AppendBytes(sp)); | |
| 131 EXPECT_EQ(sp.size(), 5u); | |
| 132 EXPECT_FALSE(bb.InputProperlyTerminated()); | |
| 133 | |
| 134 bb.ConsumeBits(15); | |
| 135 EXPECT_EQ(bb.count(), 49u) << bb; | |
| 136 EXPECT_EQ(bb.free_count(), 15u) << bb; | |
| 137 | |
| 138 HuffmanAccumulator expected(0x1122334455667788); | |
| 139 expected <<= 15; | |
| 140 EXPECT_EQ(bb.value(), expected); | |
| 141 | |
| 142 sp.remove_prefix(bb.AppendBytes(sp)); | |
| 143 EXPECT_EQ(sp.size(), 4u); | |
| 144 EXPECT_EQ(bb.count(), 57u) << bb; | |
| 145 EXPECT_EQ(bb.free_count(), 7u) << bb; | |
| 146 | |
| 147 expected |= (HuffmanAccumulator(0x99) << 7); | |
| 148 EXPECT_EQ(bb.value(), expected) << bb << std::hex | |
| 149 << "\n actual: " << bb.value() | |
| 150 << "\n expected: " << expected; | |
| 151 } | |
| 152 | |
| 153 enum class DecoderChoice { IF_TREE, SHORT_CODE }; | |
| 154 | |
| 155 class HpackHuffmanDecoderTest | |
| 156 : public RandomDecoderTest, | |
| 157 public ::testing::WithParamInterface<DecoderChoice> { | |
| 158 protected: | |
| 159 HpackHuffmanDecoderTest() { | |
| 160 // The decoder may return true, and its accumulator may be empty, at | |
| 161 // many boundaries while decoding, and yet the whole string hasn't | |
| 162 // been decoded. | |
| 163 stop_decode_on_done_ = false; | |
| 164 } | |
| 165 | |
| 166 DecodeStatus StartDecoding(DecodeBuffer* b) override { | |
| 167 input_bytes_seen_ = 0; | |
| 168 output_buffer_.clear(); | |
| 169 decoder_.Reset(); | |
| 170 return ResumeDecoding(b); | |
| 171 } | |
| 172 | |
| 173 DecodeStatus ResumeDecoding(DecodeBuffer* b) override { | |
| 174 input_bytes_seen_ += b->Remaining(); | |
| 175 StringPiece sp(b->cursor(), b->Remaining()); | |
| 176 if (DecodeFragment(sp)) { | |
| 177 b->AdvanceCursor(b->Remaining()); | |
| 178 // Successfully decoded (or buffered) the bytes in StringPiece. | |
| 179 EXPECT_LE(input_bytes_seen_, input_bytes_expected_); | |
| 180 // Have we reached the end of the encoded string? | |
| 181 if (input_bytes_expected_ == input_bytes_seen_) { | |
| 182 if (decoder_.InputProperlyTerminated()) { | |
| 183 return DecodeStatus::kDecodeDone; | |
| 184 } else { | |
| 185 return DecodeStatus::kDecodeError; | |
| 186 } | |
| 187 } | |
| 188 return DecodeStatus::kDecodeInProgress; | |
| 189 } | |
| 190 return DecodeStatus::kDecodeError; | |
| 191 } | |
| 192 | |
| 193 bool DecodeFragment(StringPiece sp) { | |
| 194 switch (GetParam()) { | |
| 195 case DecoderChoice::IF_TREE: | |
| 196 return decoder_.DecodeWithIfTreeAndStruct(sp, &output_buffer_); | |
| 197 case DecoderChoice::SHORT_CODE: | |
| 198 return decoder_.DecodeShortCodesFirst(sp, &output_buffer_); | |
| 199 } | |
| 200 | |
| 201 NOTREACHED(); | |
| 202 return false; | |
| 203 } | |
| 204 | |
| 205 AssertionResult ValidatorForHuffmanDecodeAndValidateSeveralWays( | |
| 206 StringPiece expected_plain) { | |
| 207 VERIFY_EQ(output_buffer_.size(), expected_plain.size()); | |
| 208 VERIFY_EQ(output_buffer_, expected_plain); | |
| 209 return AssertionSuccess(); | |
| 210 } | |
| 211 | |
| 212 AssertionResult HuffmanDecodeAndValidateSeveralWays( | |
| 213 StringPiece encoded, | |
| 214 StringPiece expected_plain) { | |
| 215 input_bytes_expected_ = encoded.size(); | |
| 216 DecodeBuffer db(encoded); | |
| 217 bool return_non_zero_on_first = false; | |
| 218 return DecodeAndValidateSeveralWays( | |
| 219 &db, return_non_zero_on_first, | |
| 220 ValidateDoneAndEmpty( | |
| 221 base::Bind(&HpackHuffmanDecoderTest:: | |
| 222 ValidatorForHuffmanDecodeAndValidateSeveralWays, | |
| 223 base::Unretained(this), expected_plain))); | |
| 224 } | |
| 225 | |
| 226 HpackHuffmanDecoder decoder_; | |
| 227 string output_buffer_; | |
| 228 size_t input_bytes_seen_; | |
| 229 size_t input_bytes_expected_; | |
| 230 }; | |
| 231 INSTANTIATE_TEST_CASE_P(AllDecoders, | |
| 232 HpackHuffmanDecoderTest, | |
| 233 ::testing::Values(DecoderChoice::IF_TREE, | |
| 234 DecoderChoice::SHORT_CODE)); | |
| 235 | |
| 236 TEST_P(HpackHuffmanDecoderTest, SpecRequestExamples) { | |
| 237 HpackHuffmanDecoder decoder; | |
| 238 string test_table[] = { | |
| 239 a2b_hex("f1e3c2e5f23a6ba0ab90f4ff"), | |
| 240 "www.example.com", | |
| 241 a2b_hex("a8eb10649cbf"), | |
| 242 "no-cache", | |
| 243 a2b_hex("25a849e95ba97d7f"), | |
| 244 "custom-key", | |
| 245 a2b_hex("25a849e95bb8e8b4bf"), | |
| 246 "custom-value", | |
| 247 }; | |
| 248 for (size_t i = 0; i != arraysize(test_table); i += 2) { | |
| 249 const string& huffman_encoded(test_table[i]); | |
| 250 const string& plain_string(test_table[i + 1]); | |
| 251 string buffer; | |
| 252 decoder.Reset(); | |
| 253 EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder; | |
| 254 EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder; | |
| 255 EXPECT_EQ(buffer, plain_string); | |
| 256 } | |
| 257 } | |
| 258 | |
| 259 TEST_P(HpackHuffmanDecoderTest, SpecResponseExamples) { | |
| 260 HpackHuffmanDecoder decoder; | |
| 261 // clang-format off | |
| 262 string test_table[] = { | |
| 263 a2b_hex("6402"), | |
| 264 "302", | |
| 265 a2b_hex("aec3771a4b"), | |
| 266 "private", | |
| 267 a2b_hex("d07abe941054d444a8200595040b8166" | |
| 268 "e082a62d1bff"), | |
| 269 "Mon, 21 Oct 2013 20:13:21 GMT", | |
| 270 a2b_hex("9d29ad171863c78f0b97c8e9ae82ae43" | |
| 271 "d3"), | |
| 272 "https://www.example.com", | |
| 273 a2b_hex("94e7821dd7f2e6c7b335dfdfcd5b3960" | |
| 274 "d5af27087f3672c1ab270fb5291f9587" | |
| 275 "316065c003ed4ee5b1063d5007"), | |
| 276 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", | |
| 277 }; | |
| 278 // clang-format on | |
| 279 for (size_t i = 0; i != arraysize(test_table); i += 2) { | |
| 280 const string& huffman_encoded(test_table[i]); | |
| 281 const string& plain_string(test_table[i + 1]); | |
| 282 string buffer; | |
| 283 decoder.Reset(); | |
| 284 EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder; | |
| 285 EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder; | |
| 286 EXPECT_EQ(buffer, plain_string); | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 } // namespace | |
| 291 } // namespace test | |
| 292 } // namespace net | |
| OLD | NEW |