| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/spdy/hpack_huffman_table.h" | 5 #include "net/spdy/hpack_huffman_table.h" |
| 6 | 6 |
| 7 #include <bitset> | 7 #include <bitset> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 i += j; | 79 i += j; |
| 80 } | 80 } |
| 81 } | 81 } |
| 82 | 82 |
| 83 private: | 83 private: |
| 84 const HpackHuffmanTable& table_; | 84 const HpackHuffmanTable& table_; |
| 85 }; | 85 }; |
| 86 | 86 |
| 87 namespace { | 87 namespace { |
| 88 | 88 |
| 89 class HpackHuffmanTableTest : public ::testing::Test { |
| 90 protected: |
| 91 HpackHuffmanTableTest() |
| 92 : table_(), |
| 93 peer_(table_) {} |
| 94 |
| 95 string EncodeString(StringPiece input) { |
| 96 string result; |
| 97 HpackOutputStream output_stream; |
| 98 table_.EncodeString(input, &output_stream); |
| 99 |
| 100 output_stream.TakeString(&result); |
| 101 // Verify EncodedSize() agrees with EncodeString(). |
| 102 EXPECT_EQ(result.size(), table_.EncodedSize(input)); |
| 103 return result; |
| 104 } |
| 105 |
| 106 HpackHuffmanTable table_; |
| 107 HpackHuffmanTablePeer peer_; |
| 108 }; |
| 109 |
| 89 MATCHER(DecodeEntryEq, "") { | 110 MATCHER(DecodeEntryEq, "") { |
| 90 const DecodeEntry& lhs = std::tr1::get<0>(arg); | 111 const DecodeEntry& lhs = std::tr1::get<0>(arg); |
| 91 const DecodeEntry& rhs = std::tr1::get<1>(arg); | 112 const DecodeEntry& rhs = std::tr1::get<1>(arg); |
| 92 return lhs.next_table_index == rhs.next_table_index && | 113 return lhs.next_table_index == rhs.next_table_index && |
| 93 lhs.length == rhs.length && | 114 lhs.length == rhs.length && |
| 94 lhs.symbol_id == rhs.symbol_id; | 115 lhs.symbol_id == rhs.symbol_id; |
| 95 } | 116 } |
| 96 | 117 |
| 97 uint32 bits32(const string& bitstring) { | 118 uint32 bits32(const string& bitstring) { |
| 98 return std::bitset<32>(bitstring).to_ulong(); | 119 return std::bitset<32>(bitstring).to_ulong(); |
| 99 } | 120 } |
| 100 char bits8(const string& bitstring) { | 121 char bits8(const string& bitstring) { |
| 101 return static_cast<char>(std::bitset<8>(bitstring).to_ulong()); | 122 return static_cast<char>(std::bitset<8>(bitstring).to_ulong()); |
| 102 } | 123 } |
| 103 | 124 |
| 104 TEST(HpackHuffmanTableTest, InitializeHpackCode) { | 125 TEST_F(HpackHuffmanTableTest, InitializeHpackCode) { |
| 105 HpackHuffmanTable table; | |
| 106 std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode(); | 126 std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode(); |
| 107 EXPECT_TRUE(table.Initialize(&code[0], code.size())); | 127 EXPECT_TRUE(table_.Initialize(&code[0], code.size())); |
| 108 EXPECT_TRUE(table.IsInitialized()); | 128 EXPECT_TRUE(table_.IsInitialized()); |
| 109 EXPECT_EQ(HpackHuffmanTablePeer(table).pad_bits(), | 129 EXPECT_EQ(peer_.pad_bits(), bits8("11111111")); // First 8 bits of EOS. |
| 110 bits8("11111111")); // First 8 bits of EOS. | |
| 111 } | 130 } |
| 112 | 131 |
| 113 TEST(HpackHuffmanTableTest, InitializeEdgeCases) { | 132 TEST_F(HpackHuffmanTableTest, InitializeEdgeCases) { |
| 114 { | 133 { |
| 115 // Verify eight symbols can be encoded with 3 bits per symbol. | 134 // Verify eight symbols can be encoded with 3 bits per symbol. |
| 116 HpackHuffmanSymbol code[] = { | 135 HpackHuffmanSymbol code[] = { |
| 117 {bits32("00000000000000000000000000000000"), 3, 0}, | 136 {bits32("00000000000000000000000000000000"), 3, 0}, |
| 118 {bits32("00100000000000000000000000000000"), 3, 1}, | 137 {bits32("00100000000000000000000000000000"), 3, 1}, |
| 119 {bits32("01000000000000000000000000000000"), 3, 2}, | 138 {bits32("01000000000000000000000000000000"), 3, 2}, |
| 120 {bits32("01100000000000000000000000000000"), 3, 3}, | 139 {bits32("01100000000000000000000000000000"), 3, 3}, |
| 121 {bits32("10000000000000000000000000000000"), 3, 4}, | 140 {bits32("10000000000000000000000000000000"), 3, 4}, |
| 122 {bits32("10100000000000000000000000000000"), 3, 5}, | 141 {bits32("10100000000000000000000000000000"), 3, 5}, |
| 123 {bits32("11000000000000000000000000000000"), 3, 6}, | 142 {bits32("11000000000000000000000000000000"), 3, 6}, |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 HpackHuffmanSymbol code[] = { | 218 HpackHuffmanSymbol code[] = { |
| 200 {bits32("00000000000000000000000000000000"), 1, 0}, | 219 {bits32("00000000000000000000000000000000"), 1, 0}, |
| 201 {bits32("10000000000000000000000000000000"), 2, 1}, | 220 {bits32("10000000000000000000000000000000"), 2, 1}, |
| 202 {bits32("11000000000000000000000000000000"), 3, 2}, | 221 {bits32("11000000000000000000000000000000"), 3, 2}, |
| 203 {bits32("11100000000000000000000000000000"), 7, 3}}; | 222 {bits32("11100000000000000000000000000000"), 7, 3}}; |
| 204 HpackHuffmanTable table; | 223 HpackHuffmanTable table; |
| 205 EXPECT_FALSE(table.Initialize(code, arraysize(code))); | 224 EXPECT_FALSE(table.Initialize(code, arraysize(code))); |
| 206 } | 225 } |
| 207 } | 226 } |
| 208 | 227 |
| 209 TEST(HpackHuffmanTableTest, ValidateInternalsWithSmallCode) { | 228 TEST_F(HpackHuffmanTableTest, ValidateInternalsWithSmallCode) { |
| 210 HpackHuffmanSymbol code[] = { | 229 HpackHuffmanSymbol code[] = { |
| 211 {bits32("01100000000000000000000000000000"), 4, 0}, // 3rd. | 230 {bits32("01100000000000000000000000000000"), 4, 0}, // 3rd. |
| 212 {bits32("01110000000000000000000000000000"), 4, 1}, // 4th. | 231 {bits32("01110000000000000000000000000000"), 4, 1}, // 4th. |
| 213 {bits32("00000000000000000000000000000000"), 2, 2}, // 1st assigned code. | 232 {bits32("00000000000000000000000000000000"), 2, 2}, // 1st assigned code. |
| 214 {bits32("01000000000000000000000000000000"), 3, 3}, // 2nd. | 233 {bits32("01000000000000000000000000000000"), 3, 3}, // 2nd. |
| 215 {bits32("10000000000000000000000000000000"), 5, 4}, // 5th. | 234 {bits32("10000000000000000000000000000000"), 5, 4}, // 5th. |
| 216 {bits32("10001000000000000000000000000000"), 5, 5}, // 6th. | 235 {bits32("10001000000000000000000000000000"), 5, 5}, // 6th. |
| 217 {bits32("10011000000000000000000000000000"), 8, 6}, // 8th. | 236 {bits32("10011000000000000000000000000000"), 8, 6}, // 8th. |
| 218 {bits32("10010000000000000000000000000000"), 5, 7}}; // 7th. | 237 {bits32("10010000000000000000000000000000"), 5, 7}}; // 7th. |
| 219 HpackHuffmanTable table; | 238 EXPECT_TRUE(table_.Initialize(code, arraysize(code))); |
| 220 EXPECT_TRUE(table.Initialize(code, arraysize(code))); | |
| 221 | 239 |
| 222 HpackHuffmanTablePeer peer(table); | 240 EXPECT_THAT(peer_.code_by_id(), ElementsAre( |
| 223 EXPECT_THAT(peer.code_by_id(), ElementsAre( | |
| 224 bits32("01100000000000000000000000000000"), | 241 bits32("01100000000000000000000000000000"), |
| 225 bits32("01110000000000000000000000000000"), | 242 bits32("01110000000000000000000000000000"), |
| 226 bits32("00000000000000000000000000000000"), | 243 bits32("00000000000000000000000000000000"), |
| 227 bits32("01000000000000000000000000000000"), | 244 bits32("01000000000000000000000000000000"), |
| 228 bits32("10000000000000000000000000000000"), | 245 bits32("10000000000000000000000000000000"), |
| 229 bits32("10001000000000000000000000000000"), | 246 bits32("10001000000000000000000000000000"), |
| 230 bits32("10011000000000000000000000000000"), | 247 bits32("10011000000000000000000000000000"), |
| 231 bits32("10010000000000000000000000000000"))); | 248 bits32("10010000000000000000000000000000"))); |
| 232 EXPECT_THAT(peer.length_by_id(), ElementsAre( | 249 EXPECT_THAT(peer_.length_by_id(), ElementsAre( |
| 233 4, 4, 2, 3, 5, 5, 8, 5)); | 250 4, 4, 2, 3, 5, 5, 8, 5)); |
| 234 | 251 |
| 235 EXPECT_EQ(peer.decode_tables().size(), 1u); | 252 EXPECT_EQ(1u, peer_.decode_tables().size()); |
| 236 { | 253 { |
| 237 std::vector<DecodeEntry> expected; | 254 std::vector<DecodeEntry> expected; |
| 238 expected.resize(128, DecodeEntry(0, 2, 2)); // Fills 128. | 255 expected.resize(128, DecodeEntry(0, 2, 2)); // Fills 128. |
| 239 expected.resize(192, DecodeEntry(0, 3, 3)); // Fills 64. | 256 expected.resize(192, DecodeEntry(0, 3, 3)); // Fills 64. |
| 240 expected.resize(224, DecodeEntry(0, 4, 0)); // Fills 32. | 257 expected.resize(224, DecodeEntry(0, 4, 0)); // Fills 32. |
| 241 expected.resize(256, DecodeEntry(0, 4, 1)); // Fills 32. | 258 expected.resize(256, DecodeEntry(0, 4, 1)); // Fills 32. |
| 242 expected.resize(272, DecodeEntry(0, 5, 4)); // Fills 16. | 259 expected.resize(272, DecodeEntry(0, 5, 4)); // Fills 16. |
| 243 expected.resize(288, DecodeEntry(0, 5, 5)); // Fills 16. | 260 expected.resize(288, DecodeEntry(0, 5, 5)); // Fills 16. |
| 244 expected.resize(304, DecodeEntry(0, 5, 7)); // Fills 16. | 261 expected.resize(304, DecodeEntry(0, 5, 7)); // Fills 16. |
| 245 expected.resize(306, DecodeEntry(0, 8, 6)); // Fills 2. | 262 expected.resize(306, DecodeEntry(0, 8, 6)); // Fills 2. |
| 246 expected.resize(512, DecodeEntry()); // Remainder is empty. | 263 expected.resize(512, DecodeEntry()); // Remainder is empty. |
| 247 | 264 |
| 248 EXPECT_THAT(peer.decode_entries(peer.decode_tables()[0]), | 265 EXPECT_THAT(peer_.decode_entries(peer_.decode_tables()[0]), |
| 249 Pointwise(DecodeEntryEq(), expected)); | 266 Pointwise(DecodeEntryEq(), expected)); |
| 250 } | 267 } |
| 251 EXPECT_EQ(peer.pad_bits(), bits8("10011000")); | 268 EXPECT_EQ(bits8("10011000"), peer_.pad_bits()); |
| 252 | 269 |
| 253 char input_storage[] = {2, 3, 2, 7, 4}; | 270 char input_storage[] = {2, 3, 2, 7, 4}; |
| 254 StringPiece input(input_storage, arraysize(input_storage)); | 271 StringPiece input(input_storage, arraysize(input_storage)); |
| 255 // By symbol: (2) 00 (3) 010 (2) 00 (7) 10010 (4) 10000 (6 as pad) 1001100. | 272 // By symbol: (2) 00 (3) 010 (2) 00 (7) 10010 (4) 10000 (6 as pad) 1001100. |
| 256 char expect_storage[] = { | 273 char expect_storage[] = { |
| 257 bits8("00010001"), | 274 bits8("00010001"), |
| 258 bits8("00101000"), | 275 bits8("00101000"), |
| 259 bits8("01001100")}; | 276 bits8("01001100")}; |
| 260 StringPiece expect(expect_storage, arraysize(expect_storage)); | 277 StringPiece expect(expect_storage, arraysize(expect_storage)); |
| 261 | 278 |
| 262 string buffer_in, buffer_out; | 279 string buffer_in = EncodeString(input); |
| 263 HpackOutputStream output_stream; | 280 EXPECT_EQ(expect, buffer_in); |
| 264 table.EncodeString(input, &output_stream); | |
| 265 output_stream.TakeString(&buffer_in); | |
| 266 EXPECT_EQ(buffer_in, expect); | |
| 267 | 281 |
| 282 string buffer_out; |
| 268 HpackInputStream input_stream(kuint32max, buffer_in); | 283 HpackInputStream input_stream(kuint32max, buffer_in); |
| 269 EXPECT_TRUE(table.DecodeString(&input_stream, input.size(), &buffer_out)); | 284 EXPECT_TRUE(table_.DecodeString(&input_stream, input.size(), &buffer_out)); |
| 270 EXPECT_EQ(buffer_out, input); | 285 EXPECT_EQ(buffer_out, input); |
| 271 } | 286 } |
| 272 | 287 |
| 273 TEST(HpackHuffmanTableTest, ValidateMultiLevelDecodeTables) { | 288 TEST_F(HpackHuffmanTableTest, ValidateMultiLevelDecodeTables) { |
| 274 HpackHuffmanSymbol code[] = { | 289 HpackHuffmanSymbol code[] = { |
| 275 {bits32("00000000000000000000000000000000"), 6, 0}, | 290 {bits32("00000000000000000000000000000000"), 6, 0}, |
| 276 {bits32("00000100000000000000000000000000"), 6, 1}, | 291 {bits32("00000100000000000000000000000000"), 6, 1}, |
| 277 {bits32("00001000000000000000000000000000"), 11, 2}, | 292 {bits32("00001000000000000000000000000000"), 11, 2}, |
| 278 {bits32("00001000001000000000000000000000"), 11, 3}, | 293 {bits32("00001000001000000000000000000000"), 11, 3}, |
| 279 {bits32("00001000010000000000000000000000"), 12, 4}, | 294 {bits32("00001000010000000000000000000000"), 12, 4}, |
| 280 }; | 295 }; |
| 281 HpackHuffmanTable table; | 296 EXPECT_TRUE(table_.Initialize(code, arraysize(code))); |
| 282 EXPECT_TRUE(table.Initialize(code, arraysize(code))); | |
| 283 | 297 |
| 284 HpackHuffmanTablePeer peer(table); | 298 EXPECT_EQ(2u, peer_.decode_tables().size()); |
| 285 EXPECT_EQ(peer.decode_tables().size(), 2u); | |
| 286 { | 299 { |
| 287 std::vector<DecodeEntry> expected; | 300 std::vector<DecodeEntry> expected; |
| 288 expected.resize(8, DecodeEntry(0, 6, 0)); // Fills 8. | 301 expected.resize(8, DecodeEntry(0, 6, 0)); // Fills 8. |
| 289 expected.resize(16, DecodeEntry(0, 6, 1)); // Fills 8. | 302 expected.resize(16, DecodeEntry(0, 6, 1)); // Fills 8. |
| 290 expected.resize(17, DecodeEntry(1, 12, 0)); // Pointer. Fills 1. | 303 expected.resize(17, DecodeEntry(1, 12, 0)); // Pointer. Fills 1. |
| 291 expected.resize(512, DecodeEntry()); // Remainder is empty. | 304 expected.resize(512, DecodeEntry()); // Remainder is empty. |
| 292 | 305 |
| 293 const DecodeTable& decode_table = peer.decode_tables()[0]; | 306 const DecodeTable& decode_table = peer_.decode_tables()[0]; |
| 294 EXPECT_EQ(decode_table.prefix_length, 0); | 307 EXPECT_EQ(decode_table.prefix_length, 0); |
| 295 EXPECT_EQ(decode_table.indexed_length, 9); | 308 EXPECT_EQ(decode_table.indexed_length, 9); |
| 296 EXPECT_THAT(peer.decode_entries(decode_table), | 309 EXPECT_THAT(peer_.decode_entries(decode_table), |
| 297 Pointwise(DecodeEntryEq(), expected)); | 310 Pointwise(DecodeEntryEq(), expected)); |
| 298 } | 311 } |
| 299 { | 312 { |
| 300 std::vector<DecodeEntry> expected; | 313 std::vector<DecodeEntry> expected; |
| 301 expected.resize(2, DecodeEntry(1, 11, 2)); // Fills 2. | 314 expected.resize(2, DecodeEntry(1, 11, 2)); // Fills 2. |
| 302 expected.resize(4, DecodeEntry(1, 11, 3)); // Fills 2. | 315 expected.resize(4, DecodeEntry(1, 11, 3)); // Fills 2. |
| 303 expected.resize(5, DecodeEntry(1, 12, 4)); // Fills 1. | 316 expected.resize(5, DecodeEntry(1, 12, 4)); // Fills 1. |
| 304 expected.resize(8, DecodeEntry()); // Remainder is empty. | 317 expected.resize(8, DecodeEntry()); // Remainder is empty. |
| 305 | 318 |
| 306 const DecodeTable& decode_table = peer.decode_tables()[1]; | 319 const DecodeTable& decode_table = peer_.decode_tables()[1]; |
| 307 EXPECT_EQ(decode_table.prefix_length, 9); | 320 EXPECT_EQ(decode_table.prefix_length, 9); |
| 308 EXPECT_EQ(decode_table.indexed_length, 3); | 321 EXPECT_EQ(decode_table.indexed_length, 3); |
| 309 EXPECT_THAT(peer.decode_entries(decode_table), | 322 EXPECT_THAT(peer_.decode_entries(decode_table), |
| 310 Pointwise(DecodeEntryEq(), expected)); | 323 Pointwise(DecodeEntryEq(), expected)); |
| 311 } | 324 } |
| 312 EXPECT_EQ(peer.pad_bits(), bits8("00001000")); | 325 EXPECT_EQ(bits8("00001000"), peer_.pad_bits()); |
| 313 } | 326 } |
| 314 | 327 |
| 315 TEST(HpackHuffmanTableTest, DecodeWithBadInput) { | 328 TEST_F(HpackHuffmanTableTest, DecodeWithBadInput) { |
| 316 HpackHuffmanSymbol code[] = { | 329 HpackHuffmanSymbol code[] = { |
| 317 {bits32("01100000000000000000000000000000"), 4, 0}, | 330 {bits32("01100000000000000000000000000000"), 4, 0}, |
| 318 {bits32("01110000000000000000000000000000"), 4, 1}, | 331 {bits32("01110000000000000000000000000000"), 4, 1}, |
| 319 {bits32("00000000000000000000000000000000"), 2, 2}, | 332 {bits32("00000000000000000000000000000000"), 2, 2}, |
| 320 {bits32("01000000000000000000000000000000"), 3, 3}, | 333 {bits32("01000000000000000000000000000000"), 3, 3}, |
| 321 {bits32("10000000000000000000000000000000"), 5, 4}, | 334 {bits32("10000000000000000000000000000000"), 5, 4}, |
| 322 {bits32("10001000000000000000000000000000"), 5, 5}, | 335 {bits32("10001000000000000000000000000000"), 5, 5}, |
| 323 {bits32("10011000000000000000000000000000"), 6, 6}, | 336 {bits32("10011000000000000000000000000000"), 6, 6}, |
| 324 {bits32("10010000000000000000000000000000"), 5, 7}, | 337 {bits32("10010000000000000000000000000000"), 5, 7}, |
| 325 {bits32("10011100000000000000000000000000"), 16, 8}}; | 338 {bits32("10011100000000000000000000000000"), 16, 8}}; |
| 326 HpackHuffmanTable table; | 339 EXPECT_TRUE(table_.Initialize(code, arraysize(code))); |
| 327 EXPECT_TRUE(table.Initialize(code, arraysize(code))); | |
| 328 | 340 |
| 329 string buffer; | 341 string buffer; |
| 330 const size_t capacity = 4; | 342 const size_t capacity = 4; |
| 331 { | 343 { |
| 332 // This example works: (2) 00 (3) 010 (2) 00 (6) 100110 (pad) 100. | 344 // This example works: (2) 00 (3) 010 (2) 00 (6) 100110 (pad) 100. |
| 333 char input_storage[] = {bits8("00010001"), bits8("00110100")}; | 345 char input_storage[] = {bits8("00010001"), bits8("00110100")}; |
| 334 StringPiece input(input_storage, arraysize(input_storage)); | 346 StringPiece input(input_storage, arraysize(input_storage)); |
| 335 | 347 |
| 336 HpackInputStream input_stream(kuint32max, input); | 348 HpackInputStream input_stream(kuint32max, input); |
| 337 EXPECT_TRUE(table.DecodeString(&input_stream, capacity, &buffer)); | 349 EXPECT_TRUE(table_.DecodeString(&input_stream, capacity, &buffer)); |
| 338 EXPECT_EQ(buffer, "\x02\x03\x02\x06"); | 350 EXPECT_EQ(buffer, "\x02\x03\x02\x06"); |
| 339 } | 351 } |
| 340 { | 352 { |
| 341 // Expect to fail on an invalid code prefix. | 353 // Expect to fail on an invalid code prefix. |
| 342 // (2) 00 (3) 010 (2) 00 (too-large) 101000 (pad) 100. | 354 // (2) 00 (3) 010 (2) 00 (too-large) 101000 (pad) 100. |
| 343 char input_storage[] = {bits8("00010001"), bits8("01000111")}; | 355 char input_storage[] = {bits8("00010001"), bits8("01000111")}; |
| 344 StringPiece input(input_storage, arraysize(input_storage)); | 356 StringPiece input(input_storage, arraysize(input_storage)); |
| 345 | 357 |
| 346 HpackInputStream input_stream(kuint32max, input); | 358 HpackInputStream input_stream(kuint32max, input); |
| 347 EXPECT_FALSE(table.DecodeString(&input_stream, capacity, &buffer)); | 359 EXPECT_FALSE(table_.DecodeString(&input_stream, capacity, &buffer)); |
| 348 EXPECT_EQ(buffer, "\x02\x03\x02"); | 360 EXPECT_EQ(buffer, "\x02\x03\x02"); |
| 349 } | 361 } |
| 350 { | 362 { |
| 351 // Repeat the shortest 00 code to overflow |buffer|. Expect to fail. | 363 // Repeat the shortest 0b00 code to overflow |buffer|. Expect to fail. |
| 352 std::vector<char> input_storage(1 + capacity / 4, '\0'); | 364 std::vector<char> input_storage(1 + capacity / 4, '\0'); |
| 353 StringPiece input(&input_storage[0], input_storage.size()); | 365 StringPiece input(&input_storage[0], input_storage.size()); |
| 354 | 366 |
| 355 HpackInputStream input_stream(kuint32max, input); | 367 HpackInputStream input_stream(kuint32max, input); |
| 356 EXPECT_FALSE(table.DecodeString(&input_stream, capacity, &buffer)); | 368 EXPECT_FALSE(table_.DecodeString(&input_stream, capacity, &buffer)); |
| 357 | 369 |
| 358 std::vector<char> expected(capacity, '\x02'); | 370 std::vector<char> expected(capacity, '\x02'); |
| 359 EXPECT_THAT(buffer, ElementsAreArray(expected)); | 371 EXPECT_THAT(buffer, ElementsAreArray(expected)); |
| 360 EXPECT_EQ(capacity, buffer.size()); | 372 EXPECT_EQ(capacity, buffer.size()); |
| 361 } | 373 } |
| 362 { | 374 { |
| 363 // Expect to fail if more than a byte of unconsumed input remains. | 375 // Expect to fail if more than a byte of unconsumed input remains. |
| 364 // (6) 100110 (8 truncated) 1001110000 | 376 // (6) 100110 (8 truncated) 1001110000 |
| 365 char input_storage[] = {bits8("10011010"), bits8("01110000")}; | 377 char input_storage[] = {bits8("10011010"), bits8("01110000")}; |
| 366 StringPiece input(input_storage, arraysize(input_storage)); | 378 StringPiece input(input_storage, arraysize(input_storage)); |
| 367 | 379 |
| 368 HpackInputStream input_stream(kuint32max, input); | 380 HpackInputStream input_stream(kuint32max, input); |
| 369 EXPECT_FALSE(table.DecodeString(&input_stream, 4, &buffer)); | 381 EXPECT_FALSE(table_.DecodeString(&input_stream, capacity, &buffer)); |
| 370 EXPECT_EQ(buffer, "\x06"); | 382 EXPECT_EQ(buffer, "\x06"); |
| 371 } | 383 } |
| 372 } | 384 } |
| 373 | 385 |
| 374 TEST(HpackHuffmanTableTest, SpecRequestExamples) { | 386 TEST_F(HpackHuffmanTableTest, SpecRequestExamples) { |
| 375 const HpackHuffmanTable& table(ObtainHpackHuffmanTable()); | 387 std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode(); |
| 388 EXPECT_TRUE(table_.Initialize(&code[0], code.size())); |
| 376 | 389 |
| 377 string buffer; | 390 string buffer; |
| 378 string test_table[] = { | 391 string test_table[] = { |
| 379 "\xdb\x6d\x88\x3e\x68\xd1\xcb\x12\x25\xba\x7f", | 392 "\xdb\x6d\x88\x3e\x68\xd1\xcb\x12\x25\xba\x7f", |
| 380 "www.example.com", | 393 "www.example.com", |
| 381 "\x63\x65\x4a\x13\x98\xff", | 394 "\x63\x65\x4a\x13\x98\xff", |
| 382 "no-cache", | 395 "no-cache", |
| 383 "\x4e\xb0\x8b\x74\x97\x90\xfa\x7f", | 396 "\x4e\xb0\x8b\x74\x97\x90\xfa\x7f", |
| 384 "custom-key", | 397 "custom-key", |
| 385 "\x4e\xb0\x8b\x74\x97\x9a\x17\xa8\xff", | 398 "\x4e\xb0\x8b\x74\x97\x9a\x17\xa8\xff", |
| 386 "custom-value", | 399 "custom-value", |
| 387 }; | 400 }; |
| 388 // Round-trip each test example. | 401 // Round-trip each test example. |
| 389 for (size_t i = 0; i != arraysize(test_table); i += 2) { | 402 for (size_t i = 0; i != arraysize(test_table); i += 2) { |
| 390 const string& encoded(test_table[i]); | 403 const string& encodedFixture(test_table[i]); |
| 391 const string& decoded(test_table[i+1]); | 404 const string& decodedFixture(test_table[i+1]); |
| 392 HpackInputStream input_stream(kuint32max, encoded); | 405 HpackInputStream input_stream(kuint32max, encodedFixture); |
| 393 HpackOutputStream output_stream; | |
| 394 | 406 |
| 395 buffer.reserve(decoded.size()); | 407 EXPECT_TRUE(table_.DecodeString(&input_stream, decodedFixture.size(), |
| 396 EXPECT_TRUE(table.DecodeString(&input_stream, decoded.size(), &buffer)); | 408 &buffer)); |
| 397 EXPECT_EQ(decoded, buffer); | 409 EXPECT_EQ(decodedFixture, buffer); |
| 398 table.EncodeString(decoded, &output_stream); | 410 buffer = EncodeString(decodedFixture); |
| 399 output_stream.TakeString(&buffer); | 411 EXPECT_EQ(encodedFixture, buffer); |
| 400 EXPECT_EQ(encoded, buffer); | |
| 401 } | 412 } |
| 402 } | 413 } |
| 403 | 414 |
| 404 TEST(HpackHuffmanTableTest, SpecResponseExamples) { | 415 TEST_F(HpackHuffmanTableTest, SpecResponseExamples) { |
| 405 const HpackHuffmanTable& table(ObtainHpackHuffmanTable()); | 416 std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode(); |
| 417 EXPECT_TRUE(table_.Initialize(&code[0], code.size())); |
| 406 | 418 |
| 407 string buffer; | 419 string buffer; |
| 408 string test_table[] = { | 420 string test_table[] = { |
| 409 "\x98\xa7", | 421 "\x98\xa7", |
| 410 "302", | 422 "302", |
| 411 "\x73\xd5\xcd\x11\x1f", | 423 "\x73\xd5\xcd\x11\x1f", |
| 412 "private", | 424 "private", |
| 413 "\xef\x6b\x3a\x7a\x0e\x6e\x8f\xa2\x63\xd0\x72\x9a\x6e\x83\x97\xd8" | 425 "\xef\x6b\x3a\x7a\x0e\x6e\x8f\xa2\x63\xd0\x72\x9a\x6e\x83\x97\xd8" |
| 414 "\x69\xbd\x87\x37\x47\xbb\xbf\xc7", | 426 "\x69\xbd\x87\x37\x47\xbb\xbf\xc7", |
| 415 "Mon, 21 Oct 2013 20:13:21 GMT", | 427 "Mon, 21 Oct 2013 20:13:21 GMT", |
| 416 "\xce\x31\x74\x3d\x80\x1b\x6d\xb1\x07\xcd\x1a\x39\x62\x44\xb7\x4f", | 428 "\xce\x31\x74\x3d\x80\x1b\x6d\xb1\x07\xcd\x1a\x39\x62\x44\xb7\x4f", |
| 417 "https://www.example.com", | 429 "https://www.example.com", |
| 418 "\xc5\xad\xb7\x7f\x87\x6f\xc7\xfb\xf7\xfd\xbf\xbe\xbf\xf3\xf7\xf4" | 430 "\xc5\xad\xb7\x7f\x87\x6f\xc7\xfb\xf7\xfd\xbf\xbe\xbf\xf3\xf7\xf4" |
| 419 "\xfb\x7e\xbb\xbe\x9f\x5f\x87\xe3\x7f\xef\xed\xfa\xee\xfa\x7c\x3f" | 431 "\xfb\x7e\xbb\xbe\x9f\x5f\x87\xe3\x7f\xef\xed\xfa\xee\xfa\x7c\x3f" |
| 420 "\x1d\x5d\x1a\x23\xce\x54\x64\x36\xcd\x49\x4b\xd5\xd1\xcc\x5f\x05" | 432 "\x1d\x5d\x1a\x23\xce\x54\x64\x36\xcd\x49\x4b\xd5\xd1\xcc\x5f\x05" |
| 421 "\x35\x96\x9b", | 433 "\x35\x96\x9b", |
| 422 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", | 434 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", |
| 423 }; | 435 }; |
| 424 // Round-trip each test example. | 436 // Round-trip each test example. |
| 425 for (size_t i = 0; i != arraysize(test_table); i += 2) { | 437 for (size_t i = 0; i != arraysize(test_table); i += 2) { |
| 426 const string& encoded(test_table[i]); | 438 const string& encodedFixture(test_table[i]); |
| 427 const string& decoded(test_table[i+1]); | 439 const string& decodedFixture(test_table[i+1]); |
| 428 HpackInputStream input_stream(kuint32max, encoded); | 440 HpackInputStream input_stream(kuint32max, encodedFixture); |
| 429 HpackOutputStream output_stream; | |
| 430 | 441 |
| 431 buffer.reserve(decoded.size()); | 442 EXPECT_TRUE(table_.DecodeString(&input_stream, decodedFixture.size(), |
| 432 EXPECT_TRUE(table.DecodeString(&input_stream, decoded.size(), &buffer)); | 443 &buffer)); |
| 433 EXPECT_EQ(decoded, buffer); | 444 EXPECT_EQ(decodedFixture, buffer); |
| 434 table.EncodeString(decoded, &output_stream); | 445 buffer = EncodeString(decodedFixture); |
| 435 output_stream.TakeString(&buffer); | 446 EXPECT_EQ(encodedFixture, buffer); |
| 436 EXPECT_EQ(encoded, buffer); | |
| 437 } | 447 } |
| 438 } | 448 } |
| 439 | 449 |
| 440 TEST(HpackHuffmanTableTest, RoundTripIndvidualSymbols) { | 450 TEST_F(HpackHuffmanTableTest, RoundTripIndvidualSymbols) { |
| 441 const HpackHuffmanTable& table(ObtainHpackHuffmanTable()); | 451 std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode(); |
| 452 EXPECT_TRUE(table_.Initialize(&code[0], code.size())); |
| 442 | 453 |
| 443 for (size_t i = 0; i != 256; i++) { | 454 for (size_t i = 0; i != 256; i++) { |
| 444 char c = static_cast<char>(i); | 455 char c = static_cast<char>(i); |
| 445 char storage[3] = {c, c, c}; | 456 char storage[3] = {c, c, c}; |
| 446 StringPiece input(storage, arraysize(storage)); | 457 StringPiece input(storage, arraysize(storage)); |
| 447 | 458 |
| 448 string buffer_in, buffer_out(input.size(), '\0'); | 459 string buffer_in = EncodeString(input); |
| 449 HpackOutputStream output_stream; | 460 string buffer_out; |
| 450 table.EncodeString(input, &output_stream); | |
| 451 output_stream.TakeString(&buffer_in); | |
| 452 | 461 |
| 453 HpackInputStream input_stream(kuint32max, buffer_in); | 462 HpackInputStream input_stream(kuint32max, buffer_in); |
| 454 EXPECT_TRUE(table.DecodeString(&input_stream, input.size(), &buffer_out)); | 463 EXPECT_TRUE(table_.DecodeString(&input_stream, input.size(), &buffer_out)); |
| 455 EXPECT_EQ(input, buffer_out); | 464 EXPECT_EQ(input, buffer_out); |
| 456 } | 465 } |
| 457 } | 466 } |
| 458 | 467 |
| 459 TEST(HpackHuffmanTableTest, RoundTripSymbolSequence) { | 468 TEST_F(HpackHuffmanTableTest, RoundTripSymbolSequence) { |
| 460 const HpackHuffmanTable& table(ObtainHpackHuffmanTable()); | 469 std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode(); |
| 470 EXPECT_TRUE(table_.Initialize(&code[0], code.size())); |
| 471 |
| 461 | 472 |
| 462 char storage[512]; | 473 char storage[512]; |
| 463 for (size_t i = 0; i != 256; i++) { | 474 for (size_t i = 0; i != 256; i++) { |
| 464 storage[i] = static_cast<char>(i); | 475 storage[i] = static_cast<char>(i); |
| 465 storage[511 - i] = static_cast<char>(i); | 476 storage[511 - i] = static_cast<char>(i); |
| 466 } | 477 } |
| 467 StringPiece input(storage, arraysize(storage)); | 478 StringPiece input(storage, arraysize(storage)); |
| 468 | 479 |
| 469 string buffer_in, buffer_out(input.size(), '\0'); | 480 string buffer_in = EncodeString(input); |
| 470 HpackOutputStream output_stream; | 481 string buffer_out; |
| 471 table.EncodeString(input, &output_stream); | |
| 472 output_stream.TakeString(&buffer_in); | |
| 473 | 482 |
| 474 HpackInputStream input_stream(kuint32max, buffer_in); | 483 HpackInputStream input_stream(kuint32max, buffer_in); |
| 475 EXPECT_TRUE(table.DecodeString(&input_stream, input.size(), &buffer_out)); | 484 EXPECT_TRUE(table_.DecodeString(&input_stream, input.size(), &buffer_out)); |
| 476 EXPECT_EQ(input, buffer_out); | 485 EXPECT_EQ(input, buffer_out); |
| 477 } | 486 } |
| 478 | 487 |
| 488 TEST_F(HpackHuffmanTableTest, EncodedSizeAgreesWithEncodeString) { |
| 489 std::vector<HpackHuffmanSymbol> code = HpackHuffmanCode(); |
| 490 EXPECT_TRUE(table_.Initialize(&code[0], code.size())); |
| 491 |
| 492 string test_table[] = { |
| 493 "", |
| 494 "Mon, 21 Oct 2013 20:13:21 GMT", |
| 495 "https://www.example.com", |
| 496 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", |
| 497 string(1, '\0'), |
| 498 string("foo\0bar", 7), |
| 499 string(256, '\0'), |
| 500 }; |
| 501 for (size_t i = 0; i != 256; ++i) { |
| 502 // Expand last |test_table| entry to cover all codes. |
| 503 test_table[arraysize(test_table)-1][i] = static_cast<char>(i); |
| 504 } |
| 505 |
| 506 HpackOutputStream output_stream; |
| 507 string encoding; |
| 508 for (size_t i = 0; i != arraysize(test_table); ++i) { |
| 509 table_.EncodeString(test_table[i], &output_stream); |
| 510 output_stream.TakeString(&encoding); |
| 511 EXPECT_EQ(encoding.size(), table_.EncodedSize(test_table[i])); |
| 512 } |
| 513 } |
| 514 |
| 479 } // namespace | 515 } // namespace |
| 480 | 516 |
| 481 } // namespace test | 517 } // namespace test |
| 482 | 518 |
| 483 } // namespace net | 519 } // namespace net |
| OLD | NEW |