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> | 8 #include <string> |
9 | 9 |
| 10 #include "net/base/arena.h" |
10 #include "testing/gmock/include/gmock/gmock.h" | 11 #include "testing/gmock/include/gmock/gmock.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
12 | 13 |
13 namespace net { | 14 namespace net { |
14 | 15 |
15 using base::StringPiece; | 16 using base::StringPiece; |
16 using std::string; | 17 using std::string; |
| 18 using std::vector; |
| 19 using std::pair; |
17 using testing::ElementsAre; | 20 using testing::ElementsAre; |
18 | 21 |
19 namespace test { | 22 namespace test { |
20 | 23 |
21 class HpackHeaderTablePeer { | 24 class HpackHeaderTablePeer { |
22 public: | 25 public: |
23 explicit HpackHeaderTablePeer(HpackHeaderTable* table) : table_(table) {} | 26 explicit HpackHeaderTablePeer(HpackHeaderTable* table) : table_(table) {} |
24 | 27 |
25 HpackHeaderTable::EntryTable* dynamic_entries() { | 28 HpackHeaderTable::EntryTable* dynamic_entries() { |
26 return &table_->dynamic_entries_; | 29 return &table_->dynamic_entries_; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 private: | 72 private: |
70 HpackEncoder* encoder_; | 73 HpackEncoder* encoder_; |
71 }; | 74 }; |
72 | 75 |
73 } // namespace test | 76 } // namespace test |
74 | 77 |
75 namespace { | 78 namespace { |
76 | 79 |
77 using std::map; | 80 using std::map; |
78 using testing::ElementsAre; | 81 using testing::ElementsAre; |
| 82 using testing::Pair; |
79 | 83 |
80 class HpackEncoderTest : public ::testing::Test { | 84 class HpackEncoderTest : public ::testing::Test { |
81 protected: | 85 protected: |
82 typedef test::HpackEncoderPeer::Representations Representations; | 86 typedef test::HpackEncoderPeer::Representations Representations; |
83 | 87 |
84 HpackEncoderTest() | 88 HpackEncoderTest() |
85 : encoder_(ObtainHpackHuffmanTable()), | 89 : encoder_(ObtainHpackHuffmanTable()), |
86 peer_(&encoder_), | 90 peer_(&encoder_), |
87 static_(peer_.table()->GetByIndex(1)) {} | 91 static_(peer_.table()->GetByIndex(1)), |
| 92 headers_storage_(1024 /* block size */) {} |
88 | 93 |
89 void SetUp() override { | 94 void SetUp() override { |
90 // Populate dynamic entries into the table fixture. For simplicity each | 95 // Populate dynamic entries into the table fixture. For simplicity each |
91 // entry has name.size() + value.size() == 10. | 96 // entry has name.size() + value.size() == 10. |
92 key_1_ = peer_.table()->TryAddEntry("key1", "value1"); | 97 key_1_ = peer_.table()->TryAddEntry("key1", "value1"); |
93 key_2_ = peer_.table()->TryAddEntry("key2", "value2"); | 98 key_2_ = peer_.table()->TryAddEntry("key2", "value2"); |
94 cookie_a_ = peer_.table()->TryAddEntry("cookie", "a=bb"); | 99 cookie_a_ = peer_.table()->TryAddEntry("cookie", "a=bb"); |
95 cookie_c_ = peer_.table()->TryAddEntry("cookie", "c=dd"); | 100 cookie_c_ = peer_.table()->TryAddEntry("cookie", "c=dd"); |
96 | 101 |
97 // No further insertions may occur without evictions. | 102 // No further insertions may occur without evictions. |
98 peer_.table()->SetMaxSize(peer_.table()->size()); | 103 peer_.table()->SetMaxSize(peer_.table()->size()); |
99 | 104 |
100 // Disable Huffman coding by default. Most tests don't care about it. | 105 // Disable Huffman coding by default. Most tests don't care about it. |
101 peer_.set_allow_huffman_compression(false); | 106 peer_.set_allow_huffman_compression(false); |
102 } | 107 } |
103 | 108 |
| 109 void SaveHeaders(StringPiece name, StringPiece value) { |
| 110 StringPiece n(headers_storage_.Memdup(name.data(), name.size()), |
| 111 name.size()); |
| 112 StringPiece v(headers_storage_.Memdup(value.data(), value.size()), |
| 113 value.size()); |
| 114 headers_observed_.push_back(make_pair(n, v)); |
| 115 } |
| 116 |
104 void ExpectIndex(size_t index) { | 117 void ExpectIndex(size_t index) { |
105 expected_.AppendPrefix(kIndexedOpcode); | 118 expected_.AppendPrefix(kIndexedOpcode); |
106 expected_.AppendUint32(index); | 119 expected_.AppendUint32(index); |
107 } | 120 } |
108 void ExpectIndexedLiteral(const HpackEntry* key_entry, StringPiece value) { | 121 void ExpectIndexedLiteral(const HpackEntry* key_entry, StringPiece value) { |
109 expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); | 122 expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); |
110 expected_.AppendUint32(IndexOf(key_entry)); | 123 expected_.AppendUint32(IndexOf(key_entry)); |
111 expected_.AppendPrefix(kStringLiteralIdentityEncoded); | 124 expected_.AppendPrefix(kStringLiteralIdentityEncoded); |
112 expected_.AppendUint32(value.size()); | 125 expected_.AppendUint32(value.size()); |
113 expected_.AppendBytes(value); | 126 expected_.AppendBytes(value); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 | 161 |
149 HpackEncoder encoder_; | 162 HpackEncoder encoder_; |
150 test::HpackEncoderPeer peer_; | 163 test::HpackEncoderPeer peer_; |
151 | 164 |
152 const HpackEntry* static_; | 165 const HpackEntry* static_; |
153 const HpackEntry* key_1_; | 166 const HpackEntry* key_1_; |
154 const HpackEntry* key_2_; | 167 const HpackEntry* key_2_; |
155 const HpackEntry* cookie_a_; | 168 const HpackEntry* cookie_a_; |
156 const HpackEntry* cookie_c_; | 169 const HpackEntry* cookie_c_; |
157 | 170 |
| 171 UnsafeArena headers_storage_; |
| 172 vector<pair<StringPiece, StringPiece>> headers_observed_; |
| 173 |
158 HpackOutputStream expected_; | 174 HpackOutputStream expected_; |
159 }; | 175 }; |
160 | 176 |
161 TEST_F(HpackEncoderTest, SingleDynamicIndex) { | 177 TEST_F(HpackEncoderTest, SingleDynamicIndex) { |
| 178 encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) { |
| 179 this->SaveHeaders(name, value); |
| 180 }); |
| 181 |
162 ExpectIndex(IndexOf(key_2_)); | 182 ExpectIndex(IndexOf(key_2_)); |
163 | 183 |
164 SpdyHeaderBlock headers; | 184 SpdyHeaderBlock headers; |
165 headers[key_2_->name().as_string()] = key_2_->value().as_string(); | 185 headers[key_2_->name().as_string()] = key_2_->value().as_string(); |
166 CompareWithExpectedEncoding(headers); | 186 CompareWithExpectedEncoding(headers); |
| 187 EXPECT_THAT(headers_observed_, |
| 188 ElementsAre(Pair(key_2_->name(), key_2_->value()))); |
167 } | 189 } |
168 | 190 |
169 TEST_F(HpackEncoderTest, SingleStaticIndex) { | 191 TEST_F(HpackEncoderTest, SingleStaticIndex) { |
170 ExpectIndex(IndexOf(static_)); | 192 ExpectIndex(IndexOf(static_)); |
171 | 193 |
172 SpdyHeaderBlock headers; | 194 SpdyHeaderBlock headers; |
173 headers[static_->name().as_string()] = static_->value().as_string(); | 195 headers[static_->name().as_string()] = static_->value().as_string(); |
174 CompareWithExpectedEncoding(headers); | 196 CompareWithExpectedEncoding(headers); |
175 } | 197 } |
176 | 198 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 expected_.AppendUint32(6); | 283 expected_.AppendUint32(6); |
262 expected_.AppendBytes("@@@@@@"); | 284 expected_.AppendBytes("@@@@@@"); |
263 | 285 |
264 string expected_out, actual_out; | 286 string expected_out, actual_out; |
265 expected_.TakeString(&expected_out); | 287 expected_.TakeString(&expected_out); |
266 peer_.TakeString(&actual_out); | 288 peer_.TakeString(&actual_out); |
267 EXPECT_EQ(expected_out, actual_out); | 289 EXPECT_EQ(expected_out, actual_out); |
268 } | 290 } |
269 | 291 |
270 TEST_F(HpackEncoderTest, EncodingWithoutCompression) { | 292 TEST_F(HpackEncoderTest, EncodingWithoutCompression) { |
| 293 encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) { |
| 294 this->SaveHeaders(name, value); |
| 295 }); |
| 296 |
271 // Implementation should internally disable. | 297 // Implementation should internally disable. |
272 peer_.set_allow_huffman_compression(true); | 298 peer_.set_allow_huffman_compression(true); |
273 | 299 |
274 ExpectNonIndexedLiteral(":path", "/index.html"); | 300 ExpectNonIndexedLiteral(":path", "/index.html"); |
275 ExpectNonIndexedLiteral("cookie", "foo=bar; baz=bing"); | 301 ExpectNonIndexedLiteral("cookie", "foo=bar; baz=bing"); |
276 ExpectNonIndexedLiteral("hello", "goodbye"); | 302 ExpectNonIndexedLiteral("hello", "goodbye"); |
277 | 303 |
278 SpdyHeaderBlock headers; | 304 SpdyHeaderBlock headers; |
279 headers[":path"] = "/index.html"; | 305 headers[":path"] = "/index.html"; |
280 headers["cookie"] = "foo=bar; baz=bing"; | 306 headers["cookie"] = "foo=bar; baz=bing"; |
281 headers["hello"] = "goodbye"; | 307 headers["hello"] = "goodbye"; |
282 | 308 |
283 string expected_out, actual_out; | 309 string expected_out, actual_out; |
284 expected_.TakeString(&expected_out); | 310 expected_.TakeString(&expected_out); |
285 encoder_.EncodeHeaderSetWithoutCompression(headers, &actual_out); | 311 encoder_.EncodeHeaderSetWithoutCompression(headers, &actual_out); |
286 EXPECT_EQ(expected_out, actual_out); | 312 EXPECT_EQ(expected_out, actual_out); |
| 313 |
| 314 EXPECT_THAT(headers_observed_, |
| 315 ElementsAre(Pair(":path", "/index.html"), |
| 316 Pair("cookie", "foo=bar; baz=bing"), |
| 317 Pair("hello", "goodbye"))); |
287 } | 318 } |
288 | 319 |
289 TEST_F(HpackEncoderTest, MultipleEncodingPasses) { | 320 TEST_F(HpackEncoderTest, MultipleEncodingPasses) { |
| 321 encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) { |
| 322 this->SaveHeaders(name, value); |
| 323 }); |
| 324 |
290 // Pass 1. | 325 // Pass 1. |
291 { | 326 { |
292 SpdyHeaderBlock headers; | 327 SpdyHeaderBlock headers; |
293 headers["key1"] = "value1"; | 328 headers["key1"] = "value1"; |
294 headers["cookie"] = "a=bb"; | 329 headers["cookie"] = "a=bb"; |
295 | 330 |
296 ExpectIndex(IndexOf(key_1_)); | 331 ExpectIndex(IndexOf(key_1_)); |
297 ExpectIndex(IndexOf(cookie_a_)); | 332 ExpectIndex(IndexOf(cookie_a_)); |
298 CompareWithExpectedEncoding(headers); | 333 CompareWithExpectedEncoding(headers); |
299 } | 334 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 ExpectIndex(65); | 367 ExpectIndex(65); |
333 // "cookie: a=bb" | 368 // "cookie: a=bb" |
334 ExpectIndex(64); | 369 ExpectIndex(64); |
335 // This cookie evicts |key2| from the dynamic table. | 370 // This cookie evicts |key2| from the dynamic table. |
336 ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "b=cc"); | 371 ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "b=cc"); |
337 // "cookie: c=dd" | 372 // "cookie: c=dd" |
338 ExpectIndex(64); | 373 ExpectIndex(64); |
339 | 374 |
340 CompareWithExpectedEncoding(headers); | 375 CompareWithExpectedEncoding(headers); |
341 } | 376 } |
| 377 |
| 378 // clang-format off |
| 379 EXPECT_THAT(headers_observed_, |
| 380 ElementsAre(Pair("key1", "value1"), |
| 381 Pair("cookie", "a=bb"), |
| 382 Pair("key2", "value2"), |
| 383 Pair("cookie", "c=dd"), |
| 384 Pair("cookie", "e=ff"), |
| 385 Pair("key2", "value2"), |
| 386 Pair("cookie", "a=bb"), |
| 387 Pair("cookie", "b=cc"), |
| 388 Pair("cookie", "c=dd"))); |
| 389 // clang-format on |
342 } | 390 } |
343 | 391 |
344 TEST_F(HpackEncoderTest, PseudoHeadersFirst) { | 392 TEST_F(HpackEncoderTest, PseudoHeadersFirst) { |
345 SpdyHeaderBlock headers; | 393 SpdyHeaderBlock headers; |
346 // A pseudo-header that should not be indexed. | 394 // A pseudo-header that should not be indexed. |
347 headers[":path"] = "/spam/eggs.html"; | 395 headers[":path"] = "/spam/eggs.html"; |
348 // A pseudo-header to be indexed. | 396 // A pseudo-header to be indexed. |
349 headers[":authority"] = "www.example.com"; | 397 headers[":authority"] = "www.example.com"; |
350 // A regular header which precedes ":" alphabetically, should still be encoded | 398 // A regular header which precedes ":" alphabetically, should still be encoded |
351 // after pseudo-headers. | 399 // after pseudo-headers. |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 CompareWithExpectedEncoding(headers); | 545 CompareWithExpectedEncoding(headers); |
498 | 546 |
499 HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); | 547 HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); |
500 EXPECT_EQ(new_entry->name(), "key3"); | 548 EXPECT_EQ(new_entry->name(), "key3"); |
501 EXPECT_EQ(new_entry->value(), "value3"); | 549 EXPECT_EQ(new_entry->value(), "value3"); |
502 } | 550 } |
503 | 551 |
504 } // namespace | 552 } // namespace |
505 | 553 |
506 } // namespace net | 554 } // namespace net |
OLD | NEW |