| 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/quic_session.h" | 5 #include "net/quic/quic_session.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/containers/hash_tables.h" | 10 #include "base/containers/hash_tables.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 #include "net/test/gtest_util.h" | 29 #include "net/test/gtest_util.h" |
| 30 #include "testing/gmock/include/gmock/gmock.h" | 30 #include "testing/gmock/include/gmock/gmock.h" |
| 31 #include "testing/gmock_mutant.h" | 31 #include "testing/gmock_mutant.h" |
| 32 #include "testing/gtest/include/gtest/gtest.h" | 32 #include "testing/gtest/include/gtest/gtest.h" |
| 33 | 33 |
| 34 using base::hash_map; | 34 using base::hash_map; |
| 35 using std::set; | 35 using std::set; |
| 36 using std::string; | 36 using std::string; |
| 37 using std::vector; | 37 using std::vector; |
| 38 using testing::CreateFunctor; | 38 using testing::CreateFunctor; |
| 39 using net::SpdyPriority; |
| 39 using testing::InSequence; | 40 using testing::InSequence; |
| 40 using testing::Invoke; | 41 using testing::Invoke; |
| 41 using testing::Return; | 42 using testing::Return; |
| 42 using testing::StrictMock; | 43 using testing::StrictMock; |
| 43 using testing::_; | 44 using testing::_; |
| 44 | 45 |
| 45 namespace net { | 46 namespace net { |
| 46 namespace test { | 47 namespace test { |
| 47 namespace { | 48 namespace { |
| 48 | 49 |
| 49 const QuicPriority kHighestPriority = 0; | 50 const SpdyPriority kHighestPriority = 0; |
| 50 const QuicPriority kSomeMiddlePriority = 3; | 51 const SpdyPriority kSomeMiddlePriority = 3; |
| 51 | 52 |
| 52 class TestCryptoStream : public QuicCryptoStream { | 53 class TestCryptoStream : public QuicCryptoStream { |
| 53 public: | 54 public: |
| 54 explicit TestCryptoStream(QuicSession* session) | 55 explicit TestCryptoStream(QuicSession* session) |
| 55 : QuicCryptoStream(session) { | 56 : QuicCryptoStream(session) { |
| 56 } | 57 } |
| 57 | 58 |
| 58 void OnHandshakeMessage(const CryptoHandshakeMessage& /*message*/) override { | 59 void OnHandshakeMessage(const CryptoHandshakeMessage& /*message*/) override { |
| 59 encryption_established_ = true; | 60 encryption_established_ = true; |
| 60 handshake_confirmed_ = true; | 61 handshake_confirmed_ = true; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 89 : QuicSpdyStream(id, session) {} | 90 : QuicSpdyStream(id, session) {} |
| 90 | 91 |
| 91 using ReliableQuicStream::CloseWriteSide; | 92 using ReliableQuicStream::CloseWriteSide; |
| 92 | 93 |
| 93 void OnDataAvailable() override {} | 94 void OnDataAvailable() override {} |
| 94 | 95 |
| 95 void SendBody(const string& data, bool fin) { | 96 void SendBody(const string& data, bool fin) { |
| 96 WriteOrBufferData(data, fin, nullptr); | 97 WriteOrBufferData(data, fin, nullptr); |
| 97 } | 98 } |
| 98 | 99 |
| 100 using QuicSpdyStream::set_priority; |
| 101 |
| 99 MOCK_METHOD0(OnCanWrite, void()); | 102 MOCK_METHOD0(OnCanWrite, void()); |
| 100 }; | 103 }; |
| 101 | 104 |
| 102 // Poor man's functor for use as callback in a mock. | 105 // Poor man's functor for use as callback in a mock. |
| 103 class StreamBlocker { | 106 class StreamBlocker { |
| 104 public: | 107 public: |
| 105 StreamBlocker(QuicSession* session, QuicStreamId stream_id) | 108 StreamBlocker(QuicSession* session, QuicStreamId stream_id) |
| 106 : session_(session), | 109 : session_(session), |
| 107 stream_id_(stream_id) { | 110 stream_id_(stream_id) { |
| 108 } | 111 } |
| 109 | 112 |
| 110 void MarkConnectionLevelWriteBlocked() { | 113 void MarkConnectionLevelWriteBlocked() { |
| 111 session_->MarkConnectionLevelWriteBlocked(stream_id_, kSomeMiddlePriority); | 114 session_->MarkConnectionLevelWriteBlocked(stream_id_, kSomeMiddlePriority); |
| 112 } | 115 } |
| 113 | 116 |
| 117 void MarkHighPriorityWriteBlocked() { |
| 118 session_->MarkConnectionLevelWriteBlocked(stream_id_, kHighestPriority); |
| 119 } |
| 120 |
| 114 private: | 121 private: |
| 115 QuicSession* const session_; | 122 QuicSession* const session_; |
| 116 const QuicStreamId stream_id_; | 123 const QuicStreamId stream_id_; |
| 117 }; | 124 }; |
| 118 | 125 |
| 119 class TestSession : public QuicSpdySession { | 126 class TestSession : public QuicSpdySession { |
| 120 public: | 127 public: |
| 121 explicit TestSession(QuicConnection* connection) | 128 explicit TestSession(QuicConnection* connection) |
| 122 : QuicSpdySession(connection, DefaultQuicConfig()), | 129 : QuicSpdySession(connection, DefaultQuicConfig()), |
| 123 crypto_stream_(this), | 130 crypto_stream_(this), |
| (...skipping 27 matching lines...) Expand all Loading... |
| 151 return QuicSpdySession::GetOrCreateDynamicStream(stream_id); | 158 return QuicSpdySession::GetOrCreateDynamicStream(stream_id); |
| 152 } | 159 } |
| 153 | 160 |
| 154 QuicConsumedData WritevData( | 161 QuicConsumedData WritevData( |
| 155 QuicStreamId id, | 162 QuicStreamId id, |
| 156 QuicIOVector data, | 163 QuicIOVector data, |
| 157 QuicStreamOffset offset, | 164 QuicStreamOffset offset, |
| 158 bool fin, | 165 bool fin, |
| 159 FecProtection fec_protection, | 166 FecProtection fec_protection, |
| 160 QuicAckListenerInterface* ack_notifier_delegate) override { | 167 QuicAckListenerInterface* ack_notifier_delegate) override { |
| 161 // Always consumes everything. | 168 QuicConsumedData consumed(data.total_length, fin); |
| 162 if (writev_consumes_all_data_) { | 169 if (!writev_consumes_all_data_) { |
| 163 return QuicConsumedData(data.total_length, fin); | 170 consumed = QuicSession::WritevData(id, data, offset, fin, fec_protection, |
| 164 } else { | 171 ack_notifier_delegate); |
| 165 return QuicSession::WritevData(id, data, offset, fin, fec_protection, | |
| 166 ack_notifier_delegate); | |
| 167 } | 172 } |
| 173 QuicSessionPeer::GetWriteBlockedStreams(this)->UpdateBytesForStream( |
| 174 id, consumed.bytes_consumed); |
| 175 return consumed; |
| 168 } | 176 } |
| 169 | 177 |
| 170 void set_writev_consumes_all_data(bool val) { | 178 void set_writev_consumes_all_data(bool val) { |
| 171 writev_consumes_all_data_ = val; | 179 writev_consumes_all_data_ = val; |
| 172 } | 180 } |
| 173 | 181 |
| 174 QuicConsumedData SendStreamData(QuicStreamId id) { | 182 QuicConsumedData SendStreamData(QuicStreamId id) { |
| 175 struct iovec iov; | 183 struct iovec iov; |
| 176 return WritevData(id, MakeIOVector("not empty", &iov), 0, true, | 184 return WritevData(id, MakeIOVector("not empty", &iov), 0, true, |
| 177 MAY_FEC_PROTECT, nullptr); | 185 MAY_FEC_PROTECT, nullptr); |
| 178 } | 186 } |
| 179 | 187 |
| 188 QuicConsumedData SendLargeFakeData(QuicStreamId id, int bytes) { |
| 189 DCHECK(writev_consumes_all_data_); |
| 190 struct iovec iov; |
| 191 iov.iov_base = nullptr; // should not be read. |
| 192 iov.iov_len = static_cast<size_t>(bytes); |
| 193 return WritevData(id, QuicIOVector(&iov, 1, bytes), 0, true, |
| 194 MAY_FEC_PROTECT, nullptr); |
| 195 } |
| 196 |
| 180 using QuicSession::PostProcessAfterData; | 197 using QuicSession::PostProcessAfterData; |
| 181 | 198 |
| 182 private: | 199 private: |
| 183 StrictMock<TestCryptoStream> crypto_stream_; | 200 StrictMock<TestCryptoStream> crypto_stream_; |
| 184 | 201 |
| 185 bool writev_consumes_all_data_; | 202 bool writev_consumes_all_data_; |
| 186 }; | 203 }; |
| 187 | 204 |
| 188 class QuicSessionTestBase : public ::testing::TestWithParam<QuicVersion> { | 205 class QuicSessionTestBase : public ::testing::TestWithParam<QuicVersion> { |
| 189 protected: | 206 protected: |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 // Close the stream. | 380 // Close the stream. |
| 364 EXPECT_CALL(*connection_, SendRstStream(closed_stream_id, _, _)); | 381 EXPECT_CALL(*connection_, SendRstStream(closed_stream_id, _, _)); |
| 365 stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); | 382 stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); |
| 366 EXPECT_DEBUG_DFATAL(session_.MarkConnectionLevelWriteBlocked( | 383 EXPECT_DEBUG_DFATAL(session_.MarkConnectionLevelWriteBlocked( |
| 367 closed_stream_id, kSomeMiddlePriority), | 384 closed_stream_id, kSomeMiddlePriority), |
| 368 "Marking unknown stream 2 blocked."); | 385 "Marking unknown stream 2 blocked."); |
| 369 } | 386 } |
| 370 | 387 |
| 371 TEST_P(QuicSessionTestServer, | 388 TEST_P(QuicSessionTestServer, |
| 372 DebugDFatalIfMarkWriteBlockedCalledWithWrongPriority) { | 389 DebugDFatalIfMarkWriteBlockedCalledWithWrongPriority) { |
| 373 const QuicPriority kDifferentPriority = 0; | 390 const SpdyPriority kDifferentPriority = 0; |
| 374 | 391 |
| 375 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); | 392 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); |
| 376 EXPECT_NE(kDifferentPriority, stream2->EffectivePriority()); | 393 EXPECT_NE(kDifferentPriority, stream2->Priority()); |
| 377 EXPECT_DEBUG_DFATAL(session_.MarkConnectionLevelWriteBlocked( | 394 EXPECT_DEBUG_DFATAL(session_.MarkConnectionLevelWriteBlocked( |
| 378 stream2->id(), kDifferentPriority), | 395 stream2->id(), kDifferentPriority), |
| 379 "Priorities do not match. Got: 0 Expected: 3"); | 396 "Priorities do not match. Got: 0 Expected: 3"); |
| 380 } | 397 } |
| 381 | 398 |
| 382 TEST_P(QuicSessionTestServer, OnCanWrite) { | 399 TEST_P(QuicSessionTestServer, OnCanWrite) { |
| 383 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); | 400 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); |
| 384 TestStream* stream4 = session_.CreateOutgoingDynamicStream(); | 401 TestStream* stream4 = session_.CreateOutgoingDynamicStream(); |
| 385 TestStream* stream6 = session_.CreateOutgoingDynamicStream(); | 402 TestStream* stream6 = session_.CreateOutgoingDynamicStream(); |
| 386 | 403 |
| 387 session_.MarkConnectionLevelWriteBlocked(stream2->id(), kSomeMiddlePriority); | 404 session_.MarkConnectionLevelWriteBlocked(stream2->id(), kSomeMiddlePriority); |
| 388 session_.MarkConnectionLevelWriteBlocked(stream6->id(), kSomeMiddlePriority); | 405 session_.MarkConnectionLevelWriteBlocked(stream6->id(), kSomeMiddlePriority); |
| 389 session_.MarkConnectionLevelWriteBlocked(stream4->id(), kSomeMiddlePriority); | 406 session_.MarkConnectionLevelWriteBlocked(stream4->id(), kSomeMiddlePriority); |
| 390 | 407 |
| 391 InSequence s; | 408 InSequence s; |
| 392 StreamBlocker stream2_blocker(&session_, stream2->id()); | 409 StreamBlocker stream2_blocker(&session_, stream2->id()); |
| 393 // Reregister, to test the loop limit. | 410 |
| 394 EXPECT_CALL(*stream2, OnCanWrite()) | 411 if (FLAGS_quic_batch_writes) { |
| 395 .WillOnce(Invoke(&stream2_blocker, | 412 // Reregister, to test the loop limit. |
| 396 &StreamBlocker::MarkConnectionLevelWriteBlocked)); | 413 EXPECT_CALL(*stream2, OnCanWrite()) |
| 397 EXPECT_CALL(*stream6, OnCanWrite()); | 414 .WillOnce(Invoke(&stream2_blocker, |
| 398 EXPECT_CALL(*stream4, OnCanWrite()); | 415 &StreamBlocker::MarkConnectionLevelWriteBlocked)); |
| 416 // 2 will get called a second time as it didn't finish its block |
| 417 EXPECT_CALL(*stream2, OnCanWrite()); |
| 418 EXPECT_CALL(*stream6, OnCanWrite()); |
| 419 // 4 will not get called, as we exceeded the loop limit. |
| 420 } else { |
| 421 // Reregister, to test the loop limit. |
| 422 EXPECT_CALL(*stream2, OnCanWrite()) |
| 423 .WillOnce(Invoke(&stream2_blocker, |
| 424 &StreamBlocker::MarkConnectionLevelWriteBlocked)); |
| 425 EXPECT_CALL(*stream6, OnCanWrite()); |
| 426 EXPECT_CALL(*stream4, OnCanWrite()); |
| 427 } |
| 399 session_.OnCanWrite(); | 428 session_.OnCanWrite(); |
| 400 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | 429 EXPECT_TRUE(session_.WillingAndAbleToWrite()); |
| 401 } | 430 } |
| 402 | 431 |
| 432 TEST_P(QuicSessionTestServer, TestBatchedWrites) { |
| 433 FLAGS_quic_batch_writes = true; |
| 434 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); |
| 435 TestStream* stream4 = session_.CreateOutgoingDynamicStream(); |
| 436 TestStream* stream6 = session_.CreateOutgoingDynamicStream(); |
| 437 |
| 438 session_.set_writev_consumes_all_data(true); |
| 439 session_.MarkConnectionLevelWriteBlocked(stream2->id(), kSomeMiddlePriority); |
| 440 session_.MarkConnectionLevelWriteBlocked(stream4->id(), kSomeMiddlePriority); |
| 441 |
| 442 StreamBlocker stream2_blocker(&session_, stream2->id()); |
| 443 StreamBlocker stream4_blocker(&session_, stream4->id()); |
| 444 StreamBlocker stream6_blocker(&session_, stream6->id()); |
| 445 // With two sessions blocked, we should get two write calls. They should both |
| 446 // go to the first stream as it will only write 6k and mark itself blocked |
| 447 // again. |
| 448 InSequence s; |
| 449 EXPECT_CALL(*stream2, OnCanWrite()) |
| 450 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 451 &session_, &TestSession::SendLargeFakeData, stream2->id(), 6000))), |
| 452 Invoke(&stream2_blocker, |
| 453 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 454 EXPECT_CALL(*stream2, OnCanWrite()) |
| 455 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 456 &session_, &TestSession::SendLargeFakeData, stream2->id(), 6000))), |
| 457 Invoke(&stream2_blocker, |
| 458 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 459 session_.OnCanWrite(); |
| 460 |
| 461 // We should get one more call for stream2, at which point it has used its |
| 462 // write quota and we move over to stream 4. |
| 463 EXPECT_CALL(*stream2, OnCanWrite()) |
| 464 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 465 &session_, &TestSession::SendLargeFakeData, stream2->id(), 6000))), |
| 466 Invoke(&stream2_blocker, |
| 467 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 468 EXPECT_CALL(*stream4, OnCanWrite()) |
| 469 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 470 &session_, &TestSession::SendLargeFakeData, stream4->id(), 6000))), |
| 471 Invoke(&stream4_blocker, |
| 472 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 473 session_.OnCanWrite(); |
| 474 |
| 475 // Now let stream 4 do the 2nd of its 3 writes, but add a block for a high |
| 476 // priority stream 6. 4 should be preempted. 6 will write but *not* block so |
| 477 // will cede back to 4. |
| 478 stream6->set_priority(kHighestPriority); |
| 479 EXPECT_CALL(*stream4, OnCanWrite()) |
| 480 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 481 &session_, &TestSession::SendLargeFakeData, stream4->id(), 6000))), |
| 482 Invoke(&stream4_blocker, |
| 483 &StreamBlocker::MarkConnectionLevelWriteBlocked), |
| 484 Invoke(&stream6_blocker, |
| 485 &StreamBlocker::MarkHighPriorityWriteBlocked))); |
| 486 EXPECT_CALL(*stream6, OnCanWrite()) |
| 487 .WillOnce(testing::IgnoreResult(Invoke(CreateFunctor( |
| 488 &session_, &TestSession::SendLargeFakeData, stream4->id(), 6000)))); |
| 489 session_.OnCanWrite(); |
| 490 |
| 491 // Stream4 alread did 6k worth of writes, so after doing another 12k it should |
| 492 // cede and 2 should resume. |
| 493 EXPECT_CALL(*stream4, OnCanWrite()) |
| 494 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 495 &session_, &TestSession::SendLargeFakeData, stream4->id(), 12000))), |
| 496 Invoke(&stream4_blocker, |
| 497 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 498 EXPECT_CALL(*stream2, OnCanWrite()) |
| 499 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 500 &session_, &TestSession::SendLargeFakeData, stream2->id(), 6000))), |
| 501 Invoke(&stream2_blocker, |
| 502 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 503 session_.OnCanWrite(); |
| 504 } |
| 505 |
| 403 TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { | 506 TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { |
| 404 // Drive congestion control manually. | 507 // Drive congestion control manually. |
| 405 MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; | 508 MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; |
| 406 QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); | 509 QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); |
| 407 | 510 |
| 408 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); | 511 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); |
| 409 TestStream* stream4 = session_.CreateOutgoingDynamicStream(); | 512 TestStream* stream4 = session_.CreateOutgoingDynamicStream(); |
| 410 TestStream* stream6 = session_.CreateOutgoingDynamicStream(); | 513 TestStream* stream6 = session_.CreateOutgoingDynamicStream(); |
| 411 | 514 |
| 412 session_.MarkConnectionLevelWriteBlocked(stream2->id(), kSomeMiddlePriority); | 515 session_.MarkConnectionLevelWriteBlocked(stream2->id(), kSomeMiddlePriority); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 InSequence s; | 612 InSequence s; |
| 510 // Force most streams to re-register, which is common scenario when we block | 613 // Force most streams to re-register, which is common scenario when we block |
| 511 // the Crypto stream, and only the crypto stream can "really" write. | 614 // the Crypto stream, and only the crypto stream can "really" write. |
| 512 | 615 |
| 513 // Due to prioritization, we *should* be asked to write the crypto stream | 616 // Due to prioritization, we *should* be asked to write the crypto stream |
| 514 // first. | 617 // first. |
| 515 // Don't re-register the crypto stream (which signals complete writing). | 618 // Don't re-register the crypto stream (which signals complete writing). |
| 516 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | 619 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); |
| 517 EXPECT_CALL(*crypto_stream, OnCanWrite()); | 620 EXPECT_CALL(*crypto_stream, OnCanWrite()); |
| 518 | 621 |
| 519 // Re-register all other streams, to show they weren't able to proceed. | 622 EXPECT_CALL(*stream2, OnCanWrite()); |
| 520 EXPECT_CALL(*stream2, OnCanWrite()) | 623 EXPECT_CALL(*stream3, OnCanWrite()); |
| 521 .WillOnce(Invoke(&stream2_blocker, | |
| 522 &StreamBlocker::MarkConnectionLevelWriteBlocked)); | |
| 523 EXPECT_CALL(*stream3, OnCanWrite()) | |
| 524 .WillOnce(Invoke(&stream3_blocker, | |
| 525 &StreamBlocker::MarkConnectionLevelWriteBlocked)); | |
| 526 EXPECT_CALL(*stream4, OnCanWrite()) | 624 EXPECT_CALL(*stream4, OnCanWrite()) |
| 527 .WillOnce(Invoke(&stream4_blocker, | 625 .WillOnce(Invoke(&stream4_blocker, |
| 528 &StreamBlocker::MarkConnectionLevelWriteBlocked)); | 626 &StreamBlocker::MarkConnectionLevelWriteBlocked)); |
| 529 | 627 |
| 530 session_.OnCanWrite(); | 628 session_.OnCanWrite(); |
| 531 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | 629 EXPECT_TRUE(session_.WillingAndAbleToWrite()); |
| 532 EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. | 630 EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. |
| 533 } | 631 } |
| 534 | 632 |
| 535 TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { | 633 TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 962 | 1060 |
| 963 // Unblock the headers stream by supplying a WINDOW_UPDATE. | 1061 // Unblock the headers stream by supplying a WINDOW_UPDATE. |
| 964 QuicWindowUpdateFrame window_update_frame(headers_stream->id(), | 1062 QuicWindowUpdateFrame window_update_frame(headers_stream->id(), |
| 965 2 * kMinimumFlowControlSendWindow); | 1063 2 * kMinimumFlowControlSendWindow); |
| 966 session_.OnWindowUpdateFrame(window_update_frame); | 1064 session_.OnWindowUpdateFrame(window_update_frame); |
| 967 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | 1065 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); |
| 968 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | 1066 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); |
| 969 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | 1067 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); |
| 970 } | 1068 } |
| 971 | 1069 |
| 972 TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseConnectionClose) { | 1070 TEST_P(QuicSessionTestServer, |
| 973 FLAGS_quic_count_unfinished_as_open_streams = false; | 1071 TooManyUnfinishedStreamsCauseServerRejectStream) { |
| 974 // If a buggy/malicious peer creates too many streams that are not ended | |
| 975 // with a FIN or RST then we send a connection close. | |
| 976 EXPECT_CALL(*connection_, | |
| 977 SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS)); | |
| 978 | |
| 979 const QuicStreamId kMaxStreams = 5; | |
| 980 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); | |
| 981 | |
| 982 // Create kMaxStreams + 1 data streams, and close them all without receiving | |
| 983 // a FIN or a RST_STREAM from the client. | |
| 984 const QuicStreamId kFirstStreamId = kClientDataStreamId1; | |
| 985 const QuicStreamId kFinalStreamId = | |
| 986 kClientDataStreamId1 + 2 * kMaxStreams + 1; | |
| 987 for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { | |
| 988 QuicStreamFrame data1(i, false, 0, StringPiece("HT")); | |
| 989 session_.OnStreamFrame(data1); | |
| 990 EXPECT_EQ(1u, session_.GetNumOpenStreams()); | |
| 991 EXPECT_CALL(*connection_, SendRstStream(i, _, _)); | |
| 992 session_.CloseStream(i); | |
| 993 } | |
| 994 | |
| 995 // Called after any new data is received by the session, and triggers the | |
| 996 // call to close the connection. | |
| 997 session_.PostProcessAfterData(); | |
| 998 } | |
| 999 | |
| 1000 TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) { | |
| 1001 FLAGS_quic_count_unfinished_as_open_streams = true; | |
| 1002 // If a buggy/malicious peer creates too many streams that are not ended | 1072 // If a buggy/malicious peer creates too many streams that are not ended |
| 1003 // with a FIN or RST then we send a connection close or an RST to | 1073 // with a FIN or RST then we send a connection close or an RST to |
| 1004 // refuse streams. | 1074 // refuse streams. |
| 1005 const QuicStreamId kMaxStreams = 5; | 1075 const QuicStreamId kMaxStreams = 5; |
| 1006 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); | 1076 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); |
| 1007 const QuicStreamId kFirstStreamId = kClientDataStreamId1; | 1077 const QuicStreamId kFirstStreamId = kClientDataStreamId1; |
| 1008 const QuicStreamId kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams; | 1078 const QuicStreamId kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams; |
| 1009 | 1079 |
| 1010 // Create kMaxStreams data streams, and close them all without receiving a | 1080 // Create kMaxStreams data streams, and close them all without receiving a |
| 1011 // FIN or a RST_STREAM from the client. | 1081 // FIN or a RST_STREAM from the client. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1031 | 1101 |
| 1032 // Called after any new data is received by the session, and triggers the | 1102 // Called after any new data is received by the session, and triggers the |
| 1033 // call to close the connection. | 1103 // call to close the connection. |
| 1034 session_.PostProcessAfterData(); | 1104 session_.PostProcessAfterData(); |
| 1035 } | 1105 } |
| 1036 | 1106 |
| 1037 TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { | 1107 TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { |
| 1038 // Verify that a draining stream (which has received a FIN but not consumed | 1108 // Verify that a draining stream (which has received a FIN but not consumed |
| 1039 // it) does not count against the open quota (because it is closed from the | 1109 // it) does not count against the open quota (because it is closed from the |
| 1040 // protocol point of view). | 1110 // protocol point of view). |
| 1041 if (FLAGS_quic_count_unfinished_as_open_streams) { | 1111 if (GetParam() <= QUIC_VERSION_27) { |
| 1042 if (GetParam() <= QUIC_VERSION_27) { | 1112 EXPECT_CALL(*connection_, |
| 1043 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS)) | 1113 SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS)).Times(0); |
| 1044 .Times(0); | |
| 1045 } else { | |
| 1046 EXPECT_CALL(*connection_, SendRstStream(_, QUIC_REFUSED_STREAM, _)) | |
| 1047 .Times(0); | |
| 1048 } | |
| 1049 } else { | 1114 } else { |
| 1050 EXPECT_CALL(*connection_, | 1115 EXPECT_CALL(*connection_, |
| 1051 SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS)) | 1116 SendRstStream(_, QUIC_REFUSED_STREAM, _)).Times(0); |
| 1052 .Times(0); | |
| 1053 } | 1117 } |
| 1054 | |
| 1055 const QuicStreamId kMaxStreams = 5; | 1118 const QuicStreamId kMaxStreams = 5; |
| 1056 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); | 1119 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); |
| 1057 | 1120 |
| 1058 // Create kMaxStreams + 1 data streams, and mark them draining. | 1121 // Create kMaxStreams + 1 data streams, and mark them draining. |
| 1059 const QuicStreamId kFirstStreamId = kClientDataStreamId1; | 1122 const QuicStreamId kFirstStreamId = kClientDataStreamId1; |
| 1060 const QuicStreamId kFinalStreamId = | 1123 const QuicStreamId kFinalStreamId = |
| 1061 kClientDataStreamId1 + 2 * kMaxStreams + 1; | 1124 kClientDataStreamId1 + 2 * kMaxStreams + 1; |
| 1062 for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { | 1125 for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { |
| 1063 QuicStreamFrame data1(i, true, 0, StringPiece("HT")); | 1126 QuicStreamFrame data1(i, true, 0, StringPiece("HT")); |
| 1064 session_.OnStreamFrame(data1); | 1127 session_.OnStreamFrame(data1); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1123 // Verify that there is no entry for the stream in | 1186 // Verify that there is no entry for the stream in |
| 1124 // locally_closed_streams_highest_offset_. | 1187 // locally_closed_streams_highest_offset_. |
| 1125 EXPECT_EQ( | 1188 EXPECT_EQ( |
| 1126 FLAGS_quic_fix_fin_accounting ? 0u : 1u, | 1189 FLAGS_quic_fix_fin_accounting ? 0u : 1u, |
| 1127 QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size()); | 1190 QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size()); |
| 1128 } | 1191 } |
| 1129 | 1192 |
| 1130 } // namespace | 1193 } // namespace |
| 1131 } // namespace test | 1194 } // namespace test |
| 1132 } // namespace net | 1195 } // namespace net |
| OLD | NEW |