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) |
| 174 ->UpdateBytesForStream(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, |
| 452 stream2->id(), 6000))), |
| 453 Invoke(&stream2_blocker, |
| 454 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 455 EXPECT_CALL(*stream2, OnCanWrite()) |
| 456 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 457 &session_, &TestSession::SendLargeFakeData, |
| 458 stream2->id(), 6000))), |
| 459 Invoke(&stream2_blocker, |
| 460 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 461 session_.OnCanWrite(); |
| 462 |
| 463 // We should get one more call for stream2, at which point it has used its |
| 464 // write quota and we move over to stream 4. |
| 465 EXPECT_CALL(*stream2, OnCanWrite()) |
| 466 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 467 &session_, &TestSession::SendLargeFakeData, |
| 468 stream2->id(), 6000))), |
| 469 Invoke(&stream2_blocker, |
| 470 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 471 EXPECT_CALL(*stream4, OnCanWrite()) |
| 472 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 473 &session_, &TestSession::SendLargeFakeData, |
| 474 stream4->id(), 6000))), |
| 475 Invoke(&stream4_blocker, |
| 476 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 477 session_.OnCanWrite(); |
| 478 |
| 479 // Now let stream 4 do the 2nd of its 3 writes, but add a block for a high |
| 480 // priority stream 6. 4 should be preempted. 6 will write but *not* block so |
| 481 // will cede back to 4. |
| 482 stream6->set_priority(kHighestPriority); |
| 483 EXPECT_CALL(*stream4, OnCanWrite()) |
| 484 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 485 &session_, &TestSession::SendLargeFakeData, |
| 486 stream4->id(), 6000))), |
| 487 Invoke(&stream4_blocker, |
| 488 &StreamBlocker::MarkConnectionLevelWriteBlocked), |
| 489 Invoke(&stream6_blocker, |
| 490 &StreamBlocker::MarkHighPriorityWriteBlocked))); |
| 491 EXPECT_CALL(*stream6, OnCanWrite()) |
| 492 .WillOnce(testing::IgnoreResult(Invoke(CreateFunctor( |
| 493 &session_, &TestSession::SendLargeFakeData, stream4->id(), 6000)))); |
| 494 session_.OnCanWrite(); |
| 495 |
| 496 // Stream4 alread did 6k worth of writes, so after doing another 12k it should |
| 497 // cede and 2 should resume. |
| 498 EXPECT_CALL(*stream4, OnCanWrite()) |
| 499 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 500 &session_, &TestSession::SendLargeFakeData, |
| 501 stream4->id(), 12000))), |
| 502 Invoke(&stream4_blocker, |
| 503 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 504 EXPECT_CALL(*stream2, OnCanWrite()) |
| 505 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( |
| 506 &session_, &TestSession::SendLargeFakeData, |
| 507 stream2->id(), 6000))), |
| 508 Invoke(&stream2_blocker, |
| 509 &StreamBlocker::MarkConnectionLevelWriteBlocked))); |
| 510 session_.OnCanWrite(); |
| 511 } |
| 512 |
403 TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { | 513 TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { |
404 // Drive congestion control manually. | 514 // Drive congestion control manually. |
405 MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; | 515 MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; |
406 QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); | 516 QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); |
407 | 517 |
408 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); | 518 TestStream* stream2 = session_.CreateOutgoingDynamicStream(); |
409 TestStream* stream4 = session_.CreateOutgoingDynamicStream(); | 519 TestStream* stream4 = session_.CreateOutgoingDynamicStream(); |
410 TestStream* stream6 = session_.CreateOutgoingDynamicStream(); | 520 TestStream* stream6 = session_.CreateOutgoingDynamicStream(); |
411 | 521 |
412 session_.MarkConnectionLevelWriteBlocked(stream2->id(), kSomeMiddlePriority); | 522 session_.MarkConnectionLevelWriteBlocked(stream2->id(), kSomeMiddlePriority); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 InSequence s; | 619 InSequence s; |
510 // Force most streams to re-register, which is common scenario when we block | 620 // 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. | 621 // the Crypto stream, and only the crypto stream can "really" write. |
512 | 622 |
513 // Due to prioritization, we *should* be asked to write the crypto stream | 623 // Due to prioritization, we *should* be asked to write the crypto stream |
514 // first. | 624 // first. |
515 // Don't re-register the crypto stream (which signals complete writing). | 625 // Don't re-register the crypto stream (which signals complete writing). |
516 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | 626 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); |
517 EXPECT_CALL(*crypto_stream, OnCanWrite()); | 627 EXPECT_CALL(*crypto_stream, OnCanWrite()); |
518 | 628 |
519 // Re-register all other streams, to show they weren't able to proceed. | 629 EXPECT_CALL(*stream2, OnCanWrite()); |
520 EXPECT_CALL(*stream2, OnCanWrite()) | 630 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()) | 631 EXPECT_CALL(*stream4, OnCanWrite()) |
527 .WillOnce(Invoke(&stream4_blocker, | 632 .WillOnce(Invoke(&stream4_blocker, |
528 &StreamBlocker::MarkConnectionLevelWriteBlocked)); | 633 &StreamBlocker::MarkConnectionLevelWriteBlocked)); |
529 | 634 |
530 session_.OnCanWrite(); | 635 session_.OnCanWrite(); |
531 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | 636 EXPECT_TRUE(session_.WillingAndAbleToWrite()); |
532 EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. | 637 EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. |
533 } | 638 } |
534 | 639 |
535 TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { | 640 TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
962 | 1067 |
963 // Unblock the headers stream by supplying a WINDOW_UPDATE. | 1068 // Unblock the headers stream by supplying a WINDOW_UPDATE. |
964 QuicWindowUpdateFrame window_update_frame(headers_stream->id(), | 1069 QuicWindowUpdateFrame window_update_frame(headers_stream->id(), |
965 2 * kMinimumFlowControlSendWindow); | 1070 2 * kMinimumFlowControlSendWindow); |
966 session_.OnWindowUpdateFrame(window_update_frame); | 1071 session_.OnWindowUpdateFrame(window_update_frame); |
967 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | 1072 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); |
968 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | 1073 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); |
969 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | 1074 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); |
970 } | 1075 } |
971 | 1076 |
972 TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseConnectionClose) { | |
973 FLAGS_quic_count_unfinished_as_open_streams = false; | |
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) { | 1077 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 | 1078 // 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 | 1079 // with a FIN or RST then we send a connection close or an RST to |
1004 // refuse streams. | 1080 // refuse streams. |
1005 const QuicStreamId kMaxStreams = 5; | 1081 const QuicStreamId kMaxStreams = 5; |
1006 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); | 1082 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); |
1007 const QuicStreamId kFirstStreamId = kClientDataStreamId1; | 1083 const QuicStreamId kFirstStreamId = kClientDataStreamId1; |
1008 const QuicStreamId kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams; | 1084 const QuicStreamId kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams; |
1009 | 1085 |
1010 // Create kMaxStreams data streams, and close them all without receiving a | 1086 // Create kMaxStreams data streams, and close them all without receiving a |
1011 // FIN or a RST_STREAM from the client. | 1087 // FIN or a RST_STREAM from the client. |
(...skipping 19 matching lines...) Expand all Loading... |
1031 | 1107 |
1032 // Called after any new data is received by the session, and triggers the | 1108 // Called after any new data is received by the session, and triggers the |
1033 // call to close the connection. | 1109 // call to close the connection. |
1034 session_.PostProcessAfterData(); | 1110 session_.PostProcessAfterData(); |
1035 } | 1111 } |
1036 | 1112 |
1037 TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { | 1113 TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { |
1038 // Verify that a draining stream (which has received a FIN but not consumed | 1114 // 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 | 1115 // it) does not count against the open quota (because it is closed from the |
1040 // protocol point of view). | 1116 // protocol point of view). |
1041 if (FLAGS_quic_count_unfinished_as_open_streams) { | 1117 if (GetParam() <= QUIC_VERSION_27) { |
1042 if (GetParam() <= QUIC_VERSION_27) { | 1118 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS)) |
1043 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS)) | 1119 .Times(0); |
1044 .Times(0); | |
1045 } else { | |
1046 EXPECT_CALL(*connection_, SendRstStream(_, QUIC_REFUSED_STREAM, _)) | |
1047 .Times(0); | |
1048 } | |
1049 } else { | 1120 } else { |
1050 EXPECT_CALL(*connection_, | 1121 EXPECT_CALL(*connection_, SendRstStream(_, QUIC_REFUSED_STREAM, _)) |
1051 SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS)) | |
1052 .Times(0); | 1122 .Times(0); |
1053 } | 1123 } |
1054 | |
1055 const QuicStreamId kMaxStreams = 5; | 1124 const QuicStreamId kMaxStreams = 5; |
1056 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); | 1125 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); |
1057 | 1126 |
1058 // Create kMaxStreams + 1 data streams, and mark them draining. | 1127 // Create kMaxStreams + 1 data streams, and mark them draining. |
1059 const QuicStreamId kFirstStreamId = kClientDataStreamId1; | 1128 const QuicStreamId kFirstStreamId = kClientDataStreamId1; |
1060 const QuicStreamId kFinalStreamId = | 1129 const QuicStreamId kFinalStreamId = |
1061 kClientDataStreamId1 + 2 * kMaxStreams + 1; | 1130 kClientDataStreamId1 + 2 * kMaxStreams + 1; |
1062 for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { | 1131 for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { |
1063 QuicStreamFrame data1(i, true, 0, StringPiece("HT")); | 1132 QuicStreamFrame data1(i, true, 0, StringPiece("HT")); |
1064 session_.OnStreamFrame(data1); | 1133 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 | 1192 // Verify that there is no entry for the stream in |
1124 // locally_closed_streams_highest_offset_. | 1193 // locally_closed_streams_highest_offset_. |
1125 EXPECT_EQ( | 1194 EXPECT_EQ( |
1126 FLAGS_quic_fix_fin_accounting ? 0u : 1u, | 1195 FLAGS_quic_fix_fin_accounting ? 0u : 1u, |
1127 QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size()); | 1196 QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size()); |
1128 } | 1197 } |
1129 | 1198 |
1130 } // namespace | 1199 } // namespace |
1131 } // namespace test | 1200 } // namespace test |
1132 } // namespace net | 1201 } // namespace net |
OLD | NEW |