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 |