OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/quic/quic_session.h" | |
6 | |
7 #include <set> | |
8 #include <utility> | |
9 | |
10 #include "base/rand_util.h" | |
11 #include "base/stl_util.h" | |
12 #include "base/strings/string_number_conversions.h" | |
13 #include "build/build_config.h" | |
14 #include "net/quic/crypto/crypto_protocol.h" | |
15 #include "net/quic/quic_crypto_stream.h" | |
16 #include "net/quic/quic_flags.h" | |
17 #include "net/quic/quic_protocol.h" | |
18 #include "net/quic/quic_utils.h" | |
19 #include "net/quic/reliable_quic_stream.h" | |
20 #include "net/quic/test_tools/quic_config_peer.h" | |
21 #include "net/quic/test_tools/quic_connection_peer.h" | |
22 #include "net/quic/test_tools/quic_flow_controller_peer.h" | |
23 #include "net/quic/test_tools/quic_headers_stream_peer.h" | |
24 #include "net/quic/test_tools/quic_session_peer.h" | |
25 #include "net/quic/test_tools/quic_spdy_session_peer.h" | |
26 #include "net/quic/test_tools/quic_spdy_stream_peer.h" | |
27 #include "net/quic/test_tools/quic_test_utils.h" | |
28 #include "net/quic/test_tools/reliable_quic_stream_peer.h" | |
29 #include "net/spdy/spdy_framer.h" | |
30 #include "net/test/gtest_util.h" | |
31 #include "testing/gmock/include/gmock/gmock.h" | |
32 #include "testing/gmock_mutant.h" | |
33 #include "testing/gtest/include/gtest/gtest.h" | |
34 | |
35 using net::SpdyHeaderBlock; | |
36 using net::SpdyPriority; | |
37 using std::set; | |
38 using std::string; | |
39 using std::vector; | |
40 using testing::CreateFunctor; | |
41 using testing::AtLeast; | |
42 using testing::InSequence; | |
43 using testing::Invoke; | |
44 using testing::Return; | |
45 using testing::StrictMock; | |
46 using testing::_; | |
47 | |
48 namespace net { | |
49 namespace test { | |
50 namespace { | |
51 | |
52 const SpdyPriority kHighestPriority = kV3HighestPriority; | |
53 | |
54 class TestCryptoStream : public QuicCryptoStream { | |
55 public: | |
56 explicit TestCryptoStream(QuicSession* session) : QuicCryptoStream(session) {} | |
57 | |
58 void OnHandshakeMessage(const CryptoHandshakeMessage& /*message*/) override { | |
59 encryption_established_ = true; | |
60 handshake_confirmed_ = true; | |
61 CryptoHandshakeMessage msg; | |
62 string error_details; | |
63 session()->config()->SetInitialStreamFlowControlWindowToSend( | |
64 kInitialStreamFlowControlWindowForTest); | |
65 session()->config()->SetInitialSessionFlowControlWindowToSend( | |
66 kInitialSessionFlowControlWindowForTest); | |
67 session()->config()->ToHandshakeMessage(&msg); | |
68 const QuicErrorCode error = | |
69 session()->config()->ProcessPeerHello(msg, CLIENT, &error_details); | |
70 EXPECT_EQ(QUIC_NO_ERROR, error); | |
71 session()->OnConfigNegotiated(); | |
72 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); | |
73 } | |
74 | |
75 MOCK_METHOD0(OnCanWrite, void()); | |
76 }; | |
77 | |
78 class TestHeadersStream : public QuicHeadersStream { | |
79 public: | |
80 explicit TestHeadersStream(QuicSpdySession* session) | |
81 : QuicHeadersStream(session) {} | |
82 | |
83 MOCK_METHOD0(OnCanWrite, void()); | |
84 }; | |
85 | |
86 class TestStream : public QuicSpdyStream { | |
87 public: | |
88 TestStream(QuicStreamId id, QuicSpdySession* session) | |
89 : QuicSpdyStream(id, session) {} | |
90 | |
91 using ReliableQuicStream::CloseWriteSide; | |
92 | |
93 void OnDataAvailable() override {} | |
94 | |
95 MOCK_METHOD0(OnCanWrite, void()); | |
96 }; | |
97 | |
98 // Poor man's functor for use as callback in a mock. | |
99 class StreamBlocker { | |
100 public: | |
101 StreamBlocker(QuicSession* session, QuicStreamId stream_id) | |
102 : session_(session), stream_id_(stream_id) {} | |
103 | |
104 void MarkConnectionLevelWriteBlocked() { | |
105 session_->MarkConnectionLevelWriteBlocked(stream_id_); | |
106 } | |
107 | |
108 private: | |
109 QuicSession* const session_; | |
110 const QuicStreamId stream_id_; | |
111 }; | |
112 | |
113 class TestSession : public QuicSpdySession { | |
114 public: | |
115 explicit TestSession(QuicConnection* connection) | |
116 : QuicSpdySession(connection, DefaultQuicConfig()), | |
117 crypto_stream_(this), | |
118 writev_consumes_all_data_(false) { | |
119 Initialize(); | |
120 } | |
121 | |
122 TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; } | |
123 | |
124 TestStream* CreateOutgoingDynamicStream(SpdyPriority priority) override { | |
125 TestStream* stream = new TestStream(GetNextOutgoingStreamId(), this); | |
126 stream->SetPriority(priority); | |
127 ActivateStream(stream); | |
128 return stream; | |
129 } | |
130 | |
131 TestStream* CreateIncomingDynamicStream(QuicStreamId id) override { | |
132 // Enforce the limit on the number of open streams. | |
133 if (GetNumOpenIncomingStreams() + 1 > max_open_incoming_streams()) { | |
134 connection()->CloseConnection( | |
135 QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!", | |
136 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
137 return nullptr; | |
138 } else { | |
139 TestStream* stream = new TestStream(id, this); | |
140 ActivateStream(stream); | |
141 return stream; | |
142 } | |
143 } | |
144 | |
145 bool ShouldCreateIncomingDynamicStream(QuicStreamId /*id*/) override { | |
146 return true; | |
147 } | |
148 | |
149 bool ShouldCreateOutgoingDynamicStream() override { return true; } | |
150 | |
151 bool IsClosedStream(QuicStreamId id) { | |
152 return QuicSession::IsClosedStream(id); | |
153 } | |
154 | |
155 ReliableQuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id) { | |
156 return QuicSpdySession::GetOrCreateDynamicStream(stream_id); | |
157 } | |
158 | |
159 QuicConsumedData WritevData( | |
160 ReliableQuicStream* stream, | |
161 QuicStreamId id, | |
162 QuicIOVector data, | |
163 QuicStreamOffset offset, | |
164 bool fin, | |
165 QuicAckListenerInterface* ack_notifier_delegate) override { | |
166 QuicConsumedData consumed(data.total_length, fin); | |
167 if (!writev_consumes_all_data_) { | |
168 consumed = QuicSession::WritevData(stream, id, data, offset, fin, | |
169 ack_notifier_delegate); | |
170 } | |
171 QuicSessionPeer::GetWriteBlockedStreams(this)->UpdateBytesForStream( | |
172 id, consumed.bytes_consumed); | |
173 return consumed; | |
174 } | |
175 | |
176 void set_writev_consumes_all_data(bool val) { | |
177 writev_consumes_all_data_ = val; | |
178 } | |
179 | |
180 QuicConsumedData SendStreamData(ReliableQuicStream* stream) { | |
181 struct iovec iov; | |
182 return WritevData(stream, stream->id(), MakeIOVector("not empty", &iov), 0, | |
183 true, nullptr); | |
184 } | |
185 | |
186 QuicConsumedData SendLargeFakeData(ReliableQuicStream* stream, int bytes) { | |
187 DCHECK(writev_consumes_all_data_); | |
188 struct iovec iov; | |
189 iov.iov_base = nullptr; // should not be read. | |
190 iov.iov_len = static_cast<size_t>(bytes); | |
191 return WritevData(stream, stream->id(), QuicIOVector(&iov, 1, bytes), 0, | |
192 true, nullptr); | |
193 } | |
194 | |
195 using QuicSession::PostProcessAfterData; | |
196 | |
197 private: | |
198 StrictMock<TestCryptoStream> crypto_stream_; | |
199 | |
200 bool writev_consumes_all_data_; | |
201 }; | |
202 | |
203 class QuicSessionTestBase : public ::testing::TestWithParam<QuicVersion> { | |
204 protected: | |
205 explicit QuicSessionTestBase(Perspective perspective) | |
206 : connection_( | |
207 new StrictMock<MockQuicConnection>(&helper_, | |
208 &alarm_factory_, | |
209 perspective, | |
210 SupportedVersions(GetParam()))), | |
211 session_(connection_) { | |
212 FLAGS_quic_always_log_bugs_for_tests = true; | |
213 session_.config()->SetInitialStreamFlowControlWindowToSend( | |
214 kInitialStreamFlowControlWindowForTest); | |
215 session_.config()->SetInitialSessionFlowControlWindowToSend( | |
216 kInitialSessionFlowControlWindowForTest); | |
217 headers_[":host"] = "www.google.com"; | |
218 headers_[":path"] = "/index.hml"; | |
219 headers_[":scheme"] = "http"; | |
220 headers_["cookie"] = | |
221 "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; " | |
222 "__utmc=160408618; " | |
223 "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX" | |
224 "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX" | |
225 "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT" | |
226 "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0" | |
227 "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh" | |
228 "1zFMi5vzcns38-8_Sns; " | |
229 "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-" | |
230 "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339" | |
231 "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c" | |
232 "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%" | |
233 "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4" | |
234 "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1" | |
235 "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP" | |
236 "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6" | |
237 "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b" | |
238 "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6" | |
239 "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG" | |
240 "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk" | |
241 "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn" | |
242 "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr" | |
243 "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo "; | |
244 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); | |
245 // TODO(ianswett): Fix QuicSessionTests so they don't attempt to write | |
246 // non-crypto stream data at ENCRYPTION_NONE. | |
247 FLAGS_quic_never_write_unencrypted_data = false; | |
248 } | |
249 | |
250 void CheckClosedStreams() { | |
251 for (QuicStreamId i = kCryptoStreamId; i < 100; i++) { | |
252 if (!ContainsKey(closed_streams_, i)) { | |
253 EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i; | |
254 } else { | |
255 EXPECT_TRUE(session_.IsClosedStream(i)) << " stream id: " << i; | |
256 } | |
257 } | |
258 } | |
259 | |
260 void CloseStream(QuicStreamId id) { | |
261 EXPECT_CALL(*connection_, SendRstStream(id, _, _)); | |
262 session_.CloseStream(id); | |
263 closed_streams_.insert(id); | |
264 } | |
265 | |
266 QuicVersion version() const { return connection_->version(); } | |
267 | |
268 MockQuicConnectionHelper helper_; | |
269 MockAlarmFactory alarm_factory_; | |
270 StrictMock<MockQuicConnection>* connection_; | |
271 TestSession session_; | |
272 set<QuicStreamId> closed_streams_; | |
273 SpdyHeaderBlock headers_; | |
274 }; | |
275 | |
276 class QuicSessionTestServer : public QuicSessionTestBase { | |
277 protected: | |
278 QuicSessionTestServer() : QuicSessionTestBase(Perspective::IS_SERVER) {} | |
279 }; | |
280 | |
281 INSTANTIATE_TEST_CASE_P(Tests, | |
282 QuicSessionTestServer, | |
283 ::testing::ValuesIn(QuicSupportedVersions())); | |
284 | |
285 TEST_P(QuicSessionTestServer, PeerAddress) { | |
286 EXPECT_EQ(IPEndPoint(Loopback4(), kTestPort), session_.peer_address()); | |
287 } | |
288 | |
289 TEST_P(QuicSessionTestServer, IsCryptoHandshakeConfirmed) { | |
290 EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed()); | |
291 CryptoHandshakeMessage message; | |
292 session_.GetCryptoStream()->OnHandshakeMessage(message); | |
293 EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); | |
294 } | |
295 | |
296 TEST_P(QuicSessionTestServer, IsClosedStreamDefault) { | |
297 // Ensure that no streams are initially closed. | |
298 for (QuicStreamId i = kCryptoStreamId; i < 100; i++) { | |
299 EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i; | |
300 } | |
301 } | |
302 | |
303 TEST_P(QuicSessionTestServer, AvailableStreams) { | |
304 ASSERT_TRUE(session_.GetOrCreateDynamicStream(9) != nullptr); | |
305 // Both 5 and 7 should be available. | |
306 EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 5)); | |
307 EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 7)); | |
308 ASSERT_TRUE(session_.GetOrCreateDynamicStream(7) != nullptr); | |
309 ASSERT_TRUE(session_.GetOrCreateDynamicStream(5) != nullptr); | |
310 } | |
311 | |
312 TEST_P(QuicSessionTestServer, IsClosedStreamLocallyCreated) { | |
313 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
314 EXPECT_EQ(2u, stream2->id()); | |
315 TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
316 EXPECT_EQ(4u, stream4->id()); | |
317 | |
318 CheckClosedStreams(); | |
319 CloseStream(4); | |
320 CheckClosedStreams(); | |
321 CloseStream(2); | |
322 CheckClosedStreams(); | |
323 } | |
324 | |
325 TEST_P(QuicSessionTestServer, IsClosedStreamPeerCreated) { | |
326 QuicStreamId stream_id1 = kClientDataStreamId1; | |
327 QuicStreamId stream_id2 = kClientDataStreamId2; | |
328 session_.GetOrCreateDynamicStream(stream_id1); | |
329 session_.GetOrCreateDynamicStream(stream_id2); | |
330 | |
331 CheckClosedStreams(); | |
332 CloseStream(stream_id1); | |
333 CheckClosedStreams(); | |
334 CloseStream(stream_id2); | |
335 // Create a stream, and make another available. | |
336 ReliableQuicStream* stream3 = | |
337 session_.GetOrCreateDynamicStream(stream_id2 + 4); | |
338 CheckClosedStreams(); | |
339 // Close one, but make sure the other is still not closed | |
340 CloseStream(stream3->id()); | |
341 CheckClosedStreams(); | |
342 } | |
343 | |
344 TEST_P(QuicSessionTestServer, MaximumAvailableOpenedStreams) { | |
345 QuicStreamId stream_id = kClientDataStreamId1; | |
346 session_.GetOrCreateDynamicStream(stream_id); | |
347 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); | |
348 EXPECT_NE(nullptr, | |
349 session_.GetOrCreateDynamicStream( | |
350 stream_id + 2 * (session_.max_open_incoming_streams() - 1))); | |
351 } | |
352 | |
353 TEST_P(QuicSessionTestServer, TooManyAvailableStreams) { | |
354 QuicStreamId stream_id1 = kClientDataStreamId1; | |
355 QuicStreamId stream_id2; | |
356 EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id1)); | |
357 // A stream ID which is too large to create. | |
358 stream_id2 = stream_id1 + 2 * session_.MaxAvailableStreams() + 4; | |
359 EXPECT_CALL(*connection_, | |
360 CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _)); | |
361 EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id2)); | |
362 } | |
363 | |
364 TEST_P(QuicSessionTestServer, ManyAvailableStreams) { | |
365 // When max_open_streams_ is 200, should be able to create 200 streams | |
366 // out-of-order, that is, creating the one with the largest stream ID first. | |
367 QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); | |
368 QuicStreamId stream_id = kClientDataStreamId1; | |
369 // Create one stream. | |
370 session_.GetOrCreateDynamicStream(stream_id); | |
371 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); | |
372 // Create the largest stream ID of a threatened total of 200 streams. | |
373 session_.GetOrCreateDynamicStream(stream_id + 2 * (200 - 1)); | |
374 } | |
375 | |
376 TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) { | |
377 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
378 QuicStreamId closed_stream_id = stream2->id(); | |
379 // Close the stream. | |
380 EXPECT_CALL(*connection_, SendRstStream(closed_stream_id, _, _)); | |
381 stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); | |
382 EXPECT_DEBUG_DFATAL( | |
383 session_.MarkConnectionLevelWriteBlocked(closed_stream_id), | |
384 "Marking unknown stream 2 blocked."); | |
385 } | |
386 | |
387 TEST_P(QuicSessionTestServer, OnCanWrite) { | |
388 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
389 TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
390 TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
391 | |
392 session_.MarkConnectionLevelWriteBlocked(stream2->id()); | |
393 session_.MarkConnectionLevelWriteBlocked(stream6->id()); | |
394 session_.MarkConnectionLevelWriteBlocked(stream4->id()); | |
395 | |
396 InSequence s; | |
397 StreamBlocker stream2_blocker(&session_, stream2->id()); | |
398 | |
399 // Reregister, to test the loop limit. | |
400 EXPECT_CALL(*stream2, OnCanWrite()) | |
401 .WillOnce(Invoke(&stream2_blocker, | |
402 &StreamBlocker::MarkConnectionLevelWriteBlocked)); | |
403 // 2 will get called a second time as it didn't finish its block | |
404 EXPECT_CALL(*stream2, OnCanWrite()); | |
405 EXPECT_CALL(*stream6, OnCanWrite()); | |
406 // 4 will not get called, as we exceeded the loop limit. | |
407 session_.OnCanWrite(); | |
408 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | |
409 } | |
410 | |
411 TEST_P(QuicSessionTestServer, TestBatchedWrites) { | |
412 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
413 TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
414 TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
415 | |
416 session_.set_writev_consumes_all_data(true); | |
417 session_.MarkConnectionLevelWriteBlocked(stream2->id()); | |
418 session_.MarkConnectionLevelWriteBlocked(stream4->id()); | |
419 | |
420 StreamBlocker stream2_blocker(&session_, stream2->id()); | |
421 StreamBlocker stream4_blocker(&session_, stream4->id()); | |
422 StreamBlocker stream6_blocker(&session_, stream6->id()); | |
423 // With two sessions blocked, we should get two write calls. They should both | |
424 // go to the first stream as it will only write 6k and mark itself blocked | |
425 // again. | |
426 InSequence s; | |
427 EXPECT_CALL(*stream2, OnCanWrite()) | |
428 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( | |
429 &TestSession::SendLargeFakeData, | |
430 base::Unretained(&session_), stream2, 6000))), | |
431 Invoke(&stream2_blocker, | |
432 &StreamBlocker::MarkConnectionLevelWriteBlocked))); | |
433 EXPECT_CALL(*stream2, OnCanWrite()) | |
434 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( | |
435 &TestSession::SendLargeFakeData, | |
436 base::Unretained(&session_), stream2, 6000))), | |
437 Invoke(&stream2_blocker, | |
438 &StreamBlocker::MarkConnectionLevelWriteBlocked))); | |
439 session_.OnCanWrite(); | |
440 | |
441 // We should get one more call for stream2, at which point it has used its | |
442 // write quota and we move over to stream 4. | |
443 EXPECT_CALL(*stream2, OnCanWrite()) | |
444 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( | |
445 &TestSession::SendLargeFakeData, | |
446 base::Unretained(&session_), stream2, 6000))), | |
447 Invoke(&stream2_blocker, | |
448 &StreamBlocker::MarkConnectionLevelWriteBlocked))); | |
449 EXPECT_CALL(*stream4, OnCanWrite()) | |
450 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( | |
451 &TestSession::SendLargeFakeData, | |
452 base::Unretained(&session_), stream4, 6000))), | |
453 Invoke(&stream4_blocker, | |
454 &StreamBlocker::MarkConnectionLevelWriteBlocked))); | |
455 session_.OnCanWrite(); | |
456 | |
457 // Now let stream 4 do the 2nd of its 3 writes, but add a block for a high | |
458 // priority stream 6. 4 should be preempted. 6 will write but *not* block so | |
459 // will cede back to 4. | |
460 stream6->SetPriority(kHighestPriority); | |
461 EXPECT_CALL(*stream4, OnCanWrite()) | |
462 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( | |
463 &TestSession::SendLargeFakeData, | |
464 base::Unretained(&session_), stream4, 6000))), | |
465 Invoke(&stream4_blocker, | |
466 &StreamBlocker::MarkConnectionLevelWriteBlocked), | |
467 Invoke(&stream6_blocker, | |
468 &StreamBlocker::MarkConnectionLevelWriteBlocked))); | |
469 EXPECT_CALL(*stream6, OnCanWrite()) | |
470 .WillOnce(testing::IgnoreResult( | |
471 Invoke(CreateFunctor(&TestSession::SendLargeFakeData, | |
472 base::Unretained(&session_), stream4, 6000)))); | |
473 session_.OnCanWrite(); | |
474 | |
475 // Stream4 alread did 6k worth of writes, so after doing another 12k it should | |
476 // cede and 2 should resume. | |
477 EXPECT_CALL(*stream4, OnCanWrite()) | |
478 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( | |
479 &TestSession::SendLargeFakeData, | |
480 base::Unretained(&session_), stream4, 12000))), | |
481 Invoke(&stream4_blocker, | |
482 &StreamBlocker::MarkConnectionLevelWriteBlocked))); | |
483 EXPECT_CALL(*stream2, OnCanWrite()) | |
484 .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor( | |
485 &TestSession::SendLargeFakeData, | |
486 base::Unretained(&session_), stream2, 6000))), | |
487 Invoke(&stream2_blocker, | |
488 &StreamBlocker::MarkConnectionLevelWriteBlocked))); | |
489 session_.OnCanWrite(); | |
490 } | |
491 | |
492 TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { | |
493 // Encryption needs to be established before data can be sent. | |
494 CryptoHandshakeMessage msg; | |
495 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
496 | |
497 // Drive congestion control manually. | |
498 MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; | |
499 QuicConnectionPeer::SetSendAlgorithm(session_.connection(), kDefaultPathId, | |
500 send_algorithm); | |
501 | |
502 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
503 TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
504 TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
505 | |
506 session_.MarkConnectionLevelWriteBlocked(stream2->id()); | |
507 session_.MarkConnectionLevelWriteBlocked(stream6->id()); | |
508 session_.MarkConnectionLevelWriteBlocked(stream4->id()); | |
509 | |
510 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)) | |
511 .WillRepeatedly(Return(QuicTime::Delta::Zero())); | |
512 EXPECT_CALL(*send_algorithm, GetCongestionWindow()) | |
513 .WillRepeatedly(Return(kMaxPacketSize * 10)); | |
514 EXPECT_CALL(*stream2, OnCanWrite()) | |
515 .WillOnce(testing::IgnoreResult( | |
516 Invoke(CreateFunctor(&TestSession::SendStreamData, | |
517 base::Unretained(&session_), stream2)))); | |
518 EXPECT_CALL(*stream4, OnCanWrite()) | |
519 .WillOnce(testing::IgnoreResult( | |
520 Invoke(CreateFunctor(&TestSession::SendStreamData, | |
521 base::Unretained(&session_), stream4)))); | |
522 EXPECT_CALL(*stream6, OnCanWrite()) | |
523 .WillOnce(testing::IgnoreResult( | |
524 Invoke(CreateFunctor(&TestSession::SendStreamData, | |
525 base::Unretained(&session_), stream6)))); | |
526 | |
527 // Expect that we only send one packet, the writes from different streams | |
528 // should be bundled together. | |
529 MockPacketWriter* writer = static_cast<MockPacketWriter*>( | |
530 QuicConnectionPeer::GetWriter(session_.connection())); | |
531 EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)) | |
532 .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); | |
533 EXPECT_CALL(*send_algorithm, OnPacketSent(_, _, _, _, _)); | |
534 session_.OnCanWrite(); | |
535 EXPECT_FALSE(session_.WillingAndAbleToWrite()); | |
536 } | |
537 | |
538 TEST_P(QuicSessionTestServer, OnCanWriteCongestionControlBlocks) { | |
539 InSequence s; | |
540 | |
541 // Drive congestion control manually. | |
542 MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; | |
543 QuicConnectionPeer::SetSendAlgorithm(session_.connection(), kDefaultPathId, | |
544 send_algorithm); | |
545 | |
546 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
547 TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
548 TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
549 | |
550 session_.MarkConnectionLevelWriteBlocked(stream2->id()); | |
551 session_.MarkConnectionLevelWriteBlocked(stream6->id()); | |
552 session_.MarkConnectionLevelWriteBlocked(stream4->id()); | |
553 | |
554 StreamBlocker stream2_blocker(&session_, stream2->id()); | |
555 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)) | |
556 .WillOnce(Return(QuicTime::Delta::Zero())); | |
557 EXPECT_CALL(*stream2, OnCanWrite()); | |
558 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)) | |
559 .WillOnce(Return(QuicTime::Delta::Zero())); | |
560 EXPECT_CALL(*stream6, OnCanWrite()); | |
561 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)) | |
562 .WillOnce(Return(QuicTime::Delta::Infinite())); | |
563 // stream4->OnCanWrite is not called. | |
564 | |
565 session_.OnCanWrite(); | |
566 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | |
567 | |
568 // Still congestion-control blocked. | |
569 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)) | |
570 .WillOnce(Return(QuicTime::Delta::Infinite())); | |
571 session_.OnCanWrite(); | |
572 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | |
573 | |
574 // stream4->OnCanWrite is called once the connection stops being | |
575 // congestion-control blocked. | |
576 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)) | |
577 .WillOnce(Return(QuicTime::Delta::Zero())); | |
578 EXPECT_CALL(*stream4, OnCanWrite()); | |
579 session_.OnCanWrite(); | |
580 EXPECT_FALSE(session_.WillingAndAbleToWrite()); | |
581 } | |
582 | |
583 TEST_P(QuicSessionTestServer, BufferedHandshake) { | |
584 EXPECT_FALSE(session_.HasPendingHandshake()); // Default value. | |
585 | |
586 // Test that blocking other streams does not change our status. | |
587 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
588 StreamBlocker stream2_blocker(&session_, stream2->id()); | |
589 stream2_blocker.MarkConnectionLevelWriteBlocked(); | |
590 EXPECT_FALSE(session_.HasPendingHandshake()); | |
591 | |
592 TestStream* stream3 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
593 StreamBlocker stream3_blocker(&session_, stream3->id()); | |
594 stream3_blocker.MarkConnectionLevelWriteBlocked(); | |
595 EXPECT_FALSE(session_.HasPendingHandshake()); | |
596 | |
597 // Blocking (due to buffering of) the Crypto stream is detected. | |
598 session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId); | |
599 EXPECT_TRUE(session_.HasPendingHandshake()); | |
600 | |
601 TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
602 StreamBlocker stream4_blocker(&session_, stream4->id()); | |
603 stream4_blocker.MarkConnectionLevelWriteBlocked(); | |
604 EXPECT_TRUE(session_.HasPendingHandshake()); | |
605 | |
606 InSequence s; | |
607 // Force most streams to re-register, which is common scenario when we block | |
608 // the Crypto stream, and only the crypto stream can "really" write. | |
609 | |
610 // Due to prioritization, we *should* be asked to write the crypto stream | |
611 // first. | |
612 // Don't re-register the crypto stream (which signals complete writing). | |
613 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | |
614 EXPECT_CALL(*crypto_stream, OnCanWrite()); | |
615 | |
616 EXPECT_CALL(*stream2, OnCanWrite()); | |
617 EXPECT_CALL(*stream3, OnCanWrite()); | |
618 EXPECT_CALL(*stream4, OnCanWrite()) | |
619 .WillOnce(Invoke(&stream4_blocker, | |
620 &StreamBlocker::MarkConnectionLevelWriteBlocked)); | |
621 | |
622 session_.OnCanWrite(); | |
623 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | |
624 EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. | |
625 } | |
626 | |
627 TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { | |
628 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
629 TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
630 TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
631 | |
632 session_.MarkConnectionLevelWriteBlocked(stream2->id()); | |
633 session_.MarkConnectionLevelWriteBlocked(stream6->id()); | |
634 session_.MarkConnectionLevelWriteBlocked(stream4->id()); | |
635 CloseStream(stream6->id()); | |
636 | |
637 InSequence s; | |
638 EXPECT_CALL(*stream2, OnCanWrite()); | |
639 EXPECT_CALL(*stream4, OnCanWrite()); | |
640 session_.OnCanWrite(); | |
641 EXPECT_FALSE(session_.WillingAndAbleToWrite()); | |
642 } | |
643 | |
644 TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { | |
645 // Ensure connection level flow control blockage. | |
646 QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0); | |
647 EXPECT_TRUE(session_.flow_controller()->IsBlocked()); | |
648 EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); | |
649 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
650 | |
651 // Mark the crypto and headers streams as write blocked, we expect them to be | |
652 // allowed to write later. | |
653 session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId); | |
654 session_.MarkConnectionLevelWriteBlocked(kHeadersStreamId); | |
655 | |
656 // Create a data stream, and although it is write blocked we never expect it | |
657 // to be allowed to write as we are connection level flow control blocked. | |
658 TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
659 session_.MarkConnectionLevelWriteBlocked(stream->id()); | |
660 EXPECT_CALL(*stream, OnCanWrite()).Times(0); | |
661 | |
662 // The crypto and headers streams should be called even though we are | |
663 // connection flow control blocked. | |
664 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | |
665 EXPECT_CALL(*crypto_stream, OnCanWrite()); | |
666 TestHeadersStream* headers_stream = new TestHeadersStream(&session_); | |
667 QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream); | |
668 EXPECT_CALL(*headers_stream, OnCanWrite()); | |
669 | |
670 session_.OnCanWrite(); | |
671 EXPECT_FALSE(session_.WillingAndAbleToWrite()); | |
672 } | |
673 | |
674 TEST_P(QuicSessionTestServer, SendGoAway) { | |
675 MockPacketWriter* writer = static_cast<MockPacketWriter*>( | |
676 QuicConnectionPeer::GetWriter(session_.connection())); | |
677 EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)) | |
678 .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); | |
679 EXPECT_CALL(*connection_, SendGoAway(_, _, _)) | |
680 .WillOnce(Invoke(connection_, &MockQuicConnection::ReallySendGoAway)); | |
681 session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); | |
682 EXPECT_TRUE(session_.goaway_sent()); | |
683 | |
684 const QuicStreamId kTestStreamId = 5u; | |
685 EXPECT_CALL(*connection_, | |
686 SendRstStream(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY, 0)) | |
687 .Times(0); | |
688 EXPECT_TRUE(session_.GetOrCreateDynamicStream(kTestStreamId)); | |
689 } | |
690 | |
691 TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { | |
692 EXPECT_EQ(kInitialIdleTimeoutSecs + 3, | |
693 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); | |
694 CryptoHandshakeMessage msg; | |
695 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
696 EXPECT_EQ(kMaximumIdleTimeoutSecs + 3, | |
697 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); | |
698 } | |
699 | |
700 TEST_P(QuicSessionTestServer, RstStreamBeforeHeadersDecompressed) { | |
701 // Send two bytes of payload. | |
702 QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); | |
703 session_.OnStreamFrame(data1); | |
704 EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); | |
705 | |
706 EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1, _, _)); | |
707 QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, | |
708 0); | |
709 session_.OnRstStream(rst1); | |
710 EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); | |
711 // Connection should remain alive. | |
712 EXPECT_TRUE(connection_->connected()); | |
713 } | |
714 | |
715 TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedStream) { | |
716 // Test that if a stream is flow control blocked, then on receipt of the SHLO | |
717 // containing a suitable send window offset, the stream becomes unblocked. | |
718 | |
719 // Ensure that Writev consumes all the data it is given (simulate no socket | |
720 // blocking). | |
721 session_.set_writev_consumes_all_data(true); | |
722 | |
723 // Create a stream, and send enough data to make it flow control blocked. | |
724 TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
725 string body(kMinimumFlowControlSendWindow, '.'); | |
726 EXPECT_FALSE(stream2->flow_controller()->IsBlocked()); | |
727 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
728 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
729 EXPECT_CALL(*connection_, SendBlocked(_)).Times(AtLeast(1)); | |
730 EXPECT_CALL(*connection_, SendBlocked(0)); | |
731 stream2->WriteOrBufferBody(body, false, nullptr); | |
732 EXPECT_TRUE(stream2->flow_controller()->IsBlocked()); | |
733 EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); | |
734 EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); | |
735 | |
736 // The handshake message will call OnCanWrite, so the stream can resume | |
737 // writing. | |
738 EXPECT_CALL(*stream2, OnCanWrite()); | |
739 // Now complete the crypto handshake, resulting in an increased flow control | |
740 // send window. | |
741 CryptoHandshakeMessage msg; | |
742 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
743 | |
744 // Stream is now unblocked. | |
745 EXPECT_FALSE(stream2->flow_controller()->IsBlocked()); | |
746 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
747 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
748 } | |
749 | |
750 TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { | |
751 // Test that if the crypto stream is flow control blocked, then if the SHLO | |
752 // contains a larger send window offset, the stream becomes unblocked. | |
753 session_.set_writev_consumes_all_data(true); | |
754 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | |
755 EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); | |
756 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
757 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
758 QuicHeadersStream* headers_stream = | |
759 QuicSpdySessionPeer::GetHeadersStream(&session_); | |
760 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
761 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
762 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
763 // Write until the crypto stream is flow control blocked. | |
764 EXPECT_CALL(*connection_, SendBlocked(kCryptoStreamId)); | |
765 for (QuicStreamId i = 0; | |
766 !crypto_stream->flow_controller()->IsBlocked() && i < 1000u; i++) { | |
767 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
768 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
769 QuicConfig config; | |
770 CryptoHandshakeMessage crypto_message; | |
771 config.ToHandshakeMessage(&crypto_message); | |
772 crypto_stream->SendHandshakeMessage(crypto_message); | |
773 } | |
774 EXPECT_TRUE(crypto_stream->flow_controller()->IsBlocked()); | |
775 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
776 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
777 EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); | |
778 EXPECT_FALSE(session_.HasDataToWrite()); | |
779 EXPECT_TRUE(crypto_stream->HasBufferedData()); | |
780 | |
781 // The handshake message will call OnCanWrite, so the stream can | |
782 // resume writing. | |
783 EXPECT_CALL(*crypto_stream, OnCanWrite()); | |
784 // Now complete the crypto handshake, resulting in an increased flow control | |
785 // send window. | |
786 CryptoHandshakeMessage msg; | |
787 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
788 | |
789 // Stream is now unblocked and will no longer have buffered data. | |
790 EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); | |
791 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
792 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
793 } | |
794 | |
795 #if !defined(OS_IOS) | |
796 // This test is failing flakily for iOS bots. | |
797 // http://crbug.com/425050 | |
798 // NOTE: It's not possible to use the standard MAYBE_ convention to disable | |
799 // this test on iOS because when this test gets instantiated it ends up with | |
800 // various names that are dependent on the parameters passed. | |
801 TEST_P(QuicSessionTestServer, | |
802 HandshakeUnblocksFlowControlBlockedHeadersStream) { | |
803 // Test that if the header stream is flow control blocked, then if the SHLO | |
804 // contains a larger send window offset, the stream becomes unblocked. | |
805 session_.set_writev_consumes_all_data(true); | |
806 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | |
807 EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); | |
808 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
809 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
810 QuicHeadersStream* headers_stream = | |
811 QuicSpdySessionPeer::GetHeadersStream(&session_); | |
812 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
813 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
814 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
815 QuicStreamId stream_id = 5; | |
816 // Write until the header stream is flow control blocked. | |
817 EXPECT_CALL(*connection_, SendBlocked(kHeadersStreamId)); | |
818 SpdyHeaderBlock headers; | |
819 while (!headers_stream->flow_controller()->IsBlocked() && stream_id < 2000) { | |
820 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
821 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
822 headers["header"] = base::Uint64ToString(base::RandUint64()) + | |
823 base::Uint64ToString(base::RandUint64()) + | |
824 base::Uint64ToString(base::RandUint64()); | |
825 headers_stream->WriteHeaders(stream_id, headers.Clone(), true, 0, nullptr); | |
826 stream_id += 2; | |
827 } | |
828 // Write once more to ensure that the headers stream has buffered data. The | |
829 // random headers may have exactly filled the flow control window. | |
830 headers_stream->WriteHeaders(stream_id, std::move(headers), true, 0, nullptr); | |
831 EXPECT_TRUE(headers_stream->HasBufferedData()); | |
832 | |
833 EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked()); | |
834 EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); | |
835 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
836 EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); | |
837 EXPECT_FALSE(session_.HasDataToWrite()); | |
838 | |
839 // Now complete the crypto handshake, resulting in an increased flow control | |
840 // send window. | |
841 CryptoHandshakeMessage msg; | |
842 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
843 | |
844 // Stream is now unblocked and will no longer have buffered data. | |
845 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
846 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
847 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
848 EXPECT_FALSE(headers_stream->HasBufferedData()); | |
849 } | |
850 #endif // !defined(OS_IOS) | |
851 | |
852 TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) { | |
853 // Test that when we receive an out of order stream RST we correctly adjust | |
854 // our connection level flow control receive window. | |
855 // On close, the stream should mark as consumed all bytes between the highest | |
856 // byte consumed so far and the final byte offset from the RST frame. | |
857 TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
858 | |
859 const QuicStreamOffset kByteOffset = | |
860 1 + kInitialSessionFlowControlWindowForTest / 2; | |
861 | |
862 // Expect no stream WINDOW_UPDATE frames, as stream read side closed. | |
863 EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0); | |
864 // We do expect a connection level WINDOW_UPDATE when the stream is reset. | |
865 EXPECT_CALL(*connection_, | |
866 SendWindowUpdate( | |
867 0, kInitialSessionFlowControlWindowForTest + kByteOffset)); | |
868 | |
869 EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); | |
870 QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED, | |
871 kByteOffset); | |
872 session_.OnRstStream(rst_frame); | |
873 session_.PostProcessAfterData(); | |
874 EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); | |
875 } | |
876 | |
877 TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAndLocalReset) { | |
878 // Test the situation where we receive a FIN on a stream, and before we fully | |
879 // consume all the data from the sequencer buffer we locally RST the stream. | |
880 // The bytes between highest consumed byte, and the final byte offset that we | |
881 // determined when the FIN arrived, should be marked as consumed at the | |
882 // connection level flow controller when the stream is reset. | |
883 TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
884 | |
885 const QuicStreamOffset kByteOffset = | |
886 kInitialSessionFlowControlWindowForTest / 2 - 1; | |
887 QuicStreamFrame frame(stream->id(), true, kByteOffset, "."); | |
888 session_.OnStreamFrame(frame); | |
889 session_.PostProcessAfterData(); | |
890 EXPECT_TRUE(connection_->connected()); | |
891 | |
892 EXPECT_EQ(0u, stream->flow_controller()->bytes_consumed()); | |
893 EXPECT_EQ(kByteOffset + frame.data_length, | |
894 stream->flow_controller()->highest_received_byte_offset()); | |
895 | |
896 // Reset stream locally. | |
897 EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); | |
898 stream->Reset(QUIC_STREAM_CANCELLED); | |
899 EXPECT_EQ(kByteOffset + frame.data_length, | |
900 session_.flow_controller()->bytes_consumed()); | |
901 } | |
902 | |
903 TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAfterRst) { | |
904 // Test that when we RST the stream (and tear down stream state), and then | |
905 // receive a FIN from the peer, we correctly adjust our connection level flow | |
906 // control receive window. | |
907 | |
908 // Connection starts with some non-zero highest received byte offset, | |
909 // due to other active streams. | |
910 const uint64_t kInitialConnectionBytesConsumed = 567; | |
911 const uint64_t kInitialConnectionHighestReceivedOffset = 1234; | |
912 EXPECT_LT(kInitialConnectionBytesConsumed, | |
913 kInitialConnectionHighestReceivedOffset); | |
914 session_.flow_controller()->UpdateHighestReceivedOffset( | |
915 kInitialConnectionHighestReceivedOffset); | |
916 session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed); | |
917 | |
918 // Reset our stream: this results in the stream being closed locally. | |
919 TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
920 EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); | |
921 stream->Reset(QUIC_STREAM_CANCELLED); | |
922 | |
923 // Now receive a response from the peer with a FIN. We should handle this by | |
924 // adjusting the connection level flow control receive window to take into | |
925 // account the total number of bytes sent by the peer. | |
926 const QuicStreamOffset kByteOffset = 5678; | |
927 string body = "hello"; | |
928 QuicStreamFrame frame(stream->id(), true, kByteOffset, StringPiece(body)); | |
929 session_.OnStreamFrame(frame); | |
930 | |
931 QuicStreamOffset total_stream_bytes_sent_by_peer = | |
932 kByteOffset + body.length(); | |
933 EXPECT_EQ(kInitialConnectionBytesConsumed + total_stream_bytes_sent_by_peer, | |
934 session_.flow_controller()->bytes_consumed()); | |
935 EXPECT_EQ( | |
936 kInitialConnectionHighestReceivedOffset + total_stream_bytes_sent_by_peer, | |
937 session_.flow_controller()->highest_received_byte_offset()); | |
938 } | |
939 | |
940 TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstAfterRst) { | |
941 // Test that when we RST the stream (and tear down stream state), and then | |
942 // receive a RST from the peer, we correctly adjust our connection level flow | |
943 // control receive window. | |
944 | |
945 // Connection starts with some non-zero highest received byte offset, | |
946 // due to other active streams. | |
947 const uint64_t kInitialConnectionBytesConsumed = 567; | |
948 const uint64_t kInitialConnectionHighestReceivedOffset = 1234; | |
949 EXPECT_LT(kInitialConnectionBytesConsumed, | |
950 kInitialConnectionHighestReceivedOffset); | |
951 session_.flow_controller()->UpdateHighestReceivedOffset( | |
952 kInitialConnectionHighestReceivedOffset); | |
953 session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed); | |
954 | |
955 // Reset our stream: this results in the stream being closed locally. | |
956 TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
957 EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); | |
958 stream->Reset(QUIC_STREAM_CANCELLED); | |
959 EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream)); | |
960 | |
961 // Now receive a RST from the peer. We should handle this by adjusting the | |
962 // connection level flow control receive window to take into account the total | |
963 // number of bytes sent by the peer. | |
964 const QuicStreamOffset kByteOffset = 5678; | |
965 QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED, | |
966 kByteOffset); | |
967 session_.OnRstStream(rst_frame); | |
968 | |
969 EXPECT_EQ(kInitialConnectionBytesConsumed + kByteOffset, | |
970 session_.flow_controller()->bytes_consumed()); | |
971 EXPECT_EQ(kInitialConnectionHighestReceivedOffset + kByteOffset, | |
972 session_.flow_controller()->highest_received_byte_offset()); | |
973 } | |
974 | |
975 TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) { | |
976 // Test that receipt of an invalid (< default) stream flow control window from | |
977 // the peer results in the connection being torn down. | |
978 const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; | |
979 QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(session_.config(), | |
980 kInvalidWindow); | |
981 | |
982 EXPECT_CALL(*connection_, | |
983 CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); | |
984 session_.OnConfigNegotiated(); | |
985 } | |
986 | |
987 TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) { | |
988 // Test that receipt of an invalid (< default) session flow control window | |
989 // from the peer results in the connection being torn down. | |
990 const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; | |
991 QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(), | |
992 kInvalidWindow); | |
993 | |
994 EXPECT_CALL(*connection_, | |
995 CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); | |
996 session_.OnConfigNegotiated(); | |
997 } | |
998 | |
999 TEST_P(QuicSessionTestServer, FlowControlWithInvalidFinalOffset) { | |
1000 // Test that if we receive a stream RST with a highest byte offset that | |
1001 // violates flow control, that we close the connection. | |
1002 const uint64_t kLargeOffset = kInitialSessionFlowControlWindowForTest + 1; | |
1003 EXPECT_CALL(*connection_, | |
1004 CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)) | |
1005 .Times(2); | |
1006 | |
1007 // Check that stream frame + FIN results in connection close. | |
1008 TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
1009 EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); | |
1010 stream->Reset(QUIC_STREAM_CANCELLED); | |
1011 QuicStreamFrame frame(stream->id(), true, kLargeOffset, StringPiece()); | |
1012 session_.OnStreamFrame(frame); | |
1013 | |
1014 // Check that RST results in connection close. | |
1015 QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED, | |
1016 kLargeOffset); | |
1017 session_.OnRstStream(rst_frame); | |
1018 } | |
1019 | |
1020 TEST_P(QuicSessionTestServer, WindowUpdateUnblocksHeadersStream) { | |
1021 // Test that a flow control blocked headers stream gets unblocked on recipt of | |
1022 // a WINDOW_UPDATE frame. | |
1023 | |
1024 // Set the headers stream to be flow control blocked. | |
1025 QuicHeadersStream* headers_stream = | |
1026 QuicSpdySessionPeer::GetHeadersStream(&session_); | |
1027 QuicFlowControllerPeer::SetSendWindowOffset(headers_stream->flow_controller(), | |
1028 0); | |
1029 EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked()); | |
1030 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
1031 EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); | |
1032 | |
1033 // Unblock the headers stream by supplying a WINDOW_UPDATE. | |
1034 QuicWindowUpdateFrame window_update_frame(headers_stream->id(), | |
1035 2 * kMinimumFlowControlSendWindow); | |
1036 session_.OnWindowUpdateFrame(window_update_frame); | |
1037 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
1038 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
1039 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
1040 } | |
1041 | |
1042 TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) { | |
1043 // If a buggy/malicious peer creates too many streams that are not ended | |
1044 // with a FIN or RST then we send an RST to refuse streams. | |
1045 const QuicStreamId kMaxStreams = 5; | |
1046 QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); | |
1047 const QuicStreamId kFirstStreamId = kClientDataStreamId1; | |
1048 const QuicStreamId kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams; | |
1049 | |
1050 // Create kMaxStreams data streams, and close them all without receiving a | |
1051 // FIN or a RST_STREAM from the client. | |
1052 for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { | |
1053 QuicStreamFrame data1(i, false, 0, StringPiece("HT")); | |
1054 session_.OnStreamFrame(data1); | |
1055 // EXPECT_EQ(1u, session_.GetNumOpenStreams()); | |
1056 EXPECT_CALL(*connection_, SendRstStream(i, _, _)); | |
1057 session_.CloseStream(i); | |
1058 } | |
1059 | |
1060 EXPECT_CALL(*connection_, | |
1061 SendRstStream(kFinalStreamId, QUIC_REFUSED_STREAM, _)) | |
1062 .Times(1); | |
1063 // Create one more data streams to exceed limit of open stream. | |
1064 QuicStreamFrame data1(kFinalStreamId, false, 0, StringPiece("HT")); | |
1065 session_.OnStreamFrame(data1); | |
1066 | |
1067 // Called after any new data is received by the session, and triggers the | |
1068 // call to close the connection. | |
1069 session_.PostProcessAfterData(); | |
1070 } | |
1071 | |
1072 TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { | |
1073 // Verify that a draining stream (which has received a FIN but not consumed | |
1074 // it) does not count against the open quota (because it is closed from the | |
1075 // protocol point of view). | |
1076 EXPECT_CALL(*connection_, SendRstStream(_, QUIC_REFUSED_STREAM, _)).Times(0); | |
1077 const QuicStreamId kMaxStreams = 5; | |
1078 QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); | |
1079 | |
1080 // Create kMaxStreams + 1 data streams, and mark them draining. | |
1081 const QuicStreamId kFirstStreamId = kClientDataStreamId1; | |
1082 const QuicStreamId kFinalStreamId = | |
1083 kClientDataStreamId1 + 2 * kMaxStreams + 1; | |
1084 for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { | |
1085 QuicStreamFrame data1(i, true, 0, StringPiece("HT")); | |
1086 session_.OnStreamFrame(data1); | |
1087 EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); | |
1088 session_.StreamDraining(i); | |
1089 EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); | |
1090 } | |
1091 | |
1092 // Called after any new data is received by the session, and triggers the call | |
1093 // to close the connection. | |
1094 session_.PostProcessAfterData(); | |
1095 } | |
1096 | |
1097 TEST_P(QuicSessionTestServer, TestMaxIncomingAndOutgoingStreamsAllowed) { | |
1098 // Tests that on server side, the value of max_open_incoming/outgoing streams | |
1099 // are setup correctly during negotiation. | |
1100 // The value for outgoing stream is limited to negotiated value and for | |
1101 // incoming stream it is set to be larger than that. | |
1102 session_.OnConfigNegotiated(); | |
1103 // The max number of open outgoing streams is less than that of incoming | |
1104 // streams, and it should be same as negotiated value. | |
1105 EXPECT_LT(session_.max_open_outgoing_streams(), | |
1106 session_.max_open_incoming_streams()); | |
1107 EXPECT_EQ(session_.max_open_outgoing_streams(), | |
1108 kDefaultMaxStreamsPerConnection); | |
1109 EXPECT_GT(session_.max_open_incoming_streams(), | |
1110 kDefaultMaxStreamsPerConnection); | |
1111 } | |
1112 | |
1113 TEST_P(QuicSessionTestServer, EnableFHOLThroughConfigOption) { | |
1114 QuicConfigPeer::SetReceivedForceHolBlocking(session_.config()); | |
1115 session_.OnConfigNegotiated(); | |
1116 if (version() <= QUIC_VERSION_35) { | |
1117 EXPECT_FALSE(session_.force_hol_blocking()); | |
1118 } else { | |
1119 EXPECT_TRUE(session_.force_hol_blocking()); | |
1120 } | |
1121 } | |
1122 | |
1123 class QuicSessionTestClient : public QuicSessionTestBase { | |
1124 protected: | |
1125 QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {} | |
1126 }; | |
1127 | |
1128 INSTANTIATE_TEST_CASE_P(Tests, | |
1129 QuicSessionTestClient, | |
1130 ::testing::ValuesIn(QuicSupportedVersions())); | |
1131 | |
1132 TEST_P(QuicSessionTestClient, AvailableStreamsClient) { | |
1133 ASSERT_TRUE(session_.GetOrCreateDynamicStream(6) != nullptr); | |
1134 // Both 2 and 4 should be available. | |
1135 EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 2)); | |
1136 EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 4)); | |
1137 ASSERT_TRUE(session_.GetOrCreateDynamicStream(2) != nullptr); | |
1138 ASSERT_TRUE(session_.GetOrCreateDynamicStream(4) != nullptr); | |
1139 // And 5 should be not available. | |
1140 EXPECT_FALSE(QuicSessionPeer::IsStreamAvailable(&session_, 5)); | |
1141 } | |
1142 | |
1143 TEST_P(QuicSessionTestClient, RecordFinAfterReadSideClosed) { | |
1144 // Verify that an incoming FIN is recorded in a stream object even if the read | |
1145 // side has been closed. This prevents an entry from being made in | |
1146 // locally_closed_streams_highest_offset_ (which will never be deleted). | |
1147 TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority); | |
1148 QuicStreamId stream_id = stream->id(); | |
1149 | |
1150 // Close the read side manually. | |
1151 ReliableQuicStreamPeer::CloseReadSide(stream); | |
1152 | |
1153 // Receive a stream data frame with FIN. | |
1154 QuicStreamFrame frame(stream_id, true, 0, StringPiece()); | |
1155 session_.OnStreamFrame(frame); | |
1156 EXPECT_TRUE(stream->fin_received()); | |
1157 | |
1158 // Reset stream locally. | |
1159 EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); | |
1160 stream->Reset(QUIC_STREAM_CANCELLED); | |
1161 EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream)); | |
1162 | |
1163 // Allow the session to delete the stream object. | |
1164 session_.PostProcessAfterData(); | |
1165 EXPECT_TRUE(connection_->connected()); | |
1166 EXPECT_TRUE(QuicSessionPeer::IsStreamClosed(&session_, stream_id)); | |
1167 EXPECT_FALSE(QuicSessionPeer::IsStreamCreated(&session_, stream_id)); | |
1168 | |
1169 // The stream is not waiting for the arrival of the peer's final offset as it | |
1170 // was received with the FIN earlier. | |
1171 EXPECT_EQ( | |
1172 0u, | |
1173 QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size()); | |
1174 } | |
1175 | |
1176 TEST_P(QuicSessionTestClient, TestMaxIncomingAndOutgoingStreamsAllowed) { | |
1177 // Tests that on client side, the value of max_open_incoming/outgoing streams | |
1178 // are setup correctly during negotiation. | |
1179 // When flag is true, the value for outgoing stream is limited to negotiated | |
1180 // value and for incoming stream it is set to be larger than that. | |
1181 session_.OnConfigNegotiated(); | |
1182 EXPECT_LT(session_.max_open_outgoing_streams(), | |
1183 session_.max_open_incoming_streams()); | |
1184 EXPECT_EQ(session_.max_open_outgoing_streams(), | |
1185 kDefaultMaxStreamsPerConnection); | |
1186 } | |
1187 | |
1188 TEST_P(QuicSessionTestClient, EnableDHDTThroughConnectionOption) { | |
1189 FLAGS_quic_disable_hpack_dynamic_table = true; | |
1190 | |
1191 QuicTagVector copt; | |
1192 copt.push_back(kDHDT); | |
1193 QuicConfigPeer::SetConnectionOptionsToSend(session_.config(), copt); | |
1194 session_.OnConfigNegotiated(); | |
1195 EXPECT_EQ(QuicHeadersStreamPeer::GetSpdyFramer(session_.headers_stream()) | |
1196 .header_encoder_table_size(), | |
1197 0UL); | |
1198 } | |
1199 | |
1200 TEST_P(QuicSessionTestClient, EnableFHOLThroughConfigOption) { | |
1201 session_.config()->SetForceHolBlocking(); | |
1202 session_.OnConfigNegotiated(); | |
1203 if (version() <= QUIC_VERSION_35) { | |
1204 EXPECT_FALSE(session_.force_hol_blocking()); | |
1205 } else { | |
1206 EXPECT_TRUE(session_.force_hol_blocking()); | |
1207 } | |
1208 } | |
1209 | |
1210 } // namespace | |
1211 } // namespace test | |
1212 } // namespace net | |
OLD | NEW |