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