| 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 |