| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/quic/reliable_quic_stream.h" | 5 #include "net/quic/reliable_quic_stream.h" |
| 6 | 6 |
| 7 #include "net/quic/quic_connection.h" | 7 #include "net/quic/quic_connection.h" |
| 8 #include "net/quic/quic_spdy_compressor.h" | 8 #include "net/quic/quic_spdy_compressor.h" |
| 9 #include "net/quic/quic_spdy_decompressor.h" | 9 #include "net/quic/quic_spdy_decompressor.h" |
| 10 #include "net/quic/quic_utils.h" | 10 #include "net/quic/quic_utils.h" |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 class TestStream : public ReliableQuicStream { | 37 class TestStream : public ReliableQuicStream { |
| 38 public: | 38 public: |
| 39 TestStream(QuicStreamId id, | 39 TestStream(QuicStreamId id, |
| 40 QuicSession* session, | 40 QuicSession* session, |
| 41 bool should_process_data) | 41 bool should_process_data) |
| 42 : ReliableQuicStream(id, session), | 42 : ReliableQuicStream(id, session), |
| 43 should_process_data_(should_process_data) { | 43 should_process_data_(should_process_data) { |
| 44 } | 44 } |
| 45 | 45 |
| 46 virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE { | 46 virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE { |
| 47 EXPECT_NE(0u, data_len); |
| 47 DVLOG(1) << "ProcessData data_len: " << data_len; | 48 DVLOG(1) << "ProcessData data_len: " << data_len; |
| 48 data_ += string(data, data_len); | 49 data_ += string(data, data_len); |
| 49 return should_process_data_ ? data_len : 0; | 50 return should_process_data_ ? data_len : 0; |
| 50 } | 51 } |
| 51 | 52 |
| 52 using ReliableQuicStream::WriteData; | 53 using ReliableQuicStream::WriteData; |
| 53 using ReliableQuicStream::CloseReadSide; | 54 using ReliableQuicStream::CloseReadSide; |
| 54 using ReliableQuicStream::CloseWriteSide; | 55 using ReliableQuicStream::CloseWriteSide; |
| 55 | 56 |
| 56 const string& data() const { return data_; } | 57 const string& data() const { return data_; } |
| 57 | 58 |
| 58 private: | 59 private: |
| 59 bool should_process_data_; | 60 bool should_process_data_; |
| 60 string data_; | 61 string data_; |
| 61 }; | 62 }; |
| 62 | 63 |
| 63 class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> { | 64 class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> { |
| 64 public: | 65 public: |
| 65 ReliableQuicStreamTest() { | 66 ReliableQuicStreamTest() { |
| 66 headers_[":host"] = "www.google.com"; | 67 headers_[":host"] = "www.google.com"; |
| 67 headers_[":path"] = "/index.hml"; | 68 headers_[":path"] = "/index.hml"; |
| 68 headers_[":scheme"] = "https"; | 69 headers_[":scheme"] = "https"; |
| 70 headers_["cookie"] = |
| 71 "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; " |
| 72 "__utmc=160408618; " |
| 73 "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX" |
| 74 "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX" |
| 75 "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT" |
| 76 "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0" |
| 77 "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh" |
| 78 "1zFMi5vzcns38-8_Sns; " |
| 79 "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-" |
| 80 "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339" |
| 81 "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c" |
| 82 "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%" |
| 83 "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4" |
| 84 "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1" |
| 85 "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP" |
| 86 "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6" |
| 87 "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b" |
| 88 "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6" |
| 89 "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG" |
| 90 "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk" |
| 91 "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn" |
| 92 "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr" |
| 93 "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo "; |
| 69 } | 94 } |
| 70 | 95 |
| 71 void Initialize(bool stream_should_process_data) { | 96 void Initialize(bool stream_should_process_data) { |
| 72 connection_ = new testing::StrictMock<MockConnection>( | 97 connection_ = new testing::StrictMock<MockConnection>( |
| 73 kGuid, IPEndPoint(), kIsServer); | 98 kGuid, IPEndPoint(), kIsServer); |
| 74 session_.reset(new testing::StrictMock<MockSession>( | 99 session_.reset(new testing::StrictMock<MockSession>( |
| 75 connection_, kIsServer)); | 100 connection_, kIsServer)); |
| 76 stream_.reset(new TestStream(kStreamId, session_.get(), | 101 stream_.reset(new TestStream(kStreamId, session_.get(), |
| 77 stream_should_process_data)); | 102 stream_should_process_data)); |
| 78 stream2_.reset(new TestStream(kStreamId + 2, session_.get(), | 103 stream2_.reset(new TestStream(kStreamId + 2, session_.get(), |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 size_t remaining_data = data.length() - offset; | 281 size_t remaining_data = data.length() - offset; |
| 257 StringPiece fragment(data.data() + offset, | 282 StringPiece fragment(data.data() + offset, |
| 258 min(fragment_size, remaining_data)); | 283 min(fragment_size, remaining_data)); |
| 259 QuicStreamFrame frame(kStreamId, false, offset, fragment); | 284 QuicStreamFrame frame(kStreamId, false, offset, fragment); |
| 260 | 285 |
| 261 stream_->OnStreamFrame(frame); | 286 stream_->OnStreamFrame(frame); |
| 262 } | 287 } |
| 263 ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, | 288 ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, |
| 264 stream_->data()) << "fragment_size: " << fragment_size; | 289 stream_->data()) << "fragment_size: " << fragment_size; |
| 265 } | 290 } |
| 291 |
| 292 for (size_t split_point = 1; split_point < data.size() - 1; ++split_point) { |
| 293 Initialize(kShouldProcessData); |
| 294 |
| 295 StringPiece fragment1(data.data(), split_point); |
| 296 QuicStreamFrame frame1(kStreamId, false, 0, fragment1); |
| 297 stream_->OnStreamFrame(frame1); |
| 298 |
| 299 StringPiece fragment2(data.data() + split_point, data.size() - split_point); |
| 300 QuicStreamFrame frame2(kStreamId, false, split_point, fragment2); |
| 301 stream_->OnStreamFrame(frame2); |
| 302 |
| 303 ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, |
| 304 stream_->data()) << "split_point: " << split_point; |
| 305 } |
| 266 } | 306 } |
| 267 | 307 |
| 268 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyReadv) { | 308 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyReadv) { |
| 269 Initialize(!kShouldProcessData); | 309 Initialize(!kShouldProcessData); |
| 270 | 310 |
| 271 string compressed_headers = compressor_->CompressHeaders(headers_); | 311 string compressed_headers = compressor_->CompressHeaders(headers_); |
| 272 string body = "this is the body"; | 312 string body = "this is the body"; |
| 273 string data = compressed_headers + body; | 313 string data = compressed_headers + body; |
| 274 QuicStreamFrame frame(kStreamId, false, 0, data); | 314 QuicStreamFrame frame(kStreamId, false, 0, data); |
| 275 string uncompressed_headers = | 315 string uncompressed_headers = |
| 276 SpdyUtils::SerializeUncompressedHeaders(headers_); | 316 SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 277 string uncompressed_data = uncompressed_headers + body; | 317 string uncompressed_data = uncompressed_headers + body; |
| 278 | 318 |
| 279 stream_->OnStreamFrame(frame); | 319 stream_->OnStreamFrame(frame); |
| 280 EXPECT_EQ(uncompressed_headers, stream_->data()); | 320 EXPECT_EQ(uncompressed_headers, stream_->data()); |
| 281 | 321 |
| 282 char buffer[1024]; | 322 char buffer[2048]; |
| 283 ASSERT_LT(data.length(), arraysize(buffer)); | 323 ASSERT_LT(data.length(), arraysize(buffer)); |
| 284 struct iovec vec; | 324 struct iovec vec; |
| 285 vec.iov_base = buffer; | 325 vec.iov_base = buffer; |
| 286 vec.iov_len = arraysize(buffer); | 326 vec.iov_len = arraysize(buffer); |
| 287 | 327 |
| 288 size_t bytes_read = stream_->Readv(&vec, 1); | 328 size_t bytes_read = stream_->Readv(&vec, 1); |
| 289 EXPECT_EQ(uncompressed_headers.length(), bytes_read); | 329 EXPECT_EQ(uncompressed_headers.length(), bytes_read); |
| 290 EXPECT_EQ(uncompressed_headers, string(buffer, bytes_read)); | 330 EXPECT_EQ(uncompressed_headers, string(buffer, bytes_read)); |
| 291 | 331 |
| 292 bytes_read = stream_->Readv(&vec, 1); | 332 bytes_read = stream_->Readv(&vec, 1); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 vec[1].iov_base = buffer2; | 381 vec[1].iov_base = buffer2; |
| 342 vec[1].iov_len = arraysize(buffer2); | 382 vec[1].iov_len = arraysize(buffer2); |
| 343 for (size_t i = 0; i < uncompressed_data.length(); i += 2) { | 383 for (size_t i = 0; i < uncompressed_data.length(); i += 2) { |
| 344 size_t bytes_read = stream_->Readv(vec, 2); | 384 size_t bytes_read = stream_->Readv(vec, 2); |
| 345 ASSERT_EQ(2u, bytes_read) << i; | 385 ASSERT_EQ(2u, bytes_read) << i; |
| 346 ASSERT_EQ(uncompressed_data.data()[i], buffer1[0]) << i; | 386 ASSERT_EQ(uncompressed_data.data()[i], buffer1[0]) << i; |
| 347 ASSERT_EQ(uncompressed_data.data()[i + 1], buffer2[0]) << i; | 387 ASSERT_EQ(uncompressed_data.data()[i + 1], buffer2[0]) << i; |
| 348 } | 388 } |
| 349 } | 389 } |
| 350 | 390 |
| 391 TEST_F(ReliableQuicStreamTest, ProcessCorruptHeadersEarly) { |
| 392 Initialize(kShouldProcessData); |
| 393 |
| 394 string compressed_headers1 = compressor_->CompressHeaders(headers_); |
| 395 QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1); |
| 396 string decompressed_headers1 = |
| 397 SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 398 |
| 399 headers_["content-type"] = "text/plain"; |
| 400 string compressed_headers2 = compressor_->CompressHeaders(headers_); |
| 401 compressed_headers2[4] ^= 0xA1; // Corrupt the comressed data. |
| 402 QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2); |
| 403 string decompressed_headers2 = |
| 404 SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 405 |
| 406 // Deliver frame2 to stream2 out of order. The decompressor is not |
| 407 // available yet, so no data will be processed. The compressed data |
| 408 // will be buffered until OnDecompressorAvailable() is called |
| 409 // to process it. |
| 410 stream2_->OnStreamFrame(frame2); |
| 411 EXPECT_EQ("", stream2_->data()); |
| 412 |
| 413 // Now deliver frame1 to stream1. The decompressor is available so |
| 414 // the data will be processed, and the decompressor will become |
| 415 // available for stream2. |
| 416 stream_->OnStreamFrame(frame1); |
| 417 EXPECT_EQ(decompressed_headers1, stream_->data()); |
| 418 |
| 419 // Verify that the decompressor is available, and inform stream2 |
| 420 // that it can now decompress the buffered compressed data. Since |
| 421 // the compressed data is corrupt, the stream will shutdown the session. |
| 422 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); |
| 423 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE)); |
| 424 stream2_->OnDecompressorAvailable(); |
| 425 EXPECT_EQ("", stream2_->data()); |
| 426 } |
| 427 |
| 351 TEST_F(ReliableQuicStreamTest, ProcessHeadersEarly) { | 428 TEST_F(ReliableQuicStreamTest, ProcessHeadersEarly) { |
| 352 Initialize(kShouldProcessData); | 429 Initialize(kShouldProcessData); |
| 353 | 430 |
| 354 string compressed_headers1 = compressor_->CompressHeaders(headers_); | 431 string compressed_headers1 = compressor_->CompressHeaders(headers_); |
| 355 QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1); | 432 QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1); |
| 356 string decompressed_headers1 = | 433 string decompressed_headers1 = |
| 357 SpdyUtils::SerializeUncompressedHeaders(headers_); | 434 SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 358 | 435 |
| 359 headers_["content-type"] = "text/plain"; | 436 headers_["content-type"] = "text/plain"; |
| 360 string compressed_headers2 = compressor_->CompressHeaders(headers_); | 437 string compressed_headers2 = compressor_->CompressHeaders(headers_); |
| 361 QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2); | 438 QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2); |
| 362 string decompressed_headers2 = | 439 string decompressed_headers2 = |
| 363 SpdyUtils::SerializeUncompressedHeaders(headers_); | 440 SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 364 | 441 |
| 442 // Deliver frame2 to stream2 out of order. The decompressor is not |
| 443 // available yet, so no data will be processed. The compressed data |
| 444 // will be buffered until OnDecompressorAvailable() is called |
| 445 // to process it. |
| 365 stream2_->OnStreamFrame(frame2); | 446 stream2_->OnStreamFrame(frame2); |
| 366 EXPECT_EQ("", stream_->data()); | 447 EXPECT_EQ("", stream2_->data()); |
| 367 | 448 |
| 449 // Now deliver frame1 to stream1. The decompressor is available so |
| 450 // the data will be processed, and the decompressor will become |
| 451 // available for stream2. |
| 368 stream_->OnStreamFrame(frame1); | 452 stream_->OnStreamFrame(frame1); |
| 369 EXPECT_EQ(decompressed_headers1, stream_->data()); | 453 EXPECT_EQ(decompressed_headers1, stream_->data()); |
| 370 | 454 |
| 455 // Verify that the decompressor is available, and inform stream2 |
| 456 // that it can now decompress the buffered compressed data. |
| 371 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | 457 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); |
| 372 stream2_->OnDecompressorAvailable(); | 458 stream2_->OnDecompressorAvailable(); |
| 373 EXPECT_EQ(decompressed_headers2, stream2_->data()); | 459 EXPECT_EQ(decompressed_headers2, stream2_->data()); |
| 374 } | 460 } |
| 375 | 461 |
| 376 TEST_F(ReliableQuicStreamTest, ProcessHeadersDelay) { | 462 TEST_F(ReliableQuicStreamTest, ProcessHeadersDelay) { |
| 377 Initialize(!kShouldProcessData); | 463 Initialize(!kShouldProcessData); |
| 378 | 464 |
| 379 string compressed_headers = compressor_->CompressHeaders(headers_); | 465 string compressed_headers = compressor_->CompressHeaders(headers_); |
| 380 QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers); | 466 QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers); |
| 381 string decompressed_headers = | 467 string decompressed_headers = |
| 382 SpdyUtils::SerializeUncompressedHeaders(headers_); | 468 SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 383 | 469 |
| 384 // Send the headers to the stream and verify they were decompressed. | 470 // Send the headers to the stream and verify they were decompressed. |
| 385 stream_->OnStreamFrame(frame1); | 471 stream_->OnStreamFrame(frame1); |
| 386 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | 472 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); |
| 387 | 473 |
| 388 // Verify that we are now able to handle the body data, | 474 // Verify that we are now able to handle the body data, |
| 389 // even though the stream has not processed the headers. | 475 // even though the stream has not processed the headers. |
| 390 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID)) | 476 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID)) |
| 391 .Times(0); | 477 .Times(0); |
| 392 QuicStreamFrame frame2(stream_->id(), false, compressed_headers.length(), | 478 QuicStreamFrame frame2(stream_->id(), false, compressed_headers.length(), |
| 393 "body data"); | 479 "body data"); |
| 394 stream_->OnStreamFrame(frame2); | 480 stream_->OnStreamFrame(frame2); |
| 395 } | 481 } |
| 396 | 482 |
| 397 } // namespace | 483 } // namespace |
| 398 } // namespace test | 484 } // namespace test |
| 399 } // namespace net | 485 } // namespace net |
| OLD | NEW |