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 | |
9 #include "base/basictypes.h" | |
10 #include "base/containers/hash_tables.h" | |
11 #include "base/rand_util.h" | |
12 #include "base/stl_util.h" | |
13 #include "base/strings/string_number_conversions.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_data_stream_peer.h" | |
23 #include "net/quic/test_tools/quic_flow_controller_peer.h" | |
24 #include "net/quic/test_tools/quic_session_peer.h" | |
25 #include "net/quic/test_tools/quic_test_utils.h" | |
26 #include "net/quic/test_tools/reliable_quic_stream_peer.h" | |
27 #include "net/spdy/spdy_framer.h" | |
28 #include "net/test/gtest_util.h" | |
29 #include "testing/gmock/include/gmock/gmock.h" | |
30 #include "testing/gmock_mutant.h" | |
31 #include "testing/gtest/include/gtest/gtest.h" | |
32 | |
33 using base::hash_map; | |
34 using std::set; | |
35 using std::string; | |
36 using std::vector; | |
37 using testing::CreateFunctor; | |
38 using testing::InSequence; | |
39 using testing::Invoke; | |
40 using testing::Return; | |
41 using testing::StrictMock; | |
42 using testing::_; | |
43 | |
44 namespace net { | |
45 namespace test { | |
46 namespace { | |
47 | |
48 const QuicPriority kHighestPriority = 0; | |
49 const QuicPriority kSomeMiddlePriority = 3; | |
50 | |
51 class TestCryptoStream : public QuicCryptoStream { | |
52 public: | |
53 explicit TestCryptoStream(QuicSession* session) | |
54 : QuicCryptoStream(session) { | |
55 } | |
56 | |
57 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override { | |
58 encryption_established_ = true; | |
59 handshake_confirmed_ = true; | |
60 CryptoHandshakeMessage msg; | |
61 string error_details; | |
62 session()->config()->SetInitialStreamFlowControlWindowToSend( | |
63 kInitialStreamFlowControlWindowForTest); | |
64 session()->config()->SetInitialSessionFlowControlWindowToSend( | |
65 kInitialSessionFlowControlWindowForTest); | |
66 session()->config()->ToHandshakeMessage(&msg); | |
67 const QuicErrorCode error = session()->config()->ProcessPeerHello( | |
68 msg, CLIENT, &error_details); | |
69 EXPECT_EQ(QUIC_NO_ERROR, error); | |
70 session()->OnConfigNegotiated(); | |
71 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); | |
72 } | |
73 | |
74 MOCK_METHOD0(OnCanWrite, void()); | |
75 }; | |
76 | |
77 class TestHeadersStream : public QuicHeadersStream { | |
78 public: | |
79 explicit TestHeadersStream(QuicSession* session) | |
80 : QuicHeadersStream(session) { | |
81 } | |
82 | |
83 MOCK_METHOD0(OnCanWrite, void()); | |
84 }; | |
85 | |
86 class TestStream : public QuicDataStream { | |
87 public: | |
88 TestStream(QuicStreamId id, QuicSession* session) | |
89 : QuicDataStream(id, session) { | |
90 } | |
91 | |
92 using ReliableQuicStream::CloseWriteSide; | |
93 | |
94 uint32 ProcessData(const char* data, uint32 data_len) override { | |
95 return data_len; | |
96 } | |
97 | |
98 void SendBody(const string& data, bool fin) { | |
99 WriteOrBufferData(data, fin, nullptr); | |
100 } | |
101 | |
102 MOCK_METHOD0(OnCanWrite, void()); | |
103 }; | |
104 | |
105 // Poor man's functor for use as callback in a mock. | |
106 class StreamBlocker { | |
107 public: | |
108 StreamBlocker(QuicSession* session, QuicStreamId stream_id) | |
109 : session_(session), | |
110 stream_id_(stream_id) { | |
111 } | |
112 | |
113 void MarkWriteBlocked() { | |
114 session_->MarkWriteBlocked(stream_id_, kSomeMiddlePriority); | |
115 } | |
116 | |
117 private: | |
118 QuicSession* const session_; | |
119 const QuicStreamId stream_id_; | |
120 }; | |
121 | |
122 class TestSession : public QuicSession { | |
123 public: | |
124 explicit TestSession(QuicConnection* connection) | |
125 : QuicSession(connection, DefaultQuicConfig()), | |
126 crypto_stream_(this), | |
127 writev_consumes_all_data_(false) { | |
128 InitializeSession(); | |
129 } | |
130 | |
131 TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; } | |
132 | |
133 TestStream* CreateOutgoingDataStream() override { | |
134 TestStream* stream = new TestStream(GetNextStreamId(), this); | |
135 ActivateStream(stream); | |
136 return stream; | |
137 } | |
138 | |
139 TestStream* CreateIncomingDataStream(QuicStreamId id) override { | |
140 return new TestStream(id, this); | |
141 } | |
142 | |
143 bool IsClosedStream(QuicStreamId id) { | |
144 return QuicSession::IsClosedStream(id); | |
145 } | |
146 | |
147 QuicDataStream* GetIncomingDataStream(QuicStreamId stream_id) { | |
148 return QuicSession::GetIncomingDataStream(stream_id); | |
149 } | |
150 | |
151 QuicConsumedData WritevData( | |
152 QuicStreamId id, | |
153 const IOVector& data, | |
154 QuicStreamOffset offset, | |
155 bool fin, | |
156 FecProtection fec_protection, | |
157 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) override { | |
158 // Always consumes everything. | |
159 if (writev_consumes_all_data_) { | |
160 return QuicConsumedData(data.TotalBufferSize(), fin); | |
161 } else { | |
162 return QuicSession::WritevData(id, data, offset, fin, fec_protection, | |
163 ack_notifier_delegate); | |
164 } | |
165 } | |
166 | |
167 void set_writev_consumes_all_data(bool val) { | |
168 writev_consumes_all_data_ = val; | |
169 } | |
170 | |
171 QuicConsumedData SendStreamData(QuicStreamId id) { | |
172 return WritevData(id, MakeIOVector("not empty"), 0, true, MAY_FEC_PROTECT, | |
173 nullptr); | |
174 } | |
175 | |
176 using QuicSession::PostProcessAfterData; | |
177 | |
178 private: | |
179 StrictMock<TestCryptoStream> crypto_stream_; | |
180 | |
181 bool writev_consumes_all_data_; | |
182 }; | |
183 | |
184 class QuicSessionTest : public ::testing::TestWithParam<QuicVersion> { | |
185 protected: | |
186 QuicSessionTest() | |
187 : connection_(new MockConnection(true, SupportedVersions(GetParam()))), | |
188 session_(connection_) { | |
189 session_.config()->SetInitialStreamFlowControlWindowToSend( | |
190 kInitialStreamFlowControlWindowForTest); | |
191 session_.config()->SetInitialSessionFlowControlWindowToSend( | |
192 kInitialSessionFlowControlWindowForTest); | |
193 headers_[":host"] = "www.google.com"; | |
194 headers_[":path"] = "/index.hml"; | |
195 headers_[":scheme"] = "http"; | |
196 headers_["cookie"] = | |
197 "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; " | |
198 "__utmc=160408618; " | |
199 "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX" | |
200 "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX" | |
201 "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT" | |
202 "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0" | |
203 "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh" | |
204 "1zFMi5vzcns38-8_Sns; " | |
205 "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-" | |
206 "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339" | |
207 "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c" | |
208 "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%" | |
209 "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4" | |
210 "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1" | |
211 "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP" | |
212 "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6" | |
213 "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b" | |
214 "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6" | |
215 "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG" | |
216 "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk" | |
217 "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn" | |
218 "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr" | |
219 "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo "; | |
220 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); | |
221 } | |
222 | |
223 void CheckClosedStreams() { | |
224 for (int i = kCryptoStreamId; i < 100; i++) { | |
225 if (!ContainsKey(closed_streams_, i)) { | |
226 EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i; | |
227 } else { | |
228 EXPECT_TRUE(session_.IsClosedStream(i)) << " stream id: " << i; | |
229 } | |
230 } | |
231 } | |
232 | |
233 void CloseStream(QuicStreamId id) { | |
234 session_.CloseStream(id); | |
235 closed_streams_.insert(id); | |
236 } | |
237 | |
238 QuicVersion version() const { return connection_->version(); } | |
239 | |
240 MockConnection* connection_; | |
241 TestSession session_; | |
242 set<QuicStreamId> closed_streams_; | |
243 SpdyHeaderBlock headers_; | |
244 }; | |
245 | |
246 INSTANTIATE_TEST_CASE_P(Tests, QuicSessionTest, | |
247 ::testing::ValuesIn(QuicSupportedVersions())); | |
248 | |
249 TEST_P(QuicSessionTest, PeerAddress) { | |
250 EXPECT_EQ(IPEndPoint(Loopback4(), kTestPort), session_.peer_address()); | |
251 } | |
252 | |
253 TEST_P(QuicSessionTest, IsCryptoHandshakeConfirmed) { | |
254 EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed()); | |
255 CryptoHandshakeMessage message; | |
256 session_.GetCryptoStream()->OnHandshakeMessage(message); | |
257 EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); | |
258 } | |
259 | |
260 TEST_P(QuicSessionTest, IsClosedStreamDefault) { | |
261 // Ensure that no streams are initially closed. | |
262 for (int i = kCryptoStreamId; i < 100; i++) { | |
263 EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i; | |
264 } | |
265 } | |
266 | |
267 TEST_P(QuicSessionTest, ImplicitlyCreatedStreams) { | |
268 ASSERT_TRUE(session_.GetIncomingDataStream(7) != nullptr); | |
269 // Both 3 and 5 should be implicitly created. | |
270 EXPECT_FALSE(session_.IsClosedStream(3)); | |
271 EXPECT_FALSE(session_.IsClosedStream(5)); | |
272 ASSERT_TRUE(session_.GetIncomingDataStream(5) != nullptr); | |
273 ASSERT_TRUE(session_.GetIncomingDataStream(3) != nullptr); | |
274 } | |
275 | |
276 TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) { | |
277 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
278 EXPECT_EQ(2u, stream2->id()); | |
279 TestStream* stream4 = session_.CreateOutgoingDataStream(); | |
280 EXPECT_EQ(4u, stream4->id()); | |
281 | |
282 CheckClosedStreams(); | |
283 CloseStream(4); | |
284 CheckClosedStreams(); | |
285 CloseStream(2); | |
286 CheckClosedStreams(); | |
287 } | |
288 | |
289 TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) { | |
290 QuicStreamId stream_id1 = kClientDataStreamId1; | |
291 QuicStreamId stream_id2 = kClientDataStreamId2; | |
292 QuicDataStream* stream1 = session_.GetIncomingDataStream(stream_id1); | |
293 QuicDataStreamPeer::SetHeadersDecompressed(stream1, true); | |
294 QuicDataStream* stream2 = session_.GetIncomingDataStream(stream_id2); | |
295 QuicDataStreamPeer::SetHeadersDecompressed(stream2, true); | |
296 | |
297 CheckClosedStreams(); | |
298 CloseStream(stream_id1); | |
299 CheckClosedStreams(); | |
300 CloseStream(stream_id2); | |
301 // Create a stream explicitly, and another implicitly. | |
302 QuicDataStream* stream3 = session_.GetIncomingDataStream(stream_id2 + 4); | |
303 QuicDataStreamPeer::SetHeadersDecompressed(stream3, true); | |
304 CheckClosedStreams(); | |
305 // Close one, but make sure the other is still not closed | |
306 CloseStream(stream3->id()); | |
307 CheckClosedStreams(); | |
308 } | |
309 | |
310 TEST_P(QuicSessionTest, StreamIdTooLarge) { | |
311 QuicStreamId stream_id = kClientDataStreamId1; | |
312 session_.GetIncomingDataStream(stream_id); | |
313 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)); | |
314 session_.GetIncomingDataStream(stream_id + kMaxStreamIdDelta + 2); | |
315 } | |
316 | |
317 TEST_P(QuicSessionTest, DecompressionError) { | |
318 QuicHeadersStream* stream = QuicSessionPeer::GetHeadersStream(&session_); | |
319 if (version() > QUIC_VERSION_23) { | |
320 // This test does not apply to HPACK compression. | |
321 return; | |
322 } | |
323 const unsigned char data[] = { | |
324 0x80, 0x03, 0x00, 0x01, // SPDY/3 SYN_STREAM frame | |
325 0x00, 0x00, 0x00, 0x25, // flags/length | |
326 0x00, 0x00, 0x00, 0x05, // stream id | |
327 0x00, 0x00, 0x00, 0x00, // associated stream id | |
328 0x00, 0x00, | |
329 'a', 'b', 'c', 'd' // invalid compressed data | |
330 }; | |
331 EXPECT_CALL(*connection_, SendConnectionCloseWithDetails( | |
332 QUIC_INVALID_HEADERS_STREAM_DATA, | |
333 "SPDY framing error: DECOMPRESS_FAILURE")); | |
334 stream->ProcessRawData(reinterpret_cast<const char*>(data), | |
335 arraysize(data)); | |
336 } | |
337 | |
338 TEST_P(QuicSessionTest, DebugDFatalIfMarkingClosedStreamWriteBlocked) { | |
339 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
340 // Close the stream. | |
341 stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); | |
342 // TODO(rtenneti): enable when chromium supports EXPECT_DEBUG_DFATAL. | |
343 /* | |
344 QuicStreamId kClosedStreamId = stream2->id(); | |
345 EXPECT_DEBUG_DFATAL( | |
346 session_.MarkWriteBlocked(kClosedStreamId, kSomeMiddlePriority), | |
347 "Marking unknown stream 2 blocked."); | |
348 */ | |
349 } | |
350 | |
351 TEST_P(QuicSessionTest, DebugDFatalIfMarkWriteBlockedCalledWithWrongPriority) { | |
352 const QuicPriority kDifferentPriority = 0; | |
353 | |
354 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
355 EXPECT_NE(kDifferentPriority, stream2->EffectivePriority()); | |
356 // TODO(rtenneti): enable when chromium supports EXPECT_DEBUG_DFATAL. | |
357 /* | |
358 EXPECT_DEBUG_DFATAL( | |
359 session_.MarkWriteBlocked(stream2->id(), kDifferentPriority), | |
360 "Priorities do not match. Got: 0 Expected: 3"); | |
361 */ | |
362 } | |
363 | |
364 TEST_P(QuicSessionTest, OnCanWrite) { | |
365 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
366 TestStream* stream4 = session_.CreateOutgoingDataStream(); | |
367 TestStream* stream6 = session_.CreateOutgoingDataStream(); | |
368 | |
369 session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); | |
370 session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); | |
371 session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); | |
372 | |
373 InSequence s; | |
374 StreamBlocker stream2_blocker(&session_, stream2->id()); | |
375 // Reregister, to test the loop limit. | |
376 EXPECT_CALL(*stream2, OnCanWrite()) | |
377 .WillOnce(Invoke(&stream2_blocker, &StreamBlocker::MarkWriteBlocked)); | |
378 EXPECT_CALL(*stream6, OnCanWrite()); | |
379 EXPECT_CALL(*stream4, OnCanWrite()); | |
380 session_.OnCanWrite(); | |
381 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | |
382 } | |
383 | |
384 TEST_P(QuicSessionTest, OnCanWriteBundlesStreams) { | |
385 // Drive congestion control manually. | |
386 MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; | |
387 QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); | |
388 | |
389 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
390 TestStream* stream4 = session_.CreateOutgoingDataStream(); | |
391 TestStream* stream6 = session_.CreateOutgoingDataStream(); | |
392 | |
393 session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); | |
394 session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); | |
395 session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); | |
396 | |
397 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillRepeatedly( | |
398 Return(QuicTime::Delta::Zero())); | |
399 EXPECT_CALL(*send_algorithm, GetCongestionWindow()) | |
400 .WillRepeatedly(Return(kMaxPacketSize * 10)); | |
401 EXPECT_CALL(*stream2, OnCanWrite()) | |
402 .WillOnce(IgnoreResult(Invoke(CreateFunctor( | |
403 &session_, &TestSession::SendStreamData, stream2->id())))); | |
404 EXPECT_CALL(*stream4, OnCanWrite()) | |
405 .WillOnce(IgnoreResult(Invoke(CreateFunctor( | |
406 &session_, &TestSession::SendStreamData, stream4->id())))); | |
407 EXPECT_CALL(*stream6, OnCanWrite()) | |
408 .WillOnce(IgnoreResult(Invoke(CreateFunctor( | |
409 &session_, &TestSession::SendStreamData, stream6->id())))); | |
410 | |
411 // Expect that we only send one packet, the writes from different streams | |
412 // should be bundled together. | |
413 MockPacketWriter* writer = | |
414 static_cast<MockPacketWriter*>( | |
415 QuicConnectionPeer::GetWriter(session_.connection())); | |
416 EXPECT_CALL(*writer, WritePacket(_, _, _, _)).WillOnce( | |
417 Return(WriteResult(WRITE_STATUS_OK, 0))); | |
418 EXPECT_CALL(*send_algorithm, OnPacketSent(_, _, _, _, _)).Times(1); | |
419 session_.OnCanWrite(); | |
420 EXPECT_FALSE(session_.WillingAndAbleToWrite()); | |
421 } | |
422 | |
423 TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) { | |
424 InSequence s; | |
425 | |
426 // Drive congestion control manually. | |
427 MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; | |
428 QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); | |
429 | |
430 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
431 TestStream* stream4 = session_.CreateOutgoingDataStream(); | |
432 TestStream* stream6 = session_.CreateOutgoingDataStream(); | |
433 | |
434 session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); | |
435 session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); | |
436 session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); | |
437 | |
438 StreamBlocker stream2_blocker(&session_, stream2->id()); | |
439 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return( | |
440 QuicTime::Delta::Zero())); | |
441 EXPECT_CALL(*stream2, OnCanWrite()); | |
442 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return( | |
443 QuicTime::Delta::Zero())); | |
444 EXPECT_CALL(*stream6, OnCanWrite()); | |
445 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return( | |
446 QuicTime::Delta::Infinite())); | |
447 // stream4->OnCanWrite is not called. | |
448 | |
449 session_.OnCanWrite(); | |
450 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | |
451 | |
452 // Still congestion-control blocked. | |
453 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return( | |
454 QuicTime::Delta::Infinite())); | |
455 session_.OnCanWrite(); | |
456 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | |
457 | |
458 // stream4->OnCanWrite is called once the connection stops being | |
459 // congestion-control blocked. | |
460 EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return( | |
461 QuicTime::Delta::Zero())); | |
462 EXPECT_CALL(*stream4, OnCanWrite()); | |
463 session_.OnCanWrite(); | |
464 EXPECT_FALSE(session_.WillingAndAbleToWrite()); | |
465 } | |
466 | |
467 TEST_P(QuicSessionTest, BufferedHandshake) { | |
468 EXPECT_FALSE(session_.HasPendingHandshake()); // Default value. | |
469 | |
470 // Test that blocking other streams does not change our status. | |
471 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
472 StreamBlocker stream2_blocker(&session_, stream2->id()); | |
473 stream2_blocker.MarkWriteBlocked(); | |
474 EXPECT_FALSE(session_.HasPendingHandshake()); | |
475 | |
476 TestStream* stream3 = session_.CreateOutgoingDataStream(); | |
477 StreamBlocker stream3_blocker(&session_, stream3->id()); | |
478 stream3_blocker.MarkWriteBlocked(); | |
479 EXPECT_FALSE(session_.HasPendingHandshake()); | |
480 | |
481 // Blocking (due to buffering of) the Crypto stream is detected. | |
482 session_.MarkWriteBlocked(kCryptoStreamId, kHighestPriority); | |
483 EXPECT_TRUE(session_.HasPendingHandshake()); | |
484 | |
485 TestStream* stream4 = session_.CreateOutgoingDataStream(); | |
486 StreamBlocker stream4_blocker(&session_, stream4->id()); | |
487 stream4_blocker.MarkWriteBlocked(); | |
488 EXPECT_TRUE(session_.HasPendingHandshake()); | |
489 | |
490 InSequence s; | |
491 // Force most streams to re-register, which is common scenario when we block | |
492 // the Crypto stream, and only the crypto stream can "really" write. | |
493 | |
494 // Due to prioritization, we *should* be asked to write the crypto stream | |
495 // first. | |
496 // Don't re-register the crypto stream (which signals complete writing). | |
497 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | |
498 EXPECT_CALL(*crypto_stream, OnCanWrite()); | |
499 | |
500 // Re-register all other streams, to show they weren't able to proceed. | |
501 EXPECT_CALL(*stream2, OnCanWrite()) | |
502 .WillOnce(Invoke(&stream2_blocker, &StreamBlocker::MarkWriteBlocked)); | |
503 EXPECT_CALL(*stream3, OnCanWrite()) | |
504 .WillOnce(Invoke(&stream3_blocker, &StreamBlocker::MarkWriteBlocked)); | |
505 EXPECT_CALL(*stream4, OnCanWrite()) | |
506 .WillOnce(Invoke(&stream4_blocker, &StreamBlocker::MarkWriteBlocked)); | |
507 | |
508 session_.OnCanWrite(); | |
509 EXPECT_TRUE(session_.WillingAndAbleToWrite()); | |
510 EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. | |
511 } | |
512 | |
513 TEST_P(QuicSessionTest, OnCanWriteWithClosedStream) { | |
514 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
515 TestStream* stream4 = session_.CreateOutgoingDataStream(); | |
516 TestStream* stream6 = session_.CreateOutgoingDataStream(); | |
517 | |
518 session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); | |
519 session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); | |
520 session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); | |
521 CloseStream(stream6->id()); | |
522 | |
523 InSequence s; | |
524 EXPECT_CALL(*stream2, OnCanWrite()); | |
525 EXPECT_CALL(*stream4, OnCanWrite()); | |
526 session_.OnCanWrite(); | |
527 EXPECT_FALSE(session_.WillingAndAbleToWrite()); | |
528 } | |
529 | |
530 TEST_P(QuicSessionTest, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { | |
531 // Ensure connection level flow control blockage. | |
532 QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0); | |
533 EXPECT_TRUE(session_.flow_controller()->IsBlocked()); | |
534 EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); | |
535 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
536 | |
537 // Mark the crypto and headers streams as write blocked, we expect them to be | |
538 // allowed to write later. | |
539 session_.MarkWriteBlocked(kCryptoStreamId, kHighestPriority); | |
540 session_.MarkWriteBlocked(kHeadersStreamId, kHighestPriority); | |
541 | |
542 // Create a data stream, and although it is write blocked we never expect it | |
543 // to be allowed to write as we are connection level flow control blocked. | |
544 TestStream* stream = session_.CreateOutgoingDataStream(); | |
545 session_.MarkWriteBlocked(stream->id(), kSomeMiddlePriority); | |
546 EXPECT_CALL(*stream, OnCanWrite()).Times(0); | |
547 | |
548 // The crypto and headers streams should be called even though we are | |
549 // connection flow control blocked. | |
550 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | |
551 EXPECT_CALL(*crypto_stream, OnCanWrite()).Times(1); | |
552 TestHeadersStream* headers_stream = new TestHeadersStream(&session_); | |
553 QuicSessionPeer::SetHeadersStream(&session_, headers_stream); | |
554 EXPECT_CALL(*headers_stream, OnCanWrite()).Times(1); | |
555 | |
556 session_.OnCanWrite(); | |
557 EXPECT_FALSE(session_.WillingAndAbleToWrite()); | |
558 } | |
559 | |
560 TEST_P(QuicSessionTest, SendGoAway) { | |
561 EXPECT_CALL(*connection_, | |
562 SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")); | |
563 session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); | |
564 EXPECT_TRUE(session_.goaway_sent()); | |
565 | |
566 EXPECT_CALL(*connection_, | |
567 SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY, 0)).Times(0); | |
568 EXPECT_TRUE(session_.GetIncomingDataStream(3u)); | |
569 } | |
570 | |
571 TEST_P(QuicSessionTest, DoNotSendGoAwayTwice) { | |
572 EXPECT_CALL(*connection_, | |
573 SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")).Times(1); | |
574 session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); | |
575 EXPECT_TRUE(session_.goaway_sent()); | |
576 session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); | |
577 } | |
578 | |
579 TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) { | |
580 EXPECT_EQ(kInitialIdleTimeoutSecs + 3, | |
581 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); | |
582 CryptoHandshakeMessage msg; | |
583 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
584 EXPECT_EQ(kMaximumIdleTimeoutSecs + 3, | |
585 QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); | |
586 } | |
587 | |
588 TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) { | |
589 // Send two bytes of payload. | |
590 QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT")); | |
591 vector<QuicStreamFrame> frames; | |
592 frames.push_back(data1); | |
593 session_.OnStreamFrames(frames); | |
594 EXPECT_EQ(1u, session_.GetNumOpenStreams()); | |
595 | |
596 QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0); | |
597 session_.OnRstStream(rst1); | |
598 EXPECT_EQ(0u, session_.GetNumOpenStreams()); | |
599 // Connection should remain alive. | |
600 EXPECT_TRUE(connection_->connected()); | |
601 } | |
602 | |
603 TEST_P(QuicSessionTest, MultipleRstStreamsCauseSingleConnectionClose) { | |
604 // If multiple invalid reset stream frames arrive in a single packet, this | |
605 // should trigger a connection close. However there is no need to send | |
606 // multiple connection close frames. | |
607 | |
608 // Create valid stream. | |
609 QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT")); | |
610 vector<QuicStreamFrame> frames; | |
611 frames.push_back(data1); | |
612 session_.OnStreamFrames(frames); | |
613 EXPECT_EQ(1u, session_.GetNumOpenStreams()); | |
614 | |
615 // Process first invalid stream reset, resulting in the connection being | |
616 // closed. | |
617 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)) | |
618 .Times(1); | |
619 QuicStreamId kLargeInvalidStreamId = 99999999; | |
620 QuicRstStreamFrame rst1(kLargeInvalidStreamId, QUIC_STREAM_NO_ERROR, 0); | |
621 session_.OnRstStream(rst1); | |
622 QuicConnectionPeer::CloseConnection(connection_); | |
623 | |
624 // Processing of second invalid stream reset should not result in the | |
625 // connection being closed for a second time. | |
626 QuicRstStreamFrame rst2(kLargeInvalidStreamId, QUIC_STREAM_NO_ERROR, 0); | |
627 session_.OnRstStream(rst2); | |
628 } | |
629 | |
630 TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedStream) { | |
631 // Test that if a stream is flow control blocked, then on receipt of the SHLO | |
632 // containing a suitable send window offset, the stream becomes unblocked. | |
633 | |
634 // Ensure that Writev consumes all the data it is given (simulate no socket | |
635 // blocking). | |
636 session_.set_writev_consumes_all_data(true); | |
637 | |
638 // Create a stream, and send enough data to make it flow control blocked. | |
639 TestStream* stream2 = session_.CreateOutgoingDataStream(); | |
640 string body(kMinimumFlowControlSendWindow, '.'); | |
641 EXPECT_FALSE(stream2->flow_controller()->IsBlocked()); | |
642 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
643 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
644 stream2->SendBody(body, false); | |
645 EXPECT_TRUE(stream2->flow_controller()->IsBlocked()); | |
646 EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); | |
647 EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); | |
648 | |
649 // The handshake message will call OnCanWrite, so the stream can resume | |
650 // writing. | |
651 EXPECT_CALL(*stream2, OnCanWrite()); | |
652 // Now complete the crypto handshake, resulting in an increased flow control | |
653 // send window. | |
654 CryptoHandshakeMessage msg; | |
655 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
656 | |
657 // Stream is now unblocked. | |
658 EXPECT_FALSE(stream2->flow_controller()->IsBlocked()); | |
659 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
660 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
661 } | |
662 | |
663 TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedCryptoStream) { | |
664 // Test that if the crypto stream is flow control blocked, then if the SHLO | |
665 // contains a larger send window offset, the stream becomes unblocked. | |
666 session_.set_writev_consumes_all_data(true); | |
667 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | |
668 EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); | |
669 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
670 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
671 QuicHeadersStream* headers_stream = | |
672 QuicSessionPeer::GetHeadersStream(&session_); | |
673 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
674 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
675 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
676 // Write until the crypto stream is flow control blocked. | |
677 int i = 0; | |
678 while (!crypto_stream->flow_controller()->IsBlocked() && i < 1000) { | |
679 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
680 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
681 QuicConfig config; | |
682 CryptoHandshakeMessage crypto_message; | |
683 config.ToHandshakeMessage(&crypto_message); | |
684 crypto_stream->SendHandshakeMessage(crypto_message); | |
685 ++i; | |
686 } | |
687 EXPECT_TRUE(crypto_stream->flow_controller()->IsBlocked()); | |
688 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
689 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
690 EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); | |
691 EXPECT_FALSE(session_.HasDataToWrite()); | |
692 EXPECT_TRUE(crypto_stream->HasBufferedData()); | |
693 | |
694 // The handshake message will call OnCanWrite, so the stream can | |
695 // resume writing. | |
696 EXPECT_CALL(*crypto_stream, OnCanWrite()); | |
697 // Now complete the crypto handshake, resulting in an increased flow control | |
698 // send window. | |
699 CryptoHandshakeMessage msg; | |
700 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
701 | |
702 // Stream is now unblocked and will no longer have buffered data. | |
703 EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); | |
704 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
705 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
706 } | |
707 | |
708 TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedHeadersStream) { | |
709 // Test that if the header stream is flow control blocked, then if the SHLO | |
710 // contains a larger send window offset, the stream becomes unblocked. | |
711 session_.set_writev_consumes_all_data(true); | |
712 TestCryptoStream* crypto_stream = session_.GetCryptoStream(); | |
713 EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); | |
714 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
715 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
716 QuicHeadersStream* headers_stream = | |
717 QuicSessionPeer::GetHeadersStream(&session_); | |
718 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
719 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
720 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
721 QuicStreamId stream_id = 5; | |
722 // Write until the header stream is flow control blocked. | |
723 SpdyHeaderBlock headers; | |
724 while (!headers_stream->flow_controller()->IsBlocked() && stream_id < 2000) { | |
725 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
726 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
727 headers["header"] = base::Uint64ToString(base::RandUint64()) + | |
728 base::Uint64ToString(base::RandUint64()) + | |
729 base::Uint64ToString(base::RandUint64()); | |
730 headers_stream->WriteHeaders(stream_id, headers, true, 0, nullptr); | |
731 stream_id += 2; | |
732 } | |
733 // Write once more to ensure that the headers stream has buffered data. The | |
734 // random headers may have exactly filled the flow control window. | |
735 headers_stream->WriteHeaders(stream_id, headers, true, 0, nullptr); | |
736 EXPECT_TRUE(headers_stream->HasBufferedData()); | |
737 | |
738 EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked()); | |
739 EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); | |
740 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
741 EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); | |
742 EXPECT_FALSE(session_.HasDataToWrite()); | |
743 | |
744 // Now complete the crypto handshake, resulting in an increased flow control | |
745 // send window. | |
746 CryptoHandshakeMessage msg; | |
747 session_.GetCryptoStream()->OnHandshakeMessage(msg); | |
748 | |
749 // Stream is now unblocked and will no longer have buffered data. | |
750 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
751 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
752 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
753 EXPECT_FALSE(headers_stream->HasBufferedData()); | |
754 } | |
755 | |
756 TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstOutOfOrder) { | |
757 // Test that when we receive an out of order stream RST we correctly adjust | |
758 // our connection level flow control receive window. | |
759 // On close, the stream should mark as consumed all bytes between the highest | |
760 // byte consumed so far and the final byte offset from the RST frame. | |
761 TestStream* stream = session_.CreateOutgoingDataStream(); | |
762 | |
763 const QuicStreamOffset kByteOffset = | |
764 1 + kInitialSessionFlowControlWindowForTest / 2; | |
765 | |
766 // Expect no stream WINDOW_UPDATE frames, as stream read side closed. | |
767 EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0); | |
768 // We do expect a connection level WINDOW_UPDATE when the stream is reset. | |
769 EXPECT_CALL(*connection_, | |
770 SendWindowUpdate(0, kInitialSessionFlowControlWindowForTest + | |
771 kByteOffset)).Times(1); | |
772 | |
773 QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED, | |
774 kByteOffset); | |
775 session_.OnRstStream(rst_frame); | |
776 session_.PostProcessAfterData(); | |
777 EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); | |
778 } | |
779 | |
780 TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAndLocalReset) { | |
781 // Test the situation where we receive a FIN on a stream, and before we fully | |
782 // consume all the data from the sequencer buffer we locally RST the stream. | |
783 // The bytes between highest consumed byte, and the final byte offset that we | |
784 // determined when the FIN arrived, should be marked as consumed at the | |
785 // connection level flow controller when the stream is reset. | |
786 TestStream* stream = session_.CreateOutgoingDataStream(); | |
787 | |
788 const QuicStreamOffset kByteOffset = | |
789 1 + kInitialSessionFlowControlWindowForTest / 2; | |
790 QuicStreamFrame frame(stream->id(), true, kByteOffset, IOVector()); | |
791 vector<QuicStreamFrame> frames; | |
792 frames.push_back(frame); | |
793 session_.OnStreamFrames(frames); | |
794 session_.PostProcessAfterData(); | |
795 | |
796 EXPECT_EQ(0u, stream->flow_controller()->bytes_consumed()); | |
797 EXPECT_EQ(kByteOffset, | |
798 stream->flow_controller()->highest_received_byte_offset()); | |
799 | |
800 // Reset stream locally. | |
801 stream->Reset(QUIC_STREAM_CANCELLED); | |
802 EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); | |
803 } | |
804 | |
805 TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAfterRst) { | |
806 // Test that when we RST the stream (and tear down stream state), and then | |
807 // receive a FIN from the peer, we correctly adjust our connection level flow | |
808 // control receive window. | |
809 | |
810 // Connection starts with some non-zero highest received byte offset, | |
811 // due to other active streams. | |
812 const uint64 kInitialConnectionBytesConsumed = 567; | |
813 const uint64 kInitialConnectionHighestReceivedOffset = 1234; | |
814 EXPECT_LT(kInitialConnectionBytesConsumed, | |
815 kInitialConnectionHighestReceivedOffset); | |
816 session_.flow_controller()->UpdateHighestReceivedOffset( | |
817 kInitialConnectionHighestReceivedOffset); | |
818 session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed); | |
819 | |
820 // Reset our stream: this results in the stream being closed locally. | |
821 TestStream* stream = session_.CreateOutgoingDataStream(); | |
822 stream->Reset(QUIC_STREAM_CANCELLED); | |
823 | |
824 // Now receive a response from the peer with a FIN. We should handle this by | |
825 // adjusting the connection level flow control receive window to take into | |
826 // account the total number of bytes sent by the peer. | |
827 const QuicStreamOffset kByteOffset = 5678; | |
828 string body = "hello"; | |
829 IOVector data = MakeIOVector(body); | |
830 QuicStreamFrame frame(stream->id(), true, kByteOffset, data); | |
831 vector<QuicStreamFrame> frames; | |
832 frames.push_back(frame); | |
833 session_.OnStreamFrames(frames); | |
834 | |
835 QuicStreamOffset total_stream_bytes_sent_by_peer = | |
836 kByteOffset + body.length(); | |
837 EXPECT_EQ(kInitialConnectionBytesConsumed + total_stream_bytes_sent_by_peer, | |
838 session_.flow_controller()->bytes_consumed()); | |
839 EXPECT_EQ( | |
840 kInitialConnectionHighestReceivedOffset + total_stream_bytes_sent_by_peer, | |
841 session_.flow_controller()->highest_received_byte_offset()); | |
842 } | |
843 | |
844 TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstAfterRst) { | |
845 // Test that when we RST the stream (and tear down stream state), and then | |
846 // receive a RST from the peer, we correctly adjust our connection level flow | |
847 // control receive window. | |
848 | |
849 // Connection starts with some non-zero highest received byte offset, | |
850 // due to other active streams. | |
851 const uint64 kInitialConnectionBytesConsumed = 567; | |
852 const uint64 kInitialConnectionHighestReceivedOffset = 1234; | |
853 EXPECT_LT(kInitialConnectionBytesConsumed, | |
854 kInitialConnectionHighestReceivedOffset); | |
855 session_.flow_controller()->UpdateHighestReceivedOffset( | |
856 kInitialConnectionHighestReceivedOffset); | |
857 session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed); | |
858 | |
859 // Reset our stream: this results in the stream being closed locally. | |
860 TestStream* stream = session_.CreateOutgoingDataStream(); | |
861 stream->Reset(QUIC_STREAM_CANCELLED); | |
862 | |
863 // Now receive a RST from the peer. We should handle this by adjusting the | |
864 // connection level flow control receive window to take into account the total | |
865 // number of bytes sent by the peer. | |
866 const QuicStreamOffset kByteOffset = 5678; | |
867 QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED, | |
868 kByteOffset); | |
869 session_.OnRstStream(rst_frame); | |
870 | |
871 EXPECT_EQ(kInitialConnectionBytesConsumed + kByteOffset, | |
872 session_.flow_controller()->bytes_consumed()); | |
873 EXPECT_EQ(kInitialConnectionHighestReceivedOffset + kByteOffset, | |
874 session_.flow_controller()->highest_received_byte_offset()); | |
875 } | |
876 | |
877 TEST_P(QuicSessionTest, InvalidStreamFlowControlWindowInHandshake) { | |
878 // Test that receipt of an invalid (< default) stream flow control window from | |
879 // the peer results in the connection being torn down. | |
880 uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1; | |
881 QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(session_.config(), | |
882 kInvalidWindow); | |
883 | |
884 EXPECT_CALL(*connection_, | |
885 SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW)); | |
886 session_.OnConfigNegotiated(); | |
887 } | |
888 | |
889 TEST_P(QuicSessionTest, InvalidSessionFlowControlWindowInHandshake) { | |
890 // Test that receipt of an invalid (< default) session flow control window | |
891 // from the peer results in the connection being torn down. | |
892 uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1; | |
893 QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(), | |
894 kInvalidWindow); | |
895 | |
896 EXPECT_CALL(*connection_, | |
897 SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW)); | |
898 session_.OnConfigNegotiated(); | |
899 } | |
900 | |
901 TEST_P(QuicSessionTest, FlowControlWithInvalidFinalOffset) { | |
902 // Test that if we receive a stream RST with a highest byte offset that | |
903 // violates flow control, that we close the connection. | |
904 const uint64 kLargeOffset = kInitialSessionFlowControlWindowForTest + 1; | |
905 EXPECT_CALL(*connection_, | |
906 SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA)) | |
907 .Times(2); | |
908 | |
909 // Check that stream frame + FIN results in connection close. | |
910 TestStream* stream = session_.CreateOutgoingDataStream(); | |
911 stream->Reset(QUIC_STREAM_CANCELLED); | |
912 QuicStreamFrame frame(stream->id(), true, kLargeOffset, IOVector()); | |
913 vector<QuicStreamFrame> frames; | |
914 frames.push_back(frame); | |
915 session_.OnStreamFrames(frames); | |
916 | |
917 // Check that RST results in connection close. | |
918 QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED, | |
919 kLargeOffset); | |
920 session_.OnRstStream(rst_frame); | |
921 } | |
922 | |
923 TEST_P(QuicSessionTest, WindowUpdateUnblocksHeadersStream) { | |
924 // Test that a flow control blocked headers stream gets unblocked on recipt of | |
925 // a WINDOW_UPDATE frame. Regression test for b/17413860. | |
926 | |
927 // Set the headers stream to be flow control blocked. | |
928 QuicHeadersStream* headers_stream = | |
929 QuicSessionPeer::GetHeadersStream(&session_); | |
930 QuicFlowControllerPeer::SetSendWindowOffset(headers_stream->flow_controller(), | |
931 0); | |
932 EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked()); | |
933 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
934 EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); | |
935 | |
936 // Unblock the headers stream by supplying a WINDOW_UPDATE. | |
937 QuicWindowUpdateFrame window_update_frame(headers_stream->id(), | |
938 2 * kMinimumFlowControlSendWindow); | |
939 vector<QuicWindowUpdateFrame> frames; | |
940 frames.push_back(window_update_frame); | |
941 session_.OnWindowUpdateFrames(frames); | |
942 EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); | |
943 EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); | |
944 EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); | |
945 } | |
946 | |
947 TEST_P(QuicSessionTest, TooManyUnfinishedStreamsCauseConnectionClose) { | |
948 // If a buggy/malicious peer creates too many streams that are not ended with | |
949 // a FIN or RST then we send a connection close. | |
950 EXPECT_CALL(*connection_, | |
951 SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS)).Times(1); | |
952 | |
953 const int kMaxStreams = 5; | |
954 QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); | |
955 | |
956 // Create kMaxStreams + 1 data streams, and close them all without receiving a | |
957 // FIN or a RST from the client. | |
958 const int kFirstStreamId = kClientDataStreamId1; | |
959 const int kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams + 1; | |
960 for (int i = kFirstStreamId; i < kFinalStreamId; i += 2) { | |
961 QuicStreamFrame data1(i, false, 0, MakeIOVector("HT")); | |
962 vector<QuicStreamFrame> frames; | |
963 frames.push_back(data1); | |
964 session_.OnStreamFrames(frames); | |
965 EXPECT_EQ(1u, session_.GetNumOpenStreams()); | |
966 session_.CloseStream(i); | |
967 } | |
968 | |
969 // Called after any new data is received by the session, and triggers the call | |
970 // to close the connection. | |
971 session_.PostProcessAfterData(); | |
972 } | |
973 | |
974 } // namespace | |
975 } // namespace test | |
976 } // namespace net | |
OLD | NEW |