| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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/spdy/hpack/hpack_huffman_table.h" | |
| 6 | |
| 7 #include <stdint.h> | |
| 8 | |
| 9 #include <bitset> | |
| 10 #include <utility> | |
| 11 | |
| 12 #include "base/logging.h" | |
| 13 #include "base/macros.h" | |
| 14 #include "net/spdy/hpack/hpack_constants.h" | |
| 15 #include "net/spdy/hpack/hpack_huffman_decoder.h" | |
| 16 #include "net/spdy/hpack/hpack_input_stream.h" | |
| 17 #include "net/spdy/hpack/hpack_output_stream.h" | |
| 18 #include "net/spdy/spdy_test_utils.h" | |
| 19 #include "testing/gmock/include/gmock/gmock.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | |
| 21 | |
| 22 using testing::ElementsAreArray; | |
| 23 using testing::Pointwise; | |
| 24 | |
| 25 namespace net { | |
| 26 | |
| 27 namespace test { | |
| 28 | |
| 29 typedef HpackHuffmanTable::DecodeEntry DecodeEntry; | |
| 30 typedef HpackHuffmanTable::DecodeTable DecodeTable; | |
| 31 | |
| 32 class HpackHuffmanTablePeer { | |
| 33 public: | |
| 34 explicit HpackHuffmanTablePeer(const HpackHuffmanTable& table) | |
| 35 : table_(table) {} | |
| 36 | |
| 37 const std::vector<uint32_t>& code_by_id() const { return table_.code_by_id_; } | |
| 38 const std::vector<uint8_t>& length_by_id() const { | |
| 39 return table_.length_by_id_; | |
| 40 } | |
| 41 const std::vector<DecodeTable>& decode_tables() const { | |
| 42 return table_.decode_tables_; | |
| 43 } | |
| 44 char pad_bits() const { | |
| 45 // Cast to match signed-ness of bits8(). | |
| 46 return static_cast<char>(table_.pad_bits_); | |
| 47 } | |
| 48 uint16_t failed_symbol_id() const { return table_.failed_symbol_id_; } | |
| 49 std::vector<DecodeEntry> decode_entries(const DecodeTable& decode_table) { | |
| 50 std::vector<DecodeEntry>::const_iterator begin = | |
| 51 table_.decode_entries_.begin() + decode_table.entries_offset; | |
| 52 return std::vector<DecodeEntry>(begin, begin + decode_table.size()); | |
| 53 } | |
| 54 | |
| 55 private: | |
| 56 const HpackHuffmanTable& table_; | |
| 57 }; | |
| 58 | |
| 59 namespace { | |
| 60 | |
| 61 // Tests of the ability to decode some canonical Huffman code, | |
| 62 // not just the one defined in the RFC 7541. | |
| 63 class GenericHuffmanTableTest : public ::testing::TestWithParam<bool> { | |
| 64 protected: | |
| 65 GenericHuffmanTableTest() : table_(), peer_(table_) {} | |
| 66 | |
| 67 SpdyString EncodeString(SpdyStringPiece input) { | |
| 68 SpdyString result; | |
| 69 HpackOutputStream output_stream; | |
| 70 table_.EncodeString(input, &output_stream); | |
| 71 | |
| 72 output_stream.TakeString(&result); | |
| 73 // Verify EncodedSize() agrees with EncodeString(). | |
| 74 EXPECT_EQ(result.size(), table_.EncodedSize(input)); | |
| 75 return result; | |
| 76 } | |
| 77 | |
| 78 HpackHuffmanTable table_; | |
| 79 HpackHuffmanTablePeer peer_; | |
| 80 }; | |
| 81 | |
| 82 MATCHER(DecodeEntryEq, "") { | |
| 83 const DecodeEntry& lhs = std::tr1::get<0>(arg); | |
| 84 const DecodeEntry& rhs = std::tr1::get<1>(arg); | |
| 85 return lhs.next_table_index == rhs.next_table_index && | |
| 86 lhs.length == rhs.length && lhs.symbol_id == rhs.symbol_id; | |
| 87 } | |
| 88 | |
| 89 uint32_t bits32(const SpdyString& bitstring) { | |
| 90 return std::bitset<32>(bitstring).to_ulong(); | |
| 91 } | |
| 92 char bits8(const SpdyString& bitstring) { | |
| 93 return static_cast<char>(std::bitset<8>(bitstring).to_ulong()); | |
| 94 } | |
| 95 | |
| 96 TEST_F(GenericHuffmanTableTest, InitializeEdgeCases) { | |
| 97 { | |
| 98 // Verify eight symbols can be encoded with 3 bits per symbol. | |
| 99 HpackHuffmanSymbol code[] = { | |
| 100 {bits32("00000000000000000000000000000000"), 3, 0}, | |
| 101 {bits32("00100000000000000000000000000000"), 3, 1}, | |
| 102 {bits32("01000000000000000000000000000000"), 3, 2}, | |
| 103 {bits32("01100000000000000000000000000000"), 3, 3}, | |
| 104 {bits32("10000000000000000000000000000000"), 3, 4}, | |
| 105 {bits32("10100000000000000000000000000000"), 3, 5}, | |
| 106 {bits32("11000000000000000000000000000000"), 3, 6}, | |
| 107 {bits32("11100000000000000000000000000000"), 8, 7}}; | |
| 108 HpackHuffmanTable table; | |
| 109 EXPECT_TRUE(table.Initialize(code, arraysize(code))); | |
| 110 } | |
| 111 { | |
| 112 // But using 2 bits with one symbol overflows the code. | |
| 113 HpackHuffmanSymbol code[] = { | |
| 114 {bits32("01000000000000000000000000000000"), 3, 0}, | |
| 115 {bits32("01100000000000000000000000000000"), 3, 1}, | |
| 116 {bits32("00000000000000000000000000000000"), 2, 2}, | |
| 117 {bits32("10000000000000000000000000000000"), 3, 3}, | |
| 118 {bits32("10100000000000000000000000000000"), 3, 4}, | |
| 119 {bits32("11000000000000000000000000000000"), 3, 5}, | |
| 120 {bits32("11100000000000000000000000000000"), 3, 6}, | |
| 121 {bits32("00000000000000000000000000000000"), 8, 7}}; // Overflow. | |
| 122 HpackHuffmanTable table; | |
| 123 EXPECT_FALSE(table.Initialize(code, arraysize(code))); | |
| 124 EXPECT_EQ(7, HpackHuffmanTablePeer(table).failed_symbol_id()); | |
| 125 } | |
| 126 { | |
| 127 // Verify four symbols can be encoded with incremental bits per symbol. | |
| 128 HpackHuffmanSymbol code[] = { | |
| 129 {bits32("00000000000000000000000000000000"), 1, 0}, | |
| 130 {bits32("10000000000000000000000000000000"), 2, 1}, | |
| 131 {bits32("11000000000000000000000000000000"), 3, 2}, | |
| 132 {bits32("11100000000000000000000000000000"), 8, 3}}; | |
| 133 HpackHuffmanTable table; | |
| 134 EXPECT_TRUE(table.Initialize(code, arraysize(code))); | |
| 135 } | |
| 136 { | |
| 137 // But repeating a length overflows the code. | |
| 138 HpackHuffmanSymbol code[] = { | |
| 139 {bits32("00000000000000000000000000000000"), 1, 0}, | |
| 140 {bits32("10000000000000000000000000000000"), 2, 1}, | |
| 141 {bits32("11000000000000000000000000000000"), 2, 2}, | |
| 142 {bits32("00000000000000000000000000000000"), 8, 3}}; // Overflow. | |
| 143 HpackHuffmanTable table; | |
| 144 EXPECT_FALSE(table.Initialize(code, arraysize(code))); | |
| 145 EXPECT_EQ(3, HpackHuffmanTablePeer(table).failed_symbol_id()); | |
| 146 } | |
| 147 { | |
| 148 // Symbol IDs must be assigned sequentially with no gaps. | |
| 149 HpackHuffmanSymbol code[] = { | |
| 150 {bits32("00000000000000000000000000000000"), 1, 0}, | |
| 151 {bits32("10000000000000000000000000000000"), 2, 1}, | |
| 152 {bits32("11000000000000000000000000000000"), 3, 1}, // Repeat. | |
| 153 {bits32("11100000000000000000000000000000"), 8, 3}}; | |
| 154 HpackHuffmanTable table; | |
| 155 EXPECT_FALSE(table.Initialize(code, arraysize(code))); | |
| 156 EXPECT_EQ(2, HpackHuffmanTablePeer(table).failed_symbol_id()); | |
| 157 } | |
| 158 { | |
| 159 // Canonical codes must begin with zero. | |
| 160 HpackHuffmanSymbol code[] = { | |
| 161 {bits32("10000000000000000000000000000000"), 4, 0}, | |
| 162 {bits32("10010000000000000000000000000000"), 4, 1}, | |
| 163 {bits32("10100000000000000000000000000000"), 4, 2}, | |
| 164 {bits32("10110000000000000000000000000000"), 8, 3}}; | |
| 165 HpackHuffmanTable table; | |
| 166 EXPECT_FALSE(table.Initialize(code, arraysize(code))); | |
| 167 EXPECT_EQ(0, HpackHuffmanTablePeer(table).failed_symbol_id()); | |
| 168 } | |
| 169 { | |
| 170 // Codes must match the expected canonical sequence. | |
| 171 HpackHuffmanSymbol code[] = { | |
| 172 {bits32("00000000000000000000000000000000"), 2, 0}, | |
| 173 {bits32("01000000000000000000000000000000"), 2, 1}, | |
| 174 {bits32("11000000000000000000000000000000"), 2, 2}, // Not canonical. | |
| 175 {bits32("10000000000000000000000000000000"), 8, 3}}; | |
| 176 HpackHuffmanTable table; | |
| 177 EXPECT_FALSE(table.Initialize(code, arraysize(code))); | |
| 178 EXPECT_EQ(2, HpackHuffmanTablePeer(table).failed_symbol_id()); | |
| 179 } | |
| 180 { | |
| 181 // At least one code must have a length of 8 bits (to ensure pad-ability). | |
| 182 HpackHuffmanSymbol code[] = { | |
| 183 {bits32("00000000000000000000000000000000"), 1, 0}, | |
| 184 {bits32("10000000000000000000000000000000"), 2, 1}, | |
| 185 {bits32("11000000000000000000000000000000"), 3, 2}, | |
| 186 {bits32("11100000000000000000000000000000"), 7, 3}}; | |
| 187 HpackHuffmanTable table; | |
| 188 EXPECT_FALSE(table.Initialize(code, arraysize(code))); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 TEST_F(GenericHuffmanTableTest, ValidateInternalsWithSmallCode) { | |
| 193 HpackHuffmanSymbol code[] = { | |
| 194 {bits32("01100000000000000000000000000000"), 4, 0}, // 3rd. | |
| 195 {bits32("01110000000000000000000000000000"), 4, 1}, // 4th. | |
| 196 {bits32("00000000000000000000000000000000"), 2, 2}, // 1st assigned code. | |
| 197 {bits32("01000000000000000000000000000000"), 3, 3}, // 2nd. | |
| 198 {bits32("10000000000000000000000000000000"), 5, 4}, // 5th. | |
| 199 {bits32("10001000000000000000000000000000"), 5, 5}, // 6th. | |
| 200 {bits32("10011000000000000000000000000000"), 8, 6}, // 8th. | |
| 201 {bits32("10010000000000000000000000000000"), 5, 7}}; // 7th. | |
| 202 EXPECT_TRUE(table_.Initialize(code, arraysize(code))); | |
| 203 ASSERT_EQ(arraysize(code), peer_.code_by_id().size()); | |
| 204 ASSERT_EQ(arraysize(code), peer_.length_by_id().size()); | |
| 205 for (size_t i = 0; i < arraysize(code); ++i) { | |
| 206 EXPECT_EQ(code[i].code, peer_.code_by_id()[i]); | |
| 207 EXPECT_EQ(code[i].length, peer_.length_by_id()[i]); | |
| 208 } | |
| 209 | |
| 210 EXPECT_EQ(1u, peer_.decode_tables().size()); | |
| 211 { | |
| 212 std::vector<DecodeEntry> expected; | |
| 213 expected.resize(128, DecodeEntry(0, 2, 2)); // Fills 128. | |
| 214 expected.resize(192, DecodeEntry(0, 3, 3)); // Fills 64. | |
| 215 expected.resize(224, DecodeEntry(0, 4, 0)); // Fills 32. | |
| 216 expected.resize(256, DecodeEntry(0, 4, 1)); // Fills 32. | |
| 217 expected.resize(272, DecodeEntry(0, 5, 4)); // Fills 16. | |
| 218 expected.resize(288, DecodeEntry(0, 5, 5)); // Fills 16. | |
| 219 expected.resize(304, DecodeEntry(0, 5, 7)); // Fills 16. | |
| 220 expected.resize(306, DecodeEntry(0, 8, 6)); // Fills 2. | |
| 221 expected.resize(512, DecodeEntry()); // Remainder is empty. | |
| 222 | |
| 223 EXPECT_THAT(peer_.decode_entries(peer_.decode_tables()[0]), | |
| 224 Pointwise(DecodeEntryEq(), expected)); | |
| 225 } | |
| 226 EXPECT_EQ(bits8("10011000"), peer_.pad_bits()); | |
| 227 | |
| 228 char input_storage[] = {2, 3, 2, 7, 4}; | |
| 229 SpdyStringPiece input(input_storage, arraysize(input_storage)); | |
| 230 // By symbol: (2) 00 (3) 010 (2) 00 (7) 10010 (4) 10000 (6 as pad) 1001100. | |
| 231 char expect_storage[] = {bits8("00010001"), bits8("00101000"), | |
| 232 bits8("01001100")}; | |
| 233 SpdyStringPiece expect(expect_storage, arraysize(expect_storage)); | |
| 234 | |
| 235 SpdyString buffer_in = EncodeString(input); | |
| 236 EXPECT_EQ(expect, buffer_in); | |
| 237 | |
| 238 SpdyString buffer_out; | |
| 239 HpackInputStream input_stream(buffer_in); | |
| 240 EXPECT_TRUE(table_.GenericDecodeString(&input_stream, &buffer_out)); | |
| 241 EXPECT_EQ(buffer_out, input); | |
| 242 } | |
| 243 | |
| 244 TEST_F(GenericHuffmanTableTest, ValidateMultiLevelDecodeTables) { | |
| 245 HpackHuffmanSymbol code[] = { | |
| 246 {bits32("00000000000000000000000000000000"), 6, 0}, | |
| 247 {bits32("00000100000000000000000000000000"), 6, 1}, | |
| 248 {bits32("00001000000000000000000000000000"), 11, 2}, | |
| 249 {bits32("00001000001000000000000000000000"), 11, 3}, | |
| 250 {bits32("00001000010000000000000000000000"), 12, 4}, | |
| 251 }; | |
| 252 EXPECT_TRUE(table_.Initialize(code, arraysize(code))); | |
| 253 | |
| 254 EXPECT_EQ(2u, peer_.decode_tables().size()); | |
| 255 { | |
| 256 std::vector<DecodeEntry> expected; | |
| 257 expected.resize(8, DecodeEntry(0, 6, 0)); // Fills 8. | |
| 258 expected.resize(16, DecodeEntry(0, 6, 1)); // Fills 8. | |
| 259 expected.resize(17, DecodeEntry(1, 12, 0)); // Pointer. Fills 1. | |
| 260 expected.resize(512, DecodeEntry()); // Remainder is empty. | |
| 261 | |
| 262 const DecodeTable& decode_table = peer_.decode_tables()[0]; | |
| 263 EXPECT_EQ(decode_table.prefix_length, 0); | |
| 264 EXPECT_EQ(decode_table.indexed_length, 9); | |
| 265 EXPECT_THAT(peer_.decode_entries(decode_table), | |
| 266 Pointwise(DecodeEntryEq(), expected)); | |
| 267 } | |
| 268 { | |
| 269 std::vector<DecodeEntry> expected; | |
| 270 expected.resize(2, DecodeEntry(1, 11, 2)); // Fills 2. | |
| 271 expected.resize(4, DecodeEntry(1, 11, 3)); // Fills 2. | |
| 272 expected.resize(5, DecodeEntry(1, 12, 4)); // Fills 1. | |
| 273 expected.resize(8, DecodeEntry()); // Remainder is empty. | |
| 274 | |
| 275 const DecodeTable& decode_table = peer_.decode_tables()[1]; | |
| 276 EXPECT_EQ(decode_table.prefix_length, 9); | |
| 277 EXPECT_EQ(decode_table.indexed_length, 3); | |
| 278 EXPECT_THAT(peer_.decode_entries(decode_table), | |
| 279 Pointwise(DecodeEntryEq(), expected)); | |
| 280 } | |
| 281 EXPECT_EQ(bits8("00001000"), peer_.pad_bits()); | |
| 282 } | |
| 283 | |
| 284 TEST_F(GenericHuffmanTableTest, DecodeWithBadInput) { | |
| 285 HpackHuffmanSymbol code[] = { | |
| 286 {bits32("01100000000000000000000000000000"), 4, 0}, | |
| 287 {bits32("01110000000000000000000000000000"), 4, 1}, | |
| 288 {bits32("00000000000000000000000000000000"), 2, 2}, | |
| 289 {bits32("01000000000000000000000000000000"), 3, 3}, | |
| 290 {bits32("10000000000000000000000000000000"), 5, 4}, | |
| 291 {bits32("10001000000000000000000000000000"), 5, 5}, | |
| 292 {bits32("10011000000000000000000000000000"), 6, 6}, | |
| 293 {bits32("10010000000000000000000000000000"), 5, 7}, | |
| 294 {bits32("10011100000000000000000000000000"), 16, 8}}; | |
| 295 EXPECT_TRUE(table_.Initialize(code, arraysize(code))); | |
| 296 | |
| 297 SpdyString buffer; | |
| 298 { | |
| 299 // This example works: (2) 00 (3) 010 (2) 00 (6) 100110 (pad) 100. | |
| 300 char input_storage[] = {bits8("00010001"), bits8("00110100")}; | |
| 301 SpdyStringPiece input(input_storage, arraysize(input_storage)); | |
| 302 | |
| 303 HpackInputStream input_stream(input); | |
| 304 EXPECT_TRUE(table_.GenericDecodeString(&input_stream, &buffer)); | |
| 305 EXPECT_EQ(buffer, "\x02\x03\x02\x06"); | |
| 306 } | |
| 307 { | |
| 308 // Expect to fail on an invalid code prefix. | |
| 309 // (2) 00 (3) 010 (2) 00 (too-large) 101000 (pad) 100. | |
| 310 char input_storage[] = {bits8("00010001"), bits8("01000111")}; | |
| 311 SpdyStringPiece input(input_storage, arraysize(input_storage)); | |
| 312 | |
| 313 HpackInputStream input_stream(input); | |
| 314 EXPECT_FALSE(table_.GenericDecodeString(&input_stream, &buffer)); | |
| 315 EXPECT_EQ(buffer, "\x02\x03\x02"); | |
| 316 } | |
| 317 { | |
| 318 // Expect to fail if more than a byte of unconsumed input remains. | |
| 319 // (6) 100110 (8 truncated) 1001110000 | |
| 320 char input_storage[] = {bits8("10011010"), bits8("01110000")}; | |
| 321 SpdyStringPiece input(input_storage, arraysize(input_storage)); | |
| 322 | |
| 323 HpackInputStream input_stream(input); | |
| 324 EXPECT_FALSE(table_.GenericDecodeString(&input_stream, &buffer)); | |
| 325 EXPECT_EQ(buffer, "\x06"); | |
| 326 } | |
| 327 } | |
| 328 | |
| 329 // Tests of the ability to decode the HPACK Huffman Code, defined in: | |
| 330 // https://httpwg.github.io/specs/rfc7541.html#huffman.code | |
| 331 class HpackHuffmanTableTest : public GenericHuffmanTableTest { | |
| 332 protected: | |
| 333 void SetUp() override { | |
| 334 std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode(); | |
| 335 EXPECT_TRUE(table_.Initialize(&code[0], code.size())); | |
| 336 EXPECT_TRUE(table_.IsInitialized()); | |
| 337 } | |
| 338 | |
| 339 void DecodeStringTwice(const SpdyString& encoded, SpdyString* out) { | |
| 340 // First decode with HpackHuffmanTable. | |
| 341 { | |
| 342 HpackInputStream input_stream(encoded); | |
| 343 EXPECT_TRUE(table_.GenericDecodeString(&input_stream, out)); | |
| 344 } | |
| 345 // And decode again with the fixed decoder, confirming that the result is | |
| 346 // the same. | |
| 347 { | |
| 348 HpackInputStream input_stream(encoded); | |
| 349 SpdyString buf; | |
| 350 EXPECT_TRUE(HpackHuffmanDecoder::DecodeString(&input_stream, &buf)); | |
| 351 EXPECT_EQ(*out, buf); | |
| 352 } | |
| 353 } | |
| 354 }; | |
| 355 | |
| 356 TEST_F(HpackHuffmanTableTest, InitializeHpackCode) { | |
| 357 EXPECT_EQ(peer_.pad_bits(), '\xFF'); // First 8 bits of EOS. | |
| 358 } | |
| 359 | |
| 360 TEST_F(HpackHuffmanTableTest, SpecRequestExamples) { | |
| 361 SpdyString buffer; | |
| 362 SpdyString test_table[] = { | |
| 363 a2b_hex("f1e3c2e5f23a6ba0ab90f4ff"), | |
| 364 "www.example.com", | |
| 365 a2b_hex("a8eb10649cbf"), | |
| 366 "no-cache", | |
| 367 a2b_hex("25a849e95ba97d7f"), | |
| 368 "custom-key", | |
| 369 a2b_hex("25a849e95bb8e8b4bf"), | |
| 370 "custom-value", | |
| 371 }; | |
| 372 // Round-trip each test example. | |
| 373 for (size_t i = 0; i != arraysize(test_table); i += 2) { | |
| 374 const SpdyString& encodedFixture(test_table[i]); | |
| 375 const SpdyString& decodedFixture(test_table[i + 1]); | |
| 376 DecodeStringTwice(encodedFixture, &buffer); | |
| 377 EXPECT_EQ(decodedFixture, buffer); | |
| 378 buffer = EncodeString(decodedFixture); | |
| 379 EXPECT_EQ(encodedFixture, buffer); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 TEST_F(HpackHuffmanTableTest, SpecResponseExamples) { | |
| 384 SpdyString buffer; | |
| 385 SpdyString test_table[] = { | |
| 386 a2b_hex("6402"), | |
| 387 "302", | |
| 388 a2b_hex("aec3771a4b"), | |
| 389 "private", | |
| 390 a2b_hex("d07abe941054d444a8200595040b8166" | |
| 391 "e082a62d1bff"), | |
| 392 "Mon, 21 Oct 2013 20:13:21 GMT", | |
| 393 a2b_hex("9d29ad171863c78f0b97c8e9ae82ae43" | |
| 394 "d3"), | |
| 395 "https://www.example.com", | |
| 396 a2b_hex("94e7821dd7f2e6c7b335dfdfcd5b3960" | |
| 397 "d5af27087f3672c1ab270fb5291f9587" | |
| 398 "316065c003ed4ee5b1063d5007"), | |
| 399 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", | |
| 400 }; | |
| 401 // Round-trip each test example. | |
| 402 for (size_t i = 0; i != arraysize(test_table); i += 2) { | |
| 403 const SpdyString& encodedFixture(test_table[i]); | |
| 404 const SpdyString& decodedFixture(test_table[i + 1]); | |
| 405 DecodeStringTwice(encodedFixture, &buffer); | |
| 406 EXPECT_EQ(decodedFixture, buffer); | |
| 407 buffer = EncodeString(decodedFixture); | |
| 408 EXPECT_EQ(encodedFixture, buffer); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 TEST_F(HpackHuffmanTableTest, RoundTripIndividualSymbols) { | |
| 413 for (size_t i = 0; i != 256; i++) { | |
| 414 char c = static_cast<char>(i); | |
| 415 char storage[3] = {c, c, c}; | |
| 416 SpdyStringPiece input(storage, arraysize(storage)); | |
| 417 SpdyString buffer_in = EncodeString(input); | |
| 418 SpdyString buffer_out; | |
| 419 DecodeStringTwice(buffer_in, &buffer_out); | |
| 420 EXPECT_EQ(input, buffer_out); | |
| 421 } | |
| 422 } | |
| 423 | |
| 424 TEST_F(HpackHuffmanTableTest, RoundTripSymbolSequence) { | |
| 425 char storage[512]; | |
| 426 for (size_t i = 0; i != 256; i++) { | |
| 427 storage[i] = static_cast<char>(i); | |
| 428 storage[511 - i] = static_cast<char>(i); | |
| 429 } | |
| 430 SpdyStringPiece input(storage, arraysize(storage)); | |
| 431 | |
| 432 SpdyString buffer_in = EncodeString(input); | |
| 433 SpdyString buffer_out; | |
| 434 DecodeStringTwice(buffer_in, &buffer_out); | |
| 435 EXPECT_EQ(input, buffer_out); | |
| 436 } | |
| 437 | |
| 438 TEST_F(HpackHuffmanTableTest, EncodedSizeAgreesWithEncodeString) { | |
| 439 SpdyString test_table[] = { | |
| 440 "", | |
| 441 "Mon, 21 Oct 2013 20:13:21 GMT", | |
| 442 "https://www.example.com", | |
| 443 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", | |
| 444 SpdyString(1, '\0'), | |
| 445 SpdyString("foo\0bar", 7), | |
| 446 SpdyString(256, '\0'), | |
| 447 }; | |
| 448 for (size_t i = 0; i != 256; ++i) { | |
| 449 // Expand last |test_table| entry to cover all codes. | |
| 450 test_table[arraysize(test_table) - 1][i] = static_cast<char>(i); | |
| 451 } | |
| 452 | |
| 453 HpackOutputStream output_stream; | |
| 454 SpdyString encoding; | |
| 455 for (size_t i = 0; i != arraysize(test_table); ++i) { | |
| 456 table_.EncodeString(test_table[i], &output_stream); | |
| 457 output_stream.TakeString(&encoding); | |
| 458 EXPECT_EQ(encoding.size(), table_.EncodedSize(test_table[i])); | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 } // namespace | |
| 463 | |
| 464 } // namespace test | |
| 465 | |
| 466 } // namespace net | |
| OLD | NEW |