| 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_encoder.h" | 5 #include "net/spdy/hpack_encoder.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "testing/gmock/include/gmock/gmock.h" | 10 #include "testing/gmock/include/gmock/gmock.h" |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 // 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. |
| 106 peer_.set_allow_huffman_compression(false); | 106 peer_.set_allow_huffman_compression(false); |
| 107 } | 107 } |
| 108 | 108 |
| 109 void ExpectIndex(size_t index) { | 109 void ExpectIndex(size_t index) { |
| 110 expected_.AppendPrefix(kIndexedOpcode); | 110 expected_.AppendPrefix(kIndexedOpcode); |
| 111 expected_.AppendUint32(index); | 111 expected_.AppendUint32(index); |
| 112 } | 112 } |
| 113 void ExpectIndexedLiteral(HpackEntry* key_entry, StringPiece value) { | 113 void ExpectIndexedLiteral(HpackEntry* key_entry, StringPiece value) { |
| 114 expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); | 114 expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); |
| 115 expected_.AppendUint32(key_entry->Index()); | 115 expected_.AppendUint32(IndexOf(key_entry)); |
| 116 expected_.AppendPrefix(kStringLiteralIdentityEncoded); | 116 expected_.AppendPrefix(kStringLiteralIdentityEncoded); |
| 117 expected_.AppendUint32(value.size()); | 117 expected_.AppendUint32(value.size()); |
| 118 expected_.AppendBytes(value); | 118 expected_.AppendBytes(value); |
| 119 } | 119 } |
| 120 void ExpectIndexedLiteral(StringPiece name, StringPiece value) { | 120 void ExpectIndexedLiteral(StringPiece name, StringPiece value) { |
| 121 expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); | 121 expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); |
| 122 expected_.AppendUint32(0); | 122 expected_.AppendUint32(0); |
| 123 expected_.AppendPrefix(kStringLiteralIdentityEncoded); | 123 expected_.AppendPrefix(kStringLiteralIdentityEncoded); |
| 124 expected_.AppendUint32(name.size()); | 124 expected_.AppendUint32(name.size()); |
| 125 expected_.AppendBytes(name); | 125 expected_.AppendBytes(name); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 136 expected_.AppendPrefix(kStringLiteralIdentityEncoded); | 136 expected_.AppendPrefix(kStringLiteralIdentityEncoded); |
| 137 expected_.AppendUint32(value.size()); | 137 expected_.AppendUint32(value.size()); |
| 138 expected_.AppendBytes(value); | 138 expected_.AppendBytes(value); |
| 139 } | 139 } |
| 140 void CompareWithExpectedEncoding(const map<string, string>& header_set) { | 140 void CompareWithExpectedEncoding(const map<string, string>& header_set) { |
| 141 string expected_out, actual_out; | 141 string expected_out, actual_out; |
| 142 expected_.TakeString(&expected_out); | 142 expected_.TakeString(&expected_out); |
| 143 EXPECT_TRUE(encoder_.EncodeHeaderSet(header_set, &actual_out)); | 143 EXPECT_TRUE(encoder_.EncodeHeaderSet(header_set, &actual_out)); |
| 144 EXPECT_EQ(expected_out, actual_out); | 144 EXPECT_EQ(expected_out, actual_out); |
| 145 } | 145 } |
| 146 size_t IndexOf(HpackEntry* entry) { |
| 147 return peer_.table()->IndexOf(entry); |
| 148 } |
| 146 | 149 |
| 147 HpackEncoder encoder_; | 150 HpackEncoder encoder_; |
| 148 test::HpackEncoderPeer peer_; | 151 test::HpackEncoderPeer peer_; |
| 149 | 152 |
| 150 HpackEntry* static_; | 153 HpackEntry* static_; |
| 151 HpackEntry* key_1_; | 154 HpackEntry* key_1_; |
| 152 HpackEntry* key_2_; | 155 HpackEntry* key_2_; |
| 153 HpackEntry* cookie_a_; | 156 HpackEntry* cookie_a_; |
| 154 HpackEntry* cookie_c_; | 157 HpackEntry* cookie_c_; |
| 155 | 158 |
| 156 HpackOutputStream expected_; | 159 HpackOutputStream expected_; |
| 157 }; | 160 }; |
| 158 | 161 |
| 159 TEST_F(HpackEncoderTest, SingleDynamicIndex) { | 162 TEST_F(HpackEncoderTest, SingleDynamicIndex) { |
| 160 ExpectIndex(key_2_->Index()); | 163 ExpectIndex(IndexOf(key_2_)); |
| 161 | 164 |
| 162 map<string, string> headers; | 165 map<string, string> headers; |
| 163 headers[key_2_->name()] = key_2_->value(); | 166 headers[key_2_->name()] = key_2_->value(); |
| 164 CompareWithExpectedEncoding(headers); | 167 CompareWithExpectedEncoding(headers); |
| 165 | 168 |
| 166 // |key_2_| was added to the reference set. | 169 // |key_2_| was added to the reference set. |
| 167 EXPECT_THAT(peer_.table()->reference_set(), ElementsAre(key_2_)); | 170 EXPECT_THAT(peer_.table()->reference_set(), ElementsAre(key_2_)); |
| 168 } | 171 } |
| 169 | 172 |
| 170 TEST_F(HpackEncoderTest, SingleStaticIndex) { | 173 TEST_F(HpackEncoderTest, SingleStaticIndex) { |
| 171 ExpectIndex(static_->Index()); | 174 ExpectIndex(IndexOf(static_)); |
| 172 | 175 |
| 173 map<string, string> headers; | 176 map<string, string> headers; |
| 174 headers[static_->name()] = static_->value(); | 177 headers[static_->name()] = static_->value(); |
| 175 CompareWithExpectedEncoding(headers); | 178 CompareWithExpectedEncoding(headers); |
| 176 | 179 |
| 177 // A new entry copying |static_| was inserted and added to the reference set. | 180 // A new entry copying |static_| was inserted and added to the reference set. |
| 178 HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); | 181 HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); |
| 179 EXPECT_NE(static_, new_entry); | 182 EXPECT_NE(static_, new_entry); |
| 180 EXPECT_EQ(static_->name(), new_entry->name()); | 183 EXPECT_EQ(static_->name(), new_entry->name()); |
| 181 EXPECT_EQ(static_->value(), new_entry->value()); | 184 EXPECT_EQ(static_->value(), new_entry->value()); |
| 182 EXPECT_THAT(peer_.table()->reference_set(), ElementsAre(new_entry)); | 185 EXPECT_THAT(peer_.table()->reference_set(), ElementsAre(new_entry)); |
| 183 } | 186 } |
| 184 | 187 |
| 185 TEST_F(HpackEncoderTest, SingleStaticIndexTooLarge) { | 188 TEST_F(HpackEncoderTest, SingleStaticIndexTooLarge) { |
| 186 peer_.table()->SetMaxSize(1); // Also evicts all fixtures. | 189 peer_.table()->SetMaxSize(1); // Also evicts all fixtures. |
| 187 ExpectIndex(static_->Index()); | 190 ExpectIndex(IndexOf(static_)); |
| 188 | 191 |
| 189 map<string, string> headers; | 192 map<string, string> headers; |
| 190 headers[static_->name()] = static_->value(); | 193 headers[static_->name()] = static_->value(); |
| 191 CompareWithExpectedEncoding(headers); | 194 CompareWithExpectedEncoding(headers); |
| 192 | 195 |
| 193 EXPECT_EQ(0u, peer_.table_peer().dynamic_entries()->size()); | 196 EXPECT_EQ(0u, peer_.table_peer().dynamic_entries()->size()); |
| 194 EXPECT_EQ(0u, peer_.table()->reference_set().size()); | 197 EXPECT_EQ(0u, peer_.table()->reference_set().size()); |
| 195 } | 198 } |
| 196 | 199 |
| 197 TEST_F(HpackEncoderTest, SingleLiteralWithIndexName) { | 200 TEST_F(HpackEncoderTest, SingleLiteralWithIndexName) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 map<string, string> headers; | 247 map<string, string> headers; |
| 245 headers[key_2_->name()] = key_2_->value(); | 248 headers[key_2_->name()] = key_2_->value(); |
| 246 CompareWithExpectedEncoding(headers); | 249 CompareWithExpectedEncoding(headers); |
| 247 } | 250 } |
| 248 | 251 |
| 249 TEST_F(HpackEncoderTest, ExplicitToggleOff) { | 252 TEST_F(HpackEncoderTest, ExplicitToggleOff) { |
| 250 peer_.table()->Toggle(key_1_); | 253 peer_.table()->Toggle(key_1_); |
| 251 peer_.table()->Toggle(key_2_); | 254 peer_.table()->Toggle(key_2_); |
| 252 | 255 |
| 253 // |key_1_| is explicitly toggled off. | 256 // |key_1_| is explicitly toggled off. |
| 254 ExpectIndex(key_1_->Index()); | 257 ExpectIndex(IndexOf(key_1_)); |
| 255 | 258 |
| 256 map<string, string> headers; | 259 map<string, string> headers; |
| 257 headers[key_2_->name()] = key_2_->value(); | 260 headers[key_2_->name()] = key_2_->value(); |
| 258 CompareWithExpectedEncoding(headers); | 261 CompareWithExpectedEncoding(headers); |
| 259 } | 262 } |
| 260 | 263 |
| 261 TEST_F(HpackEncoderTest, ImplicitToggleOff) { | 264 TEST_F(HpackEncoderTest, ImplicitToggleOff) { |
| 262 peer_.table()->Toggle(key_1_); | 265 peer_.table()->Toggle(key_1_); |
| 263 peer_.table()->Toggle(key_2_); | 266 peer_.table()->Toggle(key_2_); |
| 264 | 267 |
| 265 // |key_1_| is evicted. No explicit toggle required. | 268 // |key_1_| is evicted. No explicit toggle required. |
| 266 ExpectIndexedLiteral("key3", "value3"); | 269 ExpectIndexedLiteral("key3", "value3"); |
| 267 | 270 |
| 268 map<string, string> headers; | 271 map<string, string> headers; |
| 269 headers[key_2_->name()] = key_2_->value(); | 272 headers[key_2_->name()] = key_2_->value(); |
| 270 headers["key3"] = "value3"; | 273 headers["key3"] = "value3"; |
| 271 CompareWithExpectedEncoding(headers); | 274 CompareWithExpectedEncoding(headers); |
| 272 } | 275 } |
| 273 | 276 |
| 274 TEST_F(HpackEncoderTest, ExplicitDoubleToggle) { | 277 TEST_F(HpackEncoderTest, ExplicitDoubleToggle) { |
| 275 peer_.table()->Toggle(key_1_); | 278 peer_.table()->Toggle(key_1_); |
| 276 | 279 |
| 277 // |key_1_| is double-toggled prior to being evicted. | 280 // |key_1_| is double-toggled prior to being evicted. |
| 278 ExpectIndex(key_1_->Index()); | 281 ExpectIndex(IndexOf(key_1_)); |
| 279 ExpectIndex(key_1_->Index()); | 282 ExpectIndex(IndexOf(key_1_)); |
| 280 ExpectIndexedLiteral("key3", "value3"); | 283 ExpectIndexedLiteral("key3", "value3"); |
| 281 | 284 |
| 282 map<string, string> headers; | 285 map<string, string> headers; |
| 283 headers[key_1_->name()] = key_1_->value(); | 286 headers[key_1_->name()] = key_1_->value(); |
| 284 headers["key3"] = "value3"; | 287 headers["key3"] = "value3"; |
| 285 CompareWithExpectedEncoding(headers); | 288 CompareWithExpectedEncoding(headers); |
| 286 } | 289 } |
| 287 | 290 |
| 288 TEST_F(HpackEncoderTest, EmitThanEvict) { | 291 TEST_F(HpackEncoderTest, EmitThanEvict) { |
| 289 // |key_1_| is toggled and placed into the reference set, | 292 // |key_1_| is toggled and placed into the reference set, |
| 290 // and then immediately evicted by "key3". | 293 // and then immediately evicted by "key3". |
| 291 ExpectIndex(key_1_->Index()); | 294 ExpectIndex(IndexOf(key_1_)); |
| 292 ExpectIndexedLiteral("key3", "value3"); | 295 ExpectIndexedLiteral("key3", "value3"); |
| 293 | 296 |
| 294 map<string, string> headers; | 297 map<string, string> headers; |
| 295 headers[key_1_->name()] = key_1_->value(); | 298 headers[key_1_->name()] = key_1_->value(); |
| 296 headers["key3"] = "value3"; | 299 headers["key3"] = "value3"; |
| 297 CompareWithExpectedEncoding(headers); | 300 CompareWithExpectedEncoding(headers); |
| 298 } | 301 } |
| 299 | 302 |
| 300 TEST_F(HpackEncoderTest, CookieHeaderIsCrumbled) { | 303 TEST_F(HpackEncoderTest, CookieHeaderIsCrumbled) { |
| 301 peer_.table()->Toggle(cookie_a_); | 304 peer_.table()->Toggle(cookie_a_); |
| 302 | 305 |
| 303 // |cookie_a_| is already in the reference set. |cookie_c_| is | 306 // |cookie_a_| is already in the reference set. |cookie_c_| is |
| 304 // toggled, and "e=ff" is emitted with an indexed name. | 307 // toggled, and "e=ff" is emitted with an indexed name. |
| 305 ExpectIndex(cookie_c_->Index()); | 308 ExpectIndex(IndexOf(cookie_c_)); |
| 306 ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "e=ff"); | 309 ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "e=ff"); |
| 307 | 310 |
| 308 map<string, string> headers; | 311 map<string, string> headers; |
| 309 headers["cookie"] = "e=ff; a=bb; c=dd"; | 312 headers["cookie"] = "e=ff; a=bb; c=dd"; |
| 310 CompareWithExpectedEncoding(headers); | 313 CompareWithExpectedEncoding(headers); |
| 311 } | 314 } |
| 312 | 315 |
| 313 TEST_F(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) { | 316 TEST_F(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) { |
| 314 peer_.set_allow_huffman_compression(true); | 317 peer_.set_allow_huffman_compression(true); |
| 315 | 318 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 EXPECT_EQ(expected_out, actual_out); | 353 EXPECT_EQ(expected_out, actual_out); |
| 351 } | 354 } |
| 352 | 355 |
| 353 TEST_F(HpackEncoderTest, MultipleEncodingPasses) { | 356 TEST_F(HpackEncoderTest, MultipleEncodingPasses) { |
| 354 // Pass 1: key_1_ and cookie_a_ are toggled on. | 357 // Pass 1: key_1_ and cookie_a_ are toggled on. |
| 355 { | 358 { |
| 356 map<string, string> headers; | 359 map<string, string> headers; |
| 357 headers["key1"] = "value1"; | 360 headers["key1"] = "value1"; |
| 358 headers["cookie"] = "a=bb"; | 361 headers["cookie"] = "a=bb"; |
| 359 | 362 |
| 360 ExpectIndex(cookie_a_->Index()); | 363 ExpectIndex(IndexOf(cookie_a_)); |
| 361 ExpectIndex(key_1_->Index()); | 364 ExpectIndex(IndexOf(key_1_)); |
| 362 CompareWithExpectedEncoding(headers); | 365 CompareWithExpectedEncoding(headers); |
| 363 } | 366 } |
| 364 // Pass 2: |key_1_| is double-toggled and evicted. | 367 // Pass 2: |key_1_| is double-toggled and evicted. |
| 365 // |key_2_| & |cookie_c_| are toggled on. | 368 // |key_2_| & |cookie_c_| are toggled on. |
| 366 // |cookie_a_| is toggled off. | 369 // |cookie_a_| is toggled off. |
| 367 // A new cookie entry is added. | 370 // A new cookie entry is added. |
| 368 { | 371 { |
| 369 map<string, string> headers; | 372 map<string, string> headers; |
| 370 headers["key1"] = "value1"; | 373 headers["key1"] = "value1"; |
| 371 headers["key2"] = "value2"; | 374 headers["key2"] = "value2"; |
| 372 headers["cookie"] = "c=dd; e=ff"; | 375 headers["cookie"] = "c=dd; e=ff"; |
| 373 | 376 |
| 374 ExpectIndex(cookie_c_->Index()); // Toggle on. | 377 ExpectIndex(IndexOf(cookie_c_)); // Toggle on. |
| 375 ExpectIndex(key_1_->Index()); // Double-toggle before eviction. | 378 ExpectIndex(IndexOf(key_1_)); // Double-toggle before eviction. |
| 376 ExpectIndex(key_1_->Index()); | 379 ExpectIndex(IndexOf(key_1_)); |
| 377 ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "e=ff"); | 380 ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "e=ff"); |
| 378 ExpectIndex(key_2_->Index() + 1); // Toggle on. Add 1 to reflect insertion. | 381 |
| 379 ExpectIndex(cookie_a_->Index() + 1); // Toggle off. | 382 ExpectIndex(IndexOf(key_2_) + 1); // Toggle on. Add 1 to reflect insertion. |
| 383 ExpectIndex(IndexOf(cookie_a_) + 1); // Toggle off. |
| 380 CompareWithExpectedEncoding(headers); | 384 CompareWithExpectedEncoding(headers); |
| 381 } | 385 } |
| 382 // Pass 3: |key_2_| is evicted and implicitly toggled off. | 386 // Pass 3: |key_2_| is evicted and implicitly toggled off. |
| 383 // |cookie_c_| is explicitly toggled off. | 387 // |cookie_c_| is explicitly toggled off. |
| 384 // "key1" is re-inserted. | 388 // "key1" is re-inserted. |
| 385 { | 389 { |
| 386 map<string, string> headers; | 390 map<string, string> headers; |
| 387 headers["key1"] = "value1"; | 391 headers["key1"] = "value1"; |
| 388 headers["key3"] = "value3"; | 392 headers["key3"] = "value3"; |
| 389 headers["cookie"] = "e=ff"; | 393 headers["cookie"] = "e=ff"; |
| 390 | 394 |
| 391 ExpectIndexedLiteral("key1", "value1"); | 395 ExpectIndexedLiteral("key1", "value1"); |
| 392 ExpectIndexedLiteral("key3", "value3"); | 396 ExpectIndexedLiteral("key3", "value3"); |
| 393 ExpectIndex(cookie_c_->Index() + 2); // Toggle off. Add 1 for insertion. | 397 ExpectIndex(IndexOf(cookie_c_) + 2); // Toggle off. Add 1 for insertion. |
| 394 | 398 |
| 395 CompareWithExpectedEncoding(headers); | 399 CompareWithExpectedEncoding(headers); |
| 396 } | 400 } |
| 397 } | 401 } |
| 398 | 402 |
| 399 TEST_F(HpackEncoderTest, CookieToCrumbs) { | 403 TEST_F(HpackEncoderTest, CookieToCrumbs) { |
| 400 test::HpackEncoderPeer peer(NULL); | 404 test::HpackEncoderPeer peer(NULL); |
| 401 std::vector<StringPiece> out; | 405 std::vector<StringPiece> out; |
| 402 | 406 |
| 403 // A space after ';' is consumed. All other spaces remain. ';' at beginning | 407 // A space after ';' is consumed. All other spaces remain. ';' at beginning |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 expect[static_cast<uint8>('\xff')] = 1; | 444 expect[static_cast<uint8>('\xff')] = 1; |
| 441 expect[static_cast<uint8>('b')] = 1; | 445 expect[static_cast<uint8>('b')] = 1; |
| 442 | 446 |
| 443 EXPECT_EQ(expect, counts); | 447 EXPECT_EQ(expect, counts); |
| 444 EXPECT_EQ(9u, total_counts); | 448 EXPECT_EQ(9u, total_counts); |
| 445 } | 449 } |
| 446 | 450 |
| 447 } // namespace | 451 } // namespace |
| 448 | 452 |
| 449 } // namespace net | 453 } // namespace net |
| OLD | NEW |