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/hpack_encoder.h" | 5 #include "net/spdy/hpack/hpack_encoder.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <string> | |
9 | 8 |
10 #include "base/rand_util.h" | 9 #include "base/rand_util.h" |
11 #include "net/base/arena.h" | 10 #include "net/base/arena.h" |
12 #include "net/spdy/hpack/hpack_huffman_table.h" | 11 #include "net/spdy/hpack/hpack_huffman_table.h" |
13 #include "testing/gmock/include/gmock/gmock.h" | 12 #include "testing/gmock/include/gmock/gmock.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
15 | 14 |
16 namespace net { | 15 namespace net { |
17 | 16 |
18 using std::string; | |
19 using testing::ElementsAre; | 17 using testing::ElementsAre; |
20 | 18 |
21 namespace test { | 19 namespace test { |
22 | 20 |
23 class HpackHeaderTablePeer { | 21 class HpackHeaderTablePeer { |
24 public: | 22 public: |
25 explicit HpackHeaderTablePeer(HpackHeaderTable* table) : table_(table) {} | 23 explicit HpackHeaderTablePeer(HpackHeaderTable* table) : table_(table) {} |
26 | 24 |
27 HpackHeaderTable::EntryTable* dynamic_entries() { | 25 HpackHeaderTable::EntryTable* dynamic_entries() { |
28 return &table_->dynamic_entries_; | 26 return &table_->dynamic_entries_; |
(...skipping 10 matching lines...) Expand all Loading... |
39 | 37 |
40 explicit HpackEncoderPeer(HpackEncoder* encoder) : encoder_(encoder) {} | 38 explicit HpackEncoderPeer(HpackEncoder* encoder) : encoder_(encoder) {} |
41 | 39 |
42 bool compression_enabled() const { return encoder_->enable_compression_; } | 40 bool compression_enabled() const { return encoder_->enable_compression_; } |
43 HpackHeaderTable* table() { return &encoder_->header_table_; } | 41 HpackHeaderTable* table() { return &encoder_->header_table_; } |
44 HpackHeaderTablePeer table_peer() { return HpackHeaderTablePeer(table()); } | 42 HpackHeaderTablePeer table_peer() { return HpackHeaderTablePeer(table()); } |
45 const HpackHuffmanTable& huffman_table() const { | 43 const HpackHuffmanTable& huffman_table() const { |
46 return encoder_->huffman_table_; | 44 return encoder_->huffman_table_; |
47 } | 45 } |
48 void EmitString(SpdyStringPiece str) { encoder_->EmitString(str); } | 46 void EmitString(SpdyStringPiece str) { encoder_->EmitString(str); } |
49 void TakeString(string* out) { encoder_->output_stream_.TakeString(out); } | 47 void TakeString(SpdyString* out) { encoder_->output_stream_.TakeString(out); } |
50 static void CookieToCrumbs(SpdyStringPiece cookie, | 48 static void CookieToCrumbs(SpdyStringPiece cookie, |
51 std::vector<SpdyStringPiece>* out) { | 49 std::vector<SpdyStringPiece>* out) { |
52 Representations tmp; | 50 Representations tmp; |
53 HpackEncoder::CookieToCrumbs(std::make_pair("", cookie), &tmp); | 51 HpackEncoder::CookieToCrumbs(std::make_pair("", cookie), &tmp); |
54 | 52 |
55 out->clear(); | 53 out->clear(); |
56 for (size_t i = 0; i != tmp.size(); ++i) { | 54 for (size_t i = 0; i != tmp.size(); ++i) { |
57 out->push_back(tmp[i].second); | 55 out->push_back(tmp[i].second); |
58 } | 56 } |
59 } | 57 } |
60 static void DecomposeRepresentation(SpdyStringPiece value, | 58 static void DecomposeRepresentation(SpdyStringPiece value, |
61 std::vector<SpdyStringPiece>* out) { | 59 std::vector<SpdyStringPiece>* out) { |
62 Representations tmp; | 60 Representations tmp; |
63 HpackEncoder::DecomposeRepresentation(std::make_pair("foobar", value), | 61 HpackEncoder::DecomposeRepresentation(std::make_pair("foobar", value), |
64 &tmp); | 62 &tmp); |
65 | 63 |
66 out->clear(); | 64 out->clear(); |
67 for (size_t i = 0; i != tmp.size(); ++i) { | 65 for (size_t i = 0; i != tmp.size(); ++i) { |
68 out->push_back(tmp[i].second); | 66 out->push_back(tmp[i].second); |
69 } | 67 } |
70 } | 68 } |
71 | 69 |
72 // TODO(dahollings): Remove or clean up these methods when deprecating | 70 // TODO(dahollings): Remove or clean up these methods when deprecating |
73 // non-incremental encoding path. | 71 // non-incremental encoding path. |
74 static bool EncodeHeaderSet(HpackEncoder* encoder, | 72 static bool EncodeHeaderSet(HpackEncoder* encoder, |
75 const SpdyHeaderBlock& header_set, | 73 const SpdyHeaderBlock& header_set, |
76 string* output, | 74 SpdyString* output, |
77 bool use_incremental) { | 75 bool use_incremental) { |
78 if (use_incremental) { | 76 if (use_incremental) { |
79 return EncodeIncremental(encoder, header_set, output); | 77 return EncodeIncremental(encoder, header_set, output); |
80 } else { | 78 } else { |
81 return encoder->EncodeHeaderSet(header_set, output); | 79 return encoder->EncodeHeaderSet(header_set, output); |
82 } | 80 } |
83 } | 81 } |
84 | 82 |
85 static bool EncodeIncremental(HpackEncoder* encoder, | 83 static bool EncodeIncremental(HpackEncoder* encoder, |
86 const SpdyHeaderBlock& header_set, | 84 const SpdyHeaderBlock& header_set, |
87 string* output) { | 85 SpdyString* output) { |
88 std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoderator = | 86 std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoderator = |
89 encoder->EncodeHeaderSet(header_set); | 87 encoder->EncodeHeaderSet(header_set); |
90 string output_buffer; | 88 SpdyString output_buffer; |
91 encoderator->Next(base::RandInt(0, 15), &output_buffer); | 89 encoderator->Next(base::RandInt(0, 15), &output_buffer); |
92 while (encoderator->HasNext()) { | 90 while (encoderator->HasNext()) { |
93 string second_buffer; | 91 SpdyString second_buffer; |
94 encoderator->Next(base::RandInt(0, 15), &second_buffer); | 92 encoderator->Next(base::RandInt(0, 15), &second_buffer); |
95 output_buffer.append(second_buffer); | 93 output_buffer.append(second_buffer); |
96 } | 94 } |
97 *output = std::move(output_buffer); | 95 *output = std::move(output_buffer); |
98 return true; | 96 return true; |
99 } | 97 } |
100 | 98 |
101 private: | 99 private: |
102 HpackEncoder* encoder_; | 100 HpackEncoder* encoder_; |
103 }; | 101 }; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 expected_.AppendPrefix(kStringLiteralIdentityEncoded); | 175 expected_.AppendPrefix(kStringLiteralIdentityEncoded); |
178 expected_.AppendUint32(str.size()); | 176 expected_.AppendUint32(str.size()); |
179 expected_.AppendBytes(str); | 177 expected_.AppendBytes(str); |
180 } | 178 } |
181 } | 179 } |
182 void ExpectHeaderTableSizeUpdate(uint32_t size) { | 180 void ExpectHeaderTableSizeUpdate(uint32_t size) { |
183 expected_.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 181 expected_.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
184 expected_.AppendUint32(size); | 182 expected_.AppendUint32(size); |
185 } | 183 } |
186 void CompareWithExpectedEncoding(const SpdyHeaderBlock& header_set) { | 184 void CompareWithExpectedEncoding(const SpdyHeaderBlock& header_set) { |
187 string expected_out, actual_out; | 185 SpdyString expected_out, actual_out; |
188 expected_.TakeString(&expected_out); | 186 expected_.TakeString(&expected_out); |
189 EXPECT_TRUE(test::HpackEncoderPeer::EncodeHeaderSet( | 187 EXPECT_TRUE(test::HpackEncoderPeer::EncodeHeaderSet( |
190 &encoder_, header_set, &actual_out, use_incremental_)); | 188 &encoder_, header_set, &actual_out, use_incremental_)); |
191 EXPECT_EQ(expected_out, actual_out); | 189 EXPECT_EQ(expected_out, actual_out); |
192 } | 190 } |
193 size_t IndexOf(const HpackEntry* entry) { | 191 size_t IndexOf(const HpackEntry* entry) { |
194 return peer_.table()->IndexOf(entry); | 192 return peer_.table()->IndexOf(entry); |
195 } | 193 } |
196 | 194 |
197 HpackEncoder encoder_; | 195 HpackEncoder encoder_; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 expected_.AppendPrefix(kStringLiteralHuffmanEncoded); | 311 expected_.AppendPrefix(kStringLiteralHuffmanEncoded); |
314 expected_.AppendUint32(6); | 312 expected_.AppendUint32(6); |
315 expected_.AppendBytes("\x94\xA5\x92\x32\x96_"); | 313 expected_.AppendBytes("\x94\xA5\x92\x32\x96_"); |
316 | 314 |
317 // Non-compactable. Uses identity coding. | 315 // Non-compactable. Uses identity coding. |
318 peer_.EmitString("@@@@@@"); | 316 peer_.EmitString("@@@@@@"); |
319 expected_.AppendPrefix(kStringLiteralIdentityEncoded); | 317 expected_.AppendPrefix(kStringLiteralIdentityEncoded); |
320 expected_.AppendUint32(6); | 318 expected_.AppendUint32(6); |
321 expected_.AppendBytes("@@@@@@"); | 319 expected_.AppendBytes("@@@@@@"); |
322 | 320 |
323 string expected_out, actual_out; | 321 SpdyString expected_out, actual_out; |
324 expected_.TakeString(&expected_out); | 322 expected_.TakeString(&expected_out); |
325 peer_.TakeString(&actual_out); | 323 peer_.TakeString(&actual_out); |
326 EXPECT_EQ(expected_out, actual_out); | 324 EXPECT_EQ(expected_out, actual_out); |
327 } | 325 } |
328 | 326 |
329 TEST_P(HpackEncoderTest, EncodingWithoutCompression) { | 327 TEST_P(HpackEncoderTest, EncodingWithoutCompression) { |
330 encoder_.SetHeaderListener( | 328 encoder_.SetHeaderListener( |
331 [this](SpdyStringPiece name, SpdyStringPiece value) { | 329 [this](SpdyStringPiece name, SpdyStringPiece value) { |
332 this->SaveHeaders(name, value); | 330 this->SaveHeaders(name, value); |
333 }); | 331 }); |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 | 500 |
503 peer.DecomposeRepresentation(SpdyStringPiece("\0foo\0bar\0", 9), &out); | 501 peer.DecomposeRepresentation(SpdyStringPiece("\0foo\0bar\0", 9), &out); |
504 EXPECT_THAT(out, ElementsAre("", "foo", "bar", "")); | 502 EXPECT_THAT(out, ElementsAre("", "foo", "bar", "")); |
505 } | 503 } |
506 | 504 |
507 // Test that encoded headers do not have \0-delimited multiple values, as this | 505 // Test that encoded headers do not have \0-delimited multiple values, as this |
508 // became disallowed in HTTP/2 draft-14. | 506 // became disallowed in HTTP/2 draft-14. |
509 TEST_P(HpackEncoderTest, CrumbleNullByteDelimitedValue) { | 507 TEST_P(HpackEncoderTest, CrumbleNullByteDelimitedValue) { |
510 SpdyHeaderBlock headers; | 508 SpdyHeaderBlock headers; |
511 // A header field to be crumbled: "spam: foo\0bar". | 509 // A header field to be crumbled: "spam: foo\0bar". |
512 headers["spam"] = string("foo\0bar", 7); | 510 headers["spam"] = SpdyString("foo\0bar", 7); |
513 | 511 |
514 ExpectIndexedLiteral("spam", "foo"); | 512 ExpectIndexedLiteral("spam", "foo"); |
515 expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); | 513 expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); |
516 expected_.AppendUint32(62); | 514 expected_.AppendUint32(62); |
517 expected_.AppendPrefix(kStringLiteralIdentityEncoded); | 515 expected_.AppendPrefix(kStringLiteralIdentityEncoded); |
518 expected_.AppendUint32(3); | 516 expected_.AppendUint32(3); |
519 expected_.AppendBytes("bar"); | 517 expected_.AppendBytes("bar"); |
520 CompareWithExpectedEncoding(headers); | 518 CompareWithExpectedEncoding(headers); |
521 } | 519 } |
522 | 520 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
580 CompareWithExpectedEncoding(headers); | 578 CompareWithExpectedEncoding(headers); |
581 | 579 |
582 HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); | 580 HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); |
583 EXPECT_EQ(new_entry->name(), "key3"); | 581 EXPECT_EQ(new_entry->name(), "key3"); |
584 EXPECT_EQ(new_entry->value(), "value3"); | 582 EXPECT_EQ(new_entry->value(), "value3"); |
585 } | 583 } |
586 | 584 |
587 } // namespace | 585 } // namespace |
588 | 586 |
589 } // namespace net | 587 } // namespace net |
OLD | NEW |