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/spdy/spdy_session.h" | |
6 | |
7 #include <algorithm> | |
8 #include <memory> | |
9 #include <utility> | |
10 | |
11 #include "base/base64.h" | |
12 #include "base/bind.h" | |
13 #include "base/callback.h" | |
14 #include "base/run_loop.h" | |
15 #include "base/test/histogram_tester.h" | |
16 #include "base/test/scoped_feature_list.h" | |
17 #include "net/base/host_port_pair.h" | |
18 #include "net/base/io_buffer.h" | |
19 #include "net/base/ip_endpoint.h" | |
20 #include "net/base/proxy_delegate.h" | |
21 #include "net/base/request_priority.h" | |
22 #include "net/base/test_data_stream.h" | |
23 #include "net/base/test_proxy_delegate.h" | |
24 #include "net/cert/ct_policy_status.h" | |
25 #include "net/log/net_log_event_type.h" | |
26 #include "net/log/net_log_source.h" | |
27 #include "net/log/test_net_log.h" | |
28 #include "net/log/test_net_log_entry.h" | |
29 #include "net/log/test_net_log_util.h" | |
30 #include "net/proxy/proxy_server.h" | |
31 #include "net/socket/client_socket_pool_manager.h" | |
32 #include "net/socket/socket_test_util.h" | |
33 #include "net/spdy/spdy_http_utils.h" | |
34 #include "net/spdy/spdy_session_pool.h" | |
35 #include "net/spdy/spdy_session_test_util.h" | |
36 #include "net/spdy/spdy_stream.h" | |
37 #include "net/spdy/spdy_stream_test_util.h" | |
38 #include "net/spdy/spdy_test_util_common.h" | |
39 #include "net/spdy/spdy_test_utils.h" | |
40 #include "net/test/cert_test_util.h" | |
41 #include "net/test/gtest_util.h" | |
42 #include "net/test/test_data_directory.h" | |
43 #include "testing/gmock/include/gmock/gmock.h" | |
44 #include "testing/platform_test.h" | |
45 | |
46 using net::test::IsError; | |
47 using net::test::IsOk; | |
48 using net::test::TestServerPushDelegate; | |
49 | |
50 namespace net { | |
51 | |
52 namespace { | |
53 | |
54 const char kHttpURLFromAnotherOrigin[] = "http://www.example2.org/a.dat"; | |
55 const char kHttpsURLFromAnotherOrigin[] = "https://www.example2.org/b.dat"; | |
56 | |
57 const char kBodyData[] = "Body data"; | |
58 const size_t kBodyDataSize = arraysize(kBodyData); | |
59 const SpdyStringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize); | |
60 | |
61 static base::TimeDelta g_time_delta; | |
62 static base::TimeTicks g_time_now; | |
63 | |
64 base::TimeTicks TheNearFuture() { | |
65 return base::TimeTicks::Now() + g_time_delta; | |
66 } | |
67 | |
68 base::TimeTicks SlowReads() { | |
69 g_time_delta += | |
70 base::TimeDelta::FromMilliseconds(2 * kYieldAfterDurationMilliseconds); | |
71 return base::TimeTicks::Now() + g_time_delta; | |
72 } | |
73 | |
74 base::TimeTicks InstantaneousReads() { | |
75 return g_time_now; | |
76 } | |
77 | |
78 class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate { | |
79 public: | |
80 MOCK_METHOD1(IsCTRequiredForHost, CTRequirementLevel(const SpdyString& host)); | |
81 }; | |
82 | |
83 } // namespace | |
84 | |
85 class SpdySessionTest : public PlatformTest { | |
86 public: | |
87 // Functions used with RunResumeAfterUnstallTest(). | |
88 | |
89 void StallSessionOnly(SpdyStream* stream) { StallSessionSend(); } | |
90 | |
91 void StallStreamOnly(SpdyStream* stream) { StallStreamSend(stream); } | |
92 | |
93 void StallSessionStream(SpdyStream* stream) { | |
94 StallSessionSend(); | |
95 StallStreamSend(stream); | |
96 } | |
97 | |
98 void StallStreamSession(SpdyStream* stream) { | |
99 StallStreamSend(stream); | |
100 StallSessionSend(); | |
101 } | |
102 | |
103 void UnstallSessionOnly(SpdyStream* stream, int32_t delta_window_size) { | |
104 UnstallSessionSend(delta_window_size); | |
105 } | |
106 | |
107 void UnstallStreamOnly(SpdyStream* stream, int32_t delta_window_size) { | |
108 UnstallStreamSend(stream, delta_window_size); | |
109 } | |
110 | |
111 void UnstallSessionStream(SpdyStream* stream, int32_t delta_window_size) { | |
112 UnstallSessionSend(delta_window_size); | |
113 UnstallStreamSend(stream, delta_window_size); | |
114 } | |
115 | |
116 void UnstallStreamSession(SpdyStream* stream, int32_t delta_window_size) { | |
117 UnstallStreamSend(stream, delta_window_size); | |
118 UnstallSessionSend(delta_window_size); | |
119 } | |
120 | |
121 protected: | |
122 SpdySessionTest() | |
123 : old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group( | |
124 HttpNetworkSession::NORMAL_SOCKET_POOL)), | |
125 old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool( | |
126 HttpNetworkSession::NORMAL_SOCKET_POOL)), | |
127 test_push_delegate_(nullptr), | |
128 spdy_session_pool_(nullptr), | |
129 test_url_(kDefaultUrl), | |
130 test_server_(test_url_), | |
131 key_(HostPortPair::FromURL(test_url_), | |
132 ProxyServer::Direct(), | |
133 PRIVACY_MODE_DISABLED), | |
134 ssl_(SYNCHRONOUS, OK) {} | |
135 | |
136 ~SpdySessionTest() override { | |
137 // Important to restore the per-pool limit first, since the pool limit must | |
138 // always be greater than group limit, and the tests reduce both limits. | |
139 ClientSocketPoolManager::set_max_sockets_per_pool( | |
140 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_); | |
141 ClientSocketPoolManager::set_max_sockets_per_group( | |
142 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_); | |
143 } | |
144 | |
145 void SetUp() override { | |
146 g_time_delta = base::TimeDelta(); | |
147 g_time_now = base::TimeTicks::Now(); | |
148 session_deps_.net_log = log_.bound().net_log(); | |
149 session_deps_.enable_server_push_cancellation = true; | |
150 } | |
151 | |
152 void CreateNetworkSession() { | |
153 DCHECK(!http_session_); | |
154 DCHECK(!spdy_session_pool_); | |
155 http_session_ = | |
156 SpdySessionDependencies::SpdyCreateSession(&session_deps_); | |
157 std::unique_ptr<TestServerPushDelegate> test_push_delegate( | |
158 new TestServerPushDelegate()); | |
159 test_push_delegate_ = test_push_delegate.get(); | |
160 http_session_->SetServerPushDelegate(std::move(test_push_delegate)); | |
161 spdy_session_pool_ = http_session_->spdy_session_pool(); | |
162 } | |
163 | |
164 void CreateInsecureSpdySession() { | |
165 DCHECK(!session_); | |
166 session_ = ::net::CreateInsecureSpdySession(http_session_.get(), key_, | |
167 log_.bound()); | |
168 } | |
169 | |
170 void AddSSLSocketData() { | |
171 ssl_.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); | |
172 ASSERT_TRUE(ssl_.cert); | |
173 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_); | |
174 } | |
175 | |
176 void CreateSecureSpdySession() { | |
177 DCHECK(!session_); | |
178 session_ = | |
179 ::net::CreateSecureSpdySession(http_session_.get(), key_, log_.bound()); | |
180 } | |
181 | |
182 void StallSessionSend() { | |
183 // Reduce the send window size to 0 to stall. | |
184 while (session_->session_send_window_size_ > 0) { | |
185 session_->DecreaseSendWindowSize(std::min( | |
186 kMaxSpdyFrameChunkSize, session_->session_send_window_size_)); | |
187 } | |
188 } | |
189 | |
190 void UnstallSessionSend(int32_t delta_window_size) { | |
191 session_->IncreaseSendWindowSize(delta_window_size); | |
192 } | |
193 | |
194 void StallStreamSend(SpdyStream* stream) { | |
195 // Reduce the send window size to 0 to stall. | |
196 while (stream->send_window_size() > 0) { | |
197 stream->DecreaseSendWindowSize( | |
198 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size())); | |
199 } | |
200 } | |
201 | |
202 void UnstallStreamSend(SpdyStream* stream, int32_t delta_window_size) { | |
203 stream->IncreaseSendWindowSize(delta_window_size); | |
204 } | |
205 | |
206 void RunResumeAfterUnstallTest( | |
207 const base::Callback<void(SpdyStream*)>& stall_function, | |
208 const base::Callback<void(SpdyStream*, int32_t)>& unstall_function); | |
209 | |
210 // Original socket limits. Some tests set these. Safest to always restore | |
211 // them once each test has been run. | |
212 int old_max_group_sockets_; | |
213 int old_max_pool_sockets_; | |
214 | |
215 SpdyTestUtil spdy_util_; | |
216 SpdySessionDependencies session_deps_; | |
217 std::unique_ptr<HttpNetworkSession> http_session_; | |
218 base::WeakPtr<SpdySession> session_; | |
219 TestServerPushDelegate* test_push_delegate_; | |
220 SpdySessionPool* spdy_session_pool_; | |
221 const GURL test_url_; | |
222 const url::SchemeHostPort test_server_; | |
223 SpdySessionKey key_; | |
224 SSLSocketDataProvider ssl_; | |
225 BoundTestNetLog log_; | |
226 }; | |
227 | |
228 // Try to create a SPDY session that will fail during | |
229 // initialization. Nothing should blow up. | |
230 TEST_F(SpdySessionTest, InitialReadError) { | |
231 CreateNetworkSession(); | |
232 | |
233 session_ = TryCreateFakeSpdySessionExpectingFailure(spdy_session_pool_, key_, | |
234 ERR_CONNECTION_CLOSED); | |
235 EXPECT_TRUE(session_); | |
236 // Flush the read. | |
237 base::RunLoop().RunUntilIdle(); | |
238 EXPECT_FALSE(session_); | |
239 } | |
240 | |
241 namespace { | |
242 | |
243 // A helper class that vends a callback that, when fired, destroys a | |
244 // given SpdyStreamRequest. | |
245 class StreamRequestDestroyingCallback : public TestCompletionCallbackBase { | |
246 public: | |
247 StreamRequestDestroyingCallback() {} | |
248 | |
249 ~StreamRequestDestroyingCallback() override {} | |
250 | |
251 void SetRequestToDestroy(std::unique_ptr<SpdyStreamRequest> request) { | |
252 request_ = std::move(request); | |
253 } | |
254 | |
255 CompletionCallback MakeCallback() { | |
256 return base::Bind(&StreamRequestDestroyingCallback::OnComplete, | |
257 base::Unretained(this)); | |
258 } | |
259 | |
260 private: | |
261 void OnComplete(int result) { | |
262 request_.reset(); | |
263 SetResult(result); | |
264 } | |
265 | |
266 std::unique_ptr<SpdyStreamRequest> request_; | |
267 }; | |
268 | |
269 } // namespace | |
270 | |
271 // Request kInitialMaxConcurrentStreams streams. Request two more | |
272 // streams, but have the callback for one destroy the second stream | |
273 // request. Close the session. Nothing should blow up. This is a | |
274 // regression test for http://crbug.com/250841 . | |
275 TEST_F(SpdySessionTest, PendingStreamCancellingAnother) { | |
276 session_deps_.host_resolver->set_synchronous_mode(true); | |
277 | |
278 MockRead reads[] = {MockRead(ASYNC, 0, 0), }; | |
279 | |
280 SequencedSocketData data(reads, arraysize(reads), nullptr, 0); | |
281 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
282 | |
283 AddSSLSocketData(); | |
284 | |
285 CreateNetworkSession(); | |
286 CreateSecureSpdySession(); | |
287 | |
288 // Create the maximum number of concurrent streams. | |
289 for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) { | |
290 base::WeakPtr<SpdyStream> spdy_stream = | |
291 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, | |
292 test_url_, MEDIUM, NetLogWithSource()); | |
293 ASSERT_TRUE(spdy_stream); | |
294 } | |
295 | |
296 SpdyStreamRequest request1; | |
297 std::unique_ptr<SpdyStreamRequest> request2(new SpdyStreamRequest); | |
298 | |
299 StreamRequestDestroyingCallback callback1; | |
300 ASSERT_EQ(ERR_IO_PENDING, | |
301 request1.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, | |
302 test_url_, MEDIUM, NetLogWithSource(), | |
303 callback1.MakeCallback())); | |
304 | |
305 // |callback2| is never called. | |
306 TestCompletionCallback callback2; | |
307 ASSERT_EQ( | |
308 ERR_IO_PENDING, | |
309 request2->StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
310 MEDIUM, NetLogWithSource(), callback2.callback())); | |
311 | |
312 callback1.SetRequestToDestroy(std::move(request2)); | |
313 | |
314 session_->CloseSessionOnError(ERR_ABORTED, "Aborting session"); | |
315 | |
316 EXPECT_THAT(callback1.WaitForResult(), IsError(ERR_ABORTED)); | |
317 } | |
318 | |
319 // A session receiving a GOAWAY frame with no active streams should close. | |
320 TEST_F(SpdySessionTest, GoAwayWithNoActiveStreams) { | |
321 session_deps_.host_resolver->set_synchronous_mode(true); | |
322 | |
323 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1)); | |
324 MockRead reads[] = { | |
325 CreateMockRead(goaway, 0), | |
326 }; | |
327 SequencedSocketData data(reads, arraysize(reads), nullptr, 0); | |
328 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
329 | |
330 AddSSLSocketData(); | |
331 | |
332 CreateNetworkSession(); | |
333 CreateSecureSpdySession(); | |
334 | |
335 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
336 | |
337 // Read and process the GOAWAY frame. | |
338 base::RunLoop().RunUntilIdle(); | |
339 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
340 EXPECT_FALSE(session_); | |
341 } | |
342 | |
343 // A session receiving a GOAWAY frame immediately with no active | |
344 // streams should then close. | |
345 TEST_F(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) { | |
346 session_deps_.host_resolver->set_synchronous_mode(true); | |
347 | |
348 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1)); | |
349 MockRead reads[] = { | |
350 CreateMockRead(goaway, 0, SYNCHRONOUS), MockRead(ASYNC, 0, 1) // EOF | |
351 }; | |
352 SequencedSocketData data(reads, arraysize(reads), nullptr, 0); | |
353 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
354 | |
355 AddSSLSocketData(); | |
356 | |
357 CreateNetworkSession(); | |
358 | |
359 session_ = TryCreateSpdySessionExpectingFailure( | |
360 http_session_.get(), key_, ERR_CONNECTION_CLOSED, NetLogWithSource()); | |
361 base::RunLoop().RunUntilIdle(); | |
362 | |
363 EXPECT_FALSE(session_); | |
364 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
365 EXPECT_FALSE(data.AllReadDataConsumed()); | |
366 } | |
367 | |
368 // A session receiving a GOAWAY frame with active streams should close | |
369 // when the last active stream is closed. | |
370 TEST_F(SpdySessionTest, GoAwayWithActiveStreams) { | |
371 session_deps_.host_resolver->set_synchronous_mode(true); | |
372 | |
373 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1)); | |
374 MockRead reads[] = { | |
375 MockRead(ASYNC, ERR_IO_PENDING, 2), CreateMockRead(goaway, 3), | |
376 MockRead(ASYNC, ERR_IO_PENDING, 4), MockRead(ASYNC, 0, 5) // EOF | |
377 }; | |
378 SpdySerializedFrame req1( | |
379 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
380 SpdySerializedFrame req2( | |
381 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true)); | |
382 MockWrite writes[] = { | |
383 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
384 }; | |
385 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
386 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
387 | |
388 AddSSLSocketData(); | |
389 | |
390 CreateNetworkSession(); | |
391 CreateSecureSpdySession(); | |
392 | |
393 base::WeakPtr<SpdyStream> spdy_stream1 = | |
394 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
395 test_url_, MEDIUM, NetLogWithSource()); | |
396 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
397 spdy_stream1->SetDelegate(&delegate1); | |
398 | |
399 base::WeakPtr<SpdyStream> spdy_stream2 = | |
400 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
401 test_url_, MEDIUM, NetLogWithSource()); | |
402 test::StreamDelegateDoNothing delegate2(spdy_stream2); | |
403 spdy_stream2->SetDelegate(&delegate2); | |
404 | |
405 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
406 SpdyHeaderBlock headers2(headers.Clone()); | |
407 | |
408 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
409 spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
410 | |
411 base::RunLoop().RunUntilIdle(); | |
412 | |
413 EXPECT_EQ(1u, spdy_stream1->stream_id()); | |
414 EXPECT_EQ(3u, spdy_stream2->stream_id()); | |
415 | |
416 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
417 | |
418 // Read and process the GOAWAY frame. | |
419 data.Resume(); | |
420 base::RunLoop().RunUntilIdle(); | |
421 | |
422 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
423 | |
424 EXPECT_FALSE(session_->IsStreamActive(3)); | |
425 EXPECT_FALSE(spdy_stream2); | |
426 EXPECT_TRUE(session_->IsStreamActive(1)); | |
427 | |
428 EXPECT_TRUE(session_->IsGoingAway()); | |
429 | |
430 // Should close the session. | |
431 spdy_stream1->Close(); | |
432 EXPECT_FALSE(spdy_stream1); | |
433 | |
434 EXPECT_TRUE(session_); | |
435 data.Resume(); | |
436 base::RunLoop().RunUntilIdle(); | |
437 EXPECT_FALSE(session_); | |
438 } | |
439 | |
440 // Regression test for https://crbug.com/547130. | |
441 TEST_F(SpdySessionTest, GoAwayWithActiveAndCreatedStream) { | |
442 session_deps_.host_resolver->set_synchronous_mode(true); | |
443 | |
444 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(0)); | |
445 MockRead reads[] = { | |
446 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2), | |
447 }; | |
448 | |
449 // No |req2|, because the second stream will never get activated. | |
450 SpdySerializedFrame req1( | |
451 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
452 MockWrite writes[] = { | |
453 CreateMockWrite(req1, 0), | |
454 }; | |
455 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
456 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
457 | |
458 AddSSLSocketData(); | |
459 | |
460 CreateNetworkSession(); | |
461 CreateSecureSpdySession(); | |
462 | |
463 base::WeakPtr<SpdyStream> spdy_stream1 = | |
464 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
465 test_url_, MEDIUM, NetLogWithSource()); | |
466 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
467 spdy_stream1->SetDelegate(&delegate1); | |
468 SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
469 spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND); | |
470 | |
471 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
472 | |
473 // Active stream 1. | |
474 base::RunLoop().RunUntilIdle(); | |
475 EXPECT_EQ(1u, spdy_stream1->stream_id()); | |
476 EXPECT_TRUE(session_->IsStreamActive(1)); | |
477 | |
478 // Create stream corresponding to the next request. | |
479 base::WeakPtr<SpdyStream> spdy_stream2 = | |
480 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
481 test_url_, MEDIUM, NetLogWithSource()); | |
482 | |
483 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
484 | |
485 // Read and process the GOAWAY frame before the second stream could be | |
486 // activated. | |
487 data.Resume(); | |
488 base::RunLoop().RunUntilIdle(); | |
489 | |
490 EXPECT_FALSE(session_); | |
491 | |
492 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
493 EXPECT_TRUE(data.AllReadDataConsumed()); | |
494 } | |
495 | |
496 // Have a session receive two GOAWAY frames, with the last one causing | |
497 // the last active stream to be closed. The session should then be | |
498 // closed after the second GOAWAY frame. | |
499 TEST_F(SpdySessionTest, GoAwayTwice) { | |
500 session_deps_.host_resolver->set_synchronous_mode(true); | |
501 | |
502 SpdySerializedFrame goaway1(spdy_util_.ConstructSpdyGoAway(1)); | |
503 SpdySerializedFrame goaway2(spdy_util_.ConstructSpdyGoAway(0)); | |
504 MockRead reads[] = { | |
505 MockRead(ASYNC, ERR_IO_PENDING, 2), CreateMockRead(goaway1, 3), | |
506 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(goaway2, 5), | |
507 MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7) // EOF | |
508 }; | |
509 SpdySerializedFrame req1( | |
510 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
511 SpdySerializedFrame req2( | |
512 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true)); | |
513 MockWrite writes[] = { | |
514 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
515 }; | |
516 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
517 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
518 | |
519 AddSSLSocketData(); | |
520 | |
521 CreateNetworkSession(); | |
522 CreateSecureSpdySession(); | |
523 | |
524 base::WeakPtr<SpdyStream> spdy_stream1 = | |
525 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
526 test_url_, MEDIUM, NetLogWithSource()); | |
527 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
528 spdy_stream1->SetDelegate(&delegate1); | |
529 | |
530 base::WeakPtr<SpdyStream> spdy_stream2 = | |
531 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
532 test_url_, MEDIUM, NetLogWithSource()); | |
533 test::StreamDelegateDoNothing delegate2(spdy_stream2); | |
534 spdy_stream2->SetDelegate(&delegate2); | |
535 | |
536 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
537 SpdyHeaderBlock headers2(headers.Clone()); | |
538 | |
539 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
540 spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
541 | |
542 base::RunLoop().RunUntilIdle(); | |
543 | |
544 EXPECT_EQ(1u, spdy_stream1->stream_id()); | |
545 EXPECT_EQ(3u, spdy_stream2->stream_id()); | |
546 | |
547 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
548 | |
549 // Read and process the first GOAWAY frame. | |
550 data.Resume(); | |
551 base::RunLoop().RunUntilIdle(); | |
552 | |
553 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
554 | |
555 EXPECT_FALSE(session_->IsStreamActive(3)); | |
556 EXPECT_FALSE(spdy_stream2); | |
557 EXPECT_TRUE(session_->IsStreamActive(1)); | |
558 EXPECT_TRUE(session_->IsGoingAway()); | |
559 | |
560 // Read and process the second GOAWAY frame, which should close the | |
561 // session. | |
562 data.Resume(); | |
563 base::RunLoop().RunUntilIdle(); | |
564 EXPECT_FALSE(session_); | |
565 } | |
566 | |
567 // Have a session with active streams receive a GOAWAY frame and then | |
568 // close it. It should handle the close properly (i.e., not try to | |
569 // make itself unavailable in its pool twice). | |
570 TEST_F(SpdySessionTest, GoAwayWithActiveStreamsThenClose) { | |
571 session_deps_.host_resolver->set_synchronous_mode(true); | |
572 | |
573 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1)); | |
574 MockRead reads[] = { | |
575 MockRead(ASYNC, ERR_IO_PENDING, 2), CreateMockRead(goaway, 3), | |
576 MockRead(ASYNC, ERR_IO_PENDING, 4), MockRead(ASYNC, 0, 5) // EOF | |
577 }; | |
578 SpdySerializedFrame req1( | |
579 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
580 SpdySerializedFrame req2( | |
581 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true)); | |
582 MockWrite writes[] = { | |
583 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
584 }; | |
585 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
586 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
587 | |
588 AddSSLSocketData(); | |
589 | |
590 CreateNetworkSession(); | |
591 CreateSecureSpdySession(); | |
592 | |
593 base::WeakPtr<SpdyStream> spdy_stream1 = | |
594 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
595 test_url_, MEDIUM, NetLogWithSource()); | |
596 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
597 spdy_stream1->SetDelegate(&delegate1); | |
598 | |
599 base::WeakPtr<SpdyStream> spdy_stream2 = | |
600 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
601 test_url_, MEDIUM, NetLogWithSource()); | |
602 test::StreamDelegateDoNothing delegate2(spdy_stream2); | |
603 spdy_stream2->SetDelegate(&delegate2); | |
604 | |
605 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
606 SpdyHeaderBlock headers2(headers.Clone()); | |
607 | |
608 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
609 spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
610 | |
611 base::RunLoop().RunUntilIdle(); | |
612 | |
613 EXPECT_EQ(1u, spdy_stream1->stream_id()); | |
614 EXPECT_EQ(3u, spdy_stream2->stream_id()); | |
615 | |
616 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
617 | |
618 // Read and process the GOAWAY frame. | |
619 data.Resume(); | |
620 base::RunLoop().RunUntilIdle(); | |
621 | |
622 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
623 | |
624 EXPECT_FALSE(session_->IsStreamActive(3)); | |
625 EXPECT_FALSE(spdy_stream2); | |
626 EXPECT_TRUE(session_->IsStreamActive(1)); | |
627 EXPECT_TRUE(session_->IsGoingAway()); | |
628 | |
629 session_->CloseSessionOnError(ERR_ABORTED, "Aborting session"); | |
630 EXPECT_FALSE(spdy_stream1); | |
631 | |
632 data.Resume(); | |
633 base::RunLoop().RunUntilIdle(); | |
634 EXPECT_FALSE(session_); | |
635 } | |
636 | |
637 // Process a joint read buffer which causes the session to begin draining, and | |
638 // then processes a GOAWAY. The session should gracefully drain. Regression test | |
639 // for crbug.com/379469 | |
640 TEST_F(SpdySessionTest, GoAwayWhileDraining) { | |
641 session_deps_.host_resolver->set_synchronous_mode(true); | |
642 | |
643 SpdySerializedFrame req( | |
644 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
645 MockWrite writes[] = { | |
646 CreateMockWrite(req, 0), | |
647 }; | |
648 | |
649 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
650 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1)); | |
651 SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); | |
652 size_t joint_size = goaway.size() * 2 + body.size(); | |
653 | |
654 // Compose interleaved |goaway| and |body| frames into a single read. | |
655 std::unique_ptr<char[]> buffer(new char[joint_size]); | |
656 { | |
657 size_t out = 0; | |
658 memcpy(&buffer[out], goaway.data(), goaway.size()); | |
659 out += goaway.size(); | |
660 memcpy(&buffer[out], body.data(), body.size()); | |
661 out += body.size(); | |
662 memcpy(&buffer[out], goaway.data(), goaway.size()); | |
663 out += goaway.size(); | |
664 ASSERT_EQ(out, joint_size); | |
665 } | |
666 SpdySerializedFrame joint_frames(buffer.get(), joint_size, false); | |
667 | |
668 MockRead reads[] = { | |
669 CreateMockRead(resp, 1), CreateMockRead(joint_frames, 2), | |
670 MockRead(ASYNC, 0, 3) // EOF | |
671 }; | |
672 | |
673 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
674 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
675 | |
676 AddSSLSocketData(); | |
677 | |
678 CreateNetworkSession(); | |
679 CreateSecureSpdySession(); | |
680 | |
681 base::WeakPtr<SpdyStream> spdy_stream = | |
682 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
683 test_url_, MEDIUM, NetLogWithSource()); | |
684 test::StreamDelegateDoNothing delegate(spdy_stream); | |
685 spdy_stream->SetDelegate(&delegate); | |
686 | |
687 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
688 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
689 | |
690 base::RunLoop().RunUntilIdle(); | |
691 | |
692 // Stream and session closed gracefully. | |
693 EXPECT_TRUE(delegate.StreamIsClosed()); | |
694 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
695 EXPECT_EQ(kUploadData, delegate.TakeReceivedData()); | |
696 EXPECT_FALSE(session_); | |
697 } | |
698 | |
699 // Try to create a stream after receiving a GOAWAY frame. It should | |
700 // fail. | |
701 TEST_F(SpdySessionTest, CreateStreamAfterGoAway) { | |
702 session_deps_.host_resolver->set_synchronous_mode(true); | |
703 | |
704 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1)); | |
705 MockRead reads[] = { | |
706 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2), | |
707 MockRead(ASYNC, ERR_IO_PENDING, 3), MockRead(ASYNC, 0, 4) // EOF | |
708 }; | |
709 SpdySerializedFrame req( | |
710 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
711 MockWrite writes[] = { | |
712 CreateMockWrite(req, 0), | |
713 }; | |
714 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
715 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
716 | |
717 AddSSLSocketData(); | |
718 | |
719 CreateNetworkSession(); | |
720 CreateSecureSpdySession(); | |
721 | |
722 base::WeakPtr<SpdyStream> spdy_stream = | |
723 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
724 test_url_, MEDIUM, NetLogWithSource()); | |
725 test::StreamDelegateDoNothing delegate(spdy_stream); | |
726 spdy_stream->SetDelegate(&delegate); | |
727 | |
728 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
729 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
730 | |
731 base::RunLoop().RunUntilIdle(); | |
732 | |
733 EXPECT_EQ(1u, spdy_stream->stream_id()); | |
734 | |
735 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
736 | |
737 // Read and process the GOAWAY frame. | |
738 data.Resume(); | |
739 base::RunLoop().RunUntilIdle(); | |
740 | |
741 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
742 EXPECT_TRUE(session_->IsStreamActive(1)); | |
743 | |
744 SpdyStreamRequest stream_request; | |
745 int rv = stream_request.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
746 test_url_, MEDIUM, NetLogWithSource(), | |
747 CompletionCallback()); | |
748 EXPECT_THAT(rv, IsError(ERR_FAILED)); | |
749 | |
750 EXPECT_TRUE(session_); | |
751 data.Resume(); | |
752 base::RunLoop().RunUntilIdle(); | |
753 EXPECT_FALSE(session_); | |
754 } | |
755 | |
756 // Receiving a HEADERS frame after a GOAWAY frame should result in | |
757 // the stream being refused. | |
758 TEST_F(SpdySessionTest, HeadersAfterGoAway) { | |
759 session_deps_.host_resolver->set_synchronous_mode(true); | |
760 | |
761 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1)); | |
762 SpdySerializedFrame push( | |
763 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kDefaultUrl)); | |
764 MockRead reads[] = { | |
765 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2), | |
766 MockRead(ASYNC, ERR_IO_PENDING, 3), CreateMockRead(push, 4), | |
767 MockRead(ASYNC, 0, 6) // EOF | |
768 }; | |
769 SpdySerializedFrame req( | |
770 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
771 SpdySerializedFrame rst( | |
772 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM)); | |
773 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 5)}; | |
774 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
775 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
776 | |
777 AddSSLSocketData(); | |
778 | |
779 CreateNetworkSession(); | |
780 CreateSecureSpdySession(); | |
781 | |
782 base::WeakPtr<SpdyStream> spdy_stream = | |
783 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
784 test_url_, MEDIUM, NetLogWithSource()); | |
785 test::StreamDelegateDoNothing delegate(spdy_stream); | |
786 spdy_stream->SetDelegate(&delegate); | |
787 | |
788 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
789 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
790 | |
791 base::RunLoop().RunUntilIdle(); | |
792 | |
793 EXPECT_EQ(1u, spdy_stream->stream_id()); | |
794 | |
795 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
796 | |
797 // Read and process the GOAWAY frame. | |
798 data.Resume(); | |
799 base::RunLoop().RunUntilIdle(); | |
800 | |
801 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
802 EXPECT_TRUE(session_->IsStreamActive(1)); | |
803 | |
804 // Read and process the HEADERS frame, the subsequent RST_STREAM, | |
805 // and EOF. | |
806 data.Resume(); | |
807 base::RunLoop().RunUntilIdle(); | |
808 EXPECT_FALSE(session_); | |
809 } | |
810 | |
811 // A session observing a network change with active streams should close | |
812 // when the last active stream is closed. | |
813 TEST_F(SpdySessionTest, NetworkChangeWithActiveStreams) { | |
814 session_deps_.host_resolver->set_synchronous_mode(true); | |
815 | |
816 MockRead reads[] = { | |
817 MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2) // EOF | |
818 }; | |
819 SpdySerializedFrame req1( | |
820 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
821 MockWrite writes[] = { | |
822 CreateMockWrite(req1, 0), | |
823 }; | |
824 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
825 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
826 | |
827 AddSSLSocketData(); | |
828 | |
829 CreateNetworkSession(); | |
830 CreateSecureSpdySession(); | |
831 | |
832 base::WeakPtr<SpdyStream> spdy_stream = | |
833 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
834 test_url_, MEDIUM, NetLogWithSource()); | |
835 test::StreamDelegateDoNothing delegate(spdy_stream); | |
836 spdy_stream->SetDelegate(&delegate); | |
837 | |
838 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
839 | |
840 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
841 | |
842 base::RunLoop().RunUntilIdle(); | |
843 | |
844 EXPECT_EQ(1u, spdy_stream->stream_id()); | |
845 | |
846 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
847 | |
848 spdy_session_pool_->OnIPAddressChanged(); | |
849 | |
850 // The SpdySessionPool behavior differs based on how the OSs reacts to | |
851 // network changes; see comment in SpdySessionPool::OnIPAddressChanged(). | |
852 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) | |
853 // For OSs where the TCP connections will close upon relevant network | |
854 // changes, SpdySessionPool doesn't need to force them to close, so in these | |
855 // cases verify the session has become unavailable but remains open and the | |
856 // pre-existing stream is still active. | |
857 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
858 | |
859 EXPECT_TRUE(session_->IsGoingAway()); | |
860 | |
861 EXPECT_TRUE(session_->IsStreamActive(1)); | |
862 | |
863 // Should close the session. | |
864 spdy_stream->Close(); | |
865 #endif | |
866 EXPECT_FALSE(spdy_stream); | |
867 | |
868 data.Resume(); | |
869 base::RunLoop().RunUntilIdle(); | |
870 EXPECT_FALSE(session_); | |
871 } | |
872 | |
873 TEST_F(SpdySessionTest, ClientPing) { | |
874 session_deps_.enable_ping = true; | |
875 session_deps_.host_resolver->set_synchronous_mode(true); | |
876 | |
877 SpdySerializedFrame read_ping(spdy_util_.ConstructSpdyPing(1, true)); | |
878 MockRead reads[] = { | |
879 CreateMockRead(read_ping, 1), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
880 MockRead(ASYNC, 0, 3) // EOF | |
881 }; | |
882 SpdySerializedFrame write_ping(spdy_util_.ConstructSpdyPing(1, false)); | |
883 MockWrite writes[] = { | |
884 CreateMockWrite(write_ping, 0), | |
885 }; | |
886 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
887 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
888 | |
889 AddSSLSocketData(); | |
890 | |
891 CreateNetworkSession(); | |
892 CreateSecureSpdySession(); | |
893 | |
894 base::WeakPtr<SpdyStream> spdy_stream1 = | |
895 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
896 MEDIUM, NetLogWithSource()); | |
897 ASSERT_TRUE(spdy_stream1); | |
898 test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr); | |
899 spdy_stream1->SetDelegate(&delegate); | |
900 | |
901 base::TimeTicks before_ping_time = base::TimeTicks::Now(); | |
902 | |
903 session_->set_connection_at_risk_of_loss_time( | |
904 base::TimeDelta::FromSeconds(-1)); | |
905 session_->set_hung_interval(base::TimeDelta::FromMilliseconds(50)); | |
906 | |
907 session_->SendPrefacePingIfNoneInFlight(); | |
908 | |
909 base::RunLoop().RunUntilIdle(); | |
910 | |
911 session_->CheckPingStatus(before_ping_time); | |
912 | |
913 EXPECT_EQ(0, session_->pings_in_flight()); | |
914 EXPECT_GE(session_->next_ping_id(), 1U); | |
915 EXPECT_FALSE(session_->check_ping_status_pending()); | |
916 EXPECT_GE(session_->last_activity_time(), before_ping_time); | |
917 | |
918 data.Resume(); | |
919 base::RunLoop().RunUntilIdle(); | |
920 | |
921 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
922 | |
923 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
924 EXPECT_FALSE(session_); | |
925 } | |
926 | |
927 TEST_F(SpdySessionTest, ServerPing) { | |
928 session_deps_.host_resolver->set_synchronous_mode(true); | |
929 | |
930 SpdySerializedFrame read_ping(spdy_util_.ConstructSpdyPing(2, false)); | |
931 MockRead reads[] = { | |
932 CreateMockRead(read_ping), MockRead(SYNCHRONOUS, 0, 0) // EOF | |
933 }; | |
934 SpdySerializedFrame write_ping(spdy_util_.ConstructSpdyPing(2, true)); | |
935 MockWrite writes[] = { | |
936 CreateMockWrite(write_ping), | |
937 }; | |
938 StaticSocketDataProvider data( | |
939 reads, arraysize(reads), writes, arraysize(writes)); | |
940 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
941 | |
942 AddSSLSocketData(); | |
943 | |
944 CreateNetworkSession(); | |
945 CreateSecureSpdySession(); | |
946 | |
947 base::WeakPtr<SpdyStream> spdy_stream1 = | |
948 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
949 MEDIUM, NetLogWithSource()); | |
950 ASSERT_TRUE(spdy_stream1); | |
951 test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr); | |
952 spdy_stream1->SetDelegate(&delegate); | |
953 | |
954 // Flush the read completion task. | |
955 base::RunLoop().RunUntilIdle(); | |
956 | |
957 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
958 | |
959 EXPECT_FALSE(session_); | |
960 EXPECT_FALSE(spdy_stream1); | |
961 } | |
962 | |
963 // Cause a ping to be sent out while producing a write. The write loop | |
964 // should handle this properly, i.e. another DoWriteLoop task should | |
965 // not be posted. This is a regression test for | |
966 // http://crbug.com/261043 . | |
967 TEST_F(SpdySessionTest, PingAndWriteLoop) { | |
968 session_deps_.enable_ping = true; | |
969 session_deps_.time_func = TheNearFuture; | |
970 | |
971 SpdySerializedFrame write_ping(spdy_util_.ConstructSpdyPing(1, false)); | |
972 SpdySerializedFrame req( | |
973 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
974 MockWrite writes[] = { | |
975 CreateMockWrite(req, 0), CreateMockWrite(write_ping, 1), | |
976 }; | |
977 | |
978 MockRead reads[] = { | |
979 MockRead(ASYNC, ERR_IO_PENDING, 2), MockRead(ASYNC, 0, 3) // EOF | |
980 }; | |
981 | |
982 session_deps_.host_resolver->set_synchronous_mode(true); | |
983 | |
984 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
985 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
986 | |
987 AddSSLSocketData(); | |
988 | |
989 CreateNetworkSession(); | |
990 CreateSecureSpdySession(); | |
991 | |
992 base::WeakPtr<SpdyStream> spdy_stream = | |
993 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
994 test_url_, LOWEST, NetLogWithSource()); | |
995 test::StreamDelegateDoNothing delegate(spdy_stream); | |
996 spdy_stream->SetDelegate(&delegate); | |
997 | |
998 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
999 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
1000 | |
1001 // Shift time so that a ping will be sent out. | |
1002 g_time_delta = base::TimeDelta::FromSeconds(11); | |
1003 | |
1004 base::RunLoop().RunUntilIdle(); | |
1005 session_->CloseSessionOnError(ERR_ABORTED, "Aborting"); | |
1006 | |
1007 data.Resume(); | |
1008 base::RunLoop().RunUntilIdle(); | |
1009 EXPECT_FALSE(session_); | |
1010 } | |
1011 | |
1012 TEST_F(SpdySessionTest, StreamIdSpaceExhausted) { | |
1013 const SpdyStreamId kLastStreamId = 0x7fffffff; | |
1014 session_deps_.host_resolver->set_synchronous_mode(true); | |
1015 | |
1016 // Test setup: |stream_hi_water_mark_| and |max_concurrent_streams_| are | |
1017 // fixed to allow for two stream ID assignments, and three concurrent | |
1018 // streams. Four streams are started, and two are activated. Verify the | |
1019 // session goes away, and that the created (but not activated) and | |
1020 // stalled streams are aborted. Also verify the activated streams complete, | |
1021 // at which point the session closes. | |
1022 | |
1023 SpdySerializedFrame req1( | |
1024 spdy_util_.ConstructSpdyGet(nullptr, 0, kLastStreamId - 2, MEDIUM, true)); | |
1025 SpdySerializedFrame req2( | |
1026 spdy_util_.ConstructSpdyGet(nullptr, 0, kLastStreamId, MEDIUM, true)); | |
1027 | |
1028 MockWrite writes[] = { | |
1029 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
1030 }; | |
1031 | |
1032 SpdySerializedFrame resp1( | |
1033 spdy_util_.ConstructSpdyGetReply(nullptr, 0, kLastStreamId - 2)); | |
1034 SpdySerializedFrame resp2( | |
1035 spdy_util_.ConstructSpdyGetReply(nullptr, 0, kLastStreamId)); | |
1036 | |
1037 SpdySerializedFrame body1( | |
1038 spdy_util_.ConstructSpdyDataFrame(kLastStreamId - 2, true)); | |
1039 SpdySerializedFrame body2( | |
1040 spdy_util_.ConstructSpdyDataFrame(kLastStreamId, true)); | |
1041 | |
1042 MockRead reads[] = { | |
1043 CreateMockRead(resp1, 2), CreateMockRead(resp2, 3), | |
1044 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(body1, 5), | |
1045 CreateMockRead(body2, 6), MockRead(ASYNC, 0, 7) // EOF | |
1046 }; | |
1047 | |
1048 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
1049 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1050 | |
1051 AddSSLSocketData(); | |
1052 | |
1053 CreateNetworkSession(); | |
1054 CreateSecureSpdySession(); | |
1055 | |
1056 // Fix stream_hi_water_mark_ to allow for two stream activations. | |
1057 session_->stream_hi_water_mark_ = kLastStreamId - 2; | |
1058 // Fix max_concurrent_streams to allow for three stream creations. | |
1059 session_->max_concurrent_streams_ = 3; | |
1060 | |
1061 // Create three streams synchronously, and begin a fourth (which is stalled). | |
1062 base::WeakPtr<SpdyStream> stream1 = | |
1063 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1064 test_url_, MEDIUM, NetLogWithSource()); | |
1065 test::StreamDelegateDoNothing delegate1(stream1); | |
1066 stream1->SetDelegate(&delegate1); | |
1067 | |
1068 base::WeakPtr<SpdyStream> stream2 = | |
1069 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1070 test_url_, MEDIUM, NetLogWithSource()); | |
1071 test::StreamDelegateDoNothing delegate2(stream2); | |
1072 stream2->SetDelegate(&delegate2); | |
1073 | |
1074 base::WeakPtr<SpdyStream> stream3 = | |
1075 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1076 test_url_, MEDIUM, NetLogWithSource()); | |
1077 test::StreamDelegateDoNothing delegate3(stream3); | |
1078 stream3->SetDelegate(&delegate3); | |
1079 | |
1080 SpdyStreamRequest request4; | |
1081 TestCompletionCallback callback4; | |
1082 EXPECT_EQ( | |
1083 ERR_IO_PENDING, | |
1084 request4.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, | |
1085 MEDIUM, NetLogWithSource(), callback4.callback())); | |
1086 | |
1087 // Streams 1-3 were created. 4th is stalled. No streams are active yet. | |
1088 EXPECT_EQ(0u, session_->num_active_streams()); | |
1089 EXPECT_EQ(3u, session_->num_created_streams()); | |
1090 EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1091 | |
1092 // Activate stream 1. One ID remains available. | |
1093 stream1->SendRequestHeaders(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl), | |
1094 NO_MORE_DATA_TO_SEND); | |
1095 base::RunLoop().RunUntilIdle(); | |
1096 | |
1097 EXPECT_EQ(kLastStreamId - 2u, stream1->stream_id()); | |
1098 EXPECT_EQ(1u, session_->num_active_streams()); | |
1099 EXPECT_EQ(2u, session_->num_created_streams()); | |
1100 EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1101 | |
1102 // Activate stream 2. ID space is exhausted. | |
1103 stream2->SendRequestHeaders(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl), | |
1104 NO_MORE_DATA_TO_SEND); | |
1105 base::RunLoop().RunUntilIdle(); | |
1106 | |
1107 // Active streams remain active. | |
1108 EXPECT_EQ(kLastStreamId, stream2->stream_id()); | |
1109 EXPECT_EQ(2u, session_->num_active_streams()); | |
1110 | |
1111 // Session is going away. Created and stalled streams were aborted. | |
1112 EXPECT_EQ(SpdySession::STATE_GOING_AWAY, session_->availability_state_); | |
1113 EXPECT_THAT(delegate3.WaitForClose(), IsError(ERR_ABORTED)); | |
1114 EXPECT_THAT(callback4.WaitForResult(), IsError(ERR_ABORTED)); | |
1115 EXPECT_EQ(0u, session_->num_created_streams()); | |
1116 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1117 | |
1118 // Read responses on remaining active streams. | |
1119 data.Resume(); | |
1120 base::RunLoop().RunUntilIdle(); | |
1121 EXPECT_THAT(delegate1.WaitForClose(), IsOk()); | |
1122 EXPECT_EQ(kUploadData, delegate1.TakeReceivedData()); | |
1123 EXPECT_THAT(delegate2.WaitForClose(), IsOk()); | |
1124 EXPECT_EQ(kUploadData, delegate2.TakeReceivedData()); | |
1125 | |
1126 // Session was destroyed. | |
1127 EXPECT_FALSE(session_); | |
1128 } | |
1129 | |
1130 // Regression test for https://crbug.com/481009. | |
1131 TEST_F(SpdySessionTest, MaxConcurrentStreamsZero) { | |
1132 session_deps_.host_resolver->set_synchronous_mode(true); | |
1133 | |
1134 // Receive SETTINGS frame that sets max_concurrent_streams to zero. | |
1135 SettingsMap settings_zero; | |
1136 settings_zero[SETTINGS_MAX_CONCURRENT_STREAMS] = 0; | |
1137 SpdySerializedFrame settings_frame_zero( | |
1138 spdy_util_.ConstructSpdySettings(settings_zero)); | |
1139 | |
1140 // Acknowledge it. | |
1141 SpdySerializedFrame settings_ack0(spdy_util_.ConstructSpdySettingsAck()); | |
1142 | |
1143 // Receive SETTINGS frame that sets max_concurrent_streams to one. | |
1144 SettingsMap settings_one; | |
1145 settings_one[SETTINGS_MAX_CONCURRENT_STREAMS] = 1; | |
1146 SpdySerializedFrame settings_frame_one( | |
1147 spdy_util_.ConstructSpdySettings(settings_one)); | |
1148 | |
1149 // Acknowledge it. | |
1150 SpdySerializedFrame settings_ack1(spdy_util_.ConstructSpdySettingsAck()); | |
1151 | |
1152 // Request and response. | |
1153 SpdySerializedFrame req( | |
1154 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
1155 | |
1156 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
1157 | |
1158 SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); | |
1159 | |
1160 MockRead reads[] = {CreateMockRead(settings_frame_zero, 0), | |
1161 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
1162 CreateMockRead(settings_frame_one, 3), | |
1163 CreateMockRead(resp, 6), | |
1164 CreateMockRead(body, 7), | |
1165 MockRead(ASYNC, 0, 8)}; | |
1166 | |
1167 MockWrite writes[] = {CreateMockWrite(settings_ack0, 1), | |
1168 CreateMockWrite(settings_ack1, 4), | |
1169 CreateMockWrite(req, 5)}; | |
1170 | |
1171 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
1172 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1173 | |
1174 AddSSLSocketData(); | |
1175 | |
1176 // Create session. | |
1177 CreateNetworkSession(); | |
1178 CreateSecureSpdySession(); | |
1179 | |
1180 // Receive SETTINGS frame that sets max_concurrent_streams to zero. | |
1181 base::RunLoop().RunUntilIdle(); | |
1182 EXPECT_EQ(0u, session_->max_concurrent_streams_); | |
1183 | |
1184 // Start request. | |
1185 SpdyStreamRequest request; | |
1186 TestCompletionCallback callback; | |
1187 int rv = | |
1188 request.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, | |
1189 MEDIUM, NetLogWithSource(), callback.callback()); | |
1190 EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); | |
1191 | |
1192 // Stream is stalled. | |
1193 EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1194 EXPECT_EQ(0u, session_->num_created_streams()); | |
1195 | |
1196 // Receive SETTINGS frame that sets max_concurrent_streams to one. | |
1197 data.Resume(); | |
1198 base::RunLoop().RunUntilIdle(); | |
1199 EXPECT_EQ(1u, session_->max_concurrent_streams_); | |
1200 | |
1201 // Stream is created. | |
1202 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1203 EXPECT_EQ(1u, session_->num_created_streams()); | |
1204 | |
1205 EXPECT_THAT(callback.WaitForResult(), IsOk()); | |
1206 | |
1207 // Send request. | |
1208 base::WeakPtr<SpdyStream> stream = request.ReleaseStream(); | |
1209 test::StreamDelegateDoNothing delegate(stream); | |
1210 stream->SetDelegate(&delegate); | |
1211 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1212 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
1213 | |
1214 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
1215 EXPECT_EQ("hello!", delegate.TakeReceivedData()); | |
1216 | |
1217 // Finish async network reads/writes. | |
1218 base::RunLoop().RunUntilIdle(); | |
1219 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1220 EXPECT_TRUE(data.AllReadDataConsumed()); | |
1221 | |
1222 // Session is destroyed. | |
1223 EXPECT_FALSE(session_); | |
1224 } | |
1225 | |
1226 // Verifies that an unstalled pending stream creation racing with a new stream | |
1227 // creation doesn't violate the maximum stream concurrency. Regression test for | |
1228 // crbug.com/373858. | |
1229 TEST_F(SpdySessionTest, UnstallRacesWithStreamCreation) { | |
1230 session_deps_.host_resolver->set_synchronous_mode(true); | |
1231 | |
1232 MockRead reads[] = { | |
1233 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
1234 }; | |
1235 | |
1236 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
1237 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1238 | |
1239 AddSSLSocketData(); | |
1240 | |
1241 CreateNetworkSession(); | |
1242 CreateSecureSpdySession(); | |
1243 | |
1244 // Fix max_concurrent_streams to allow for one open stream. | |
1245 session_->max_concurrent_streams_ = 1; | |
1246 | |
1247 // Create two streams: one synchronously, and one which stalls. | |
1248 base::WeakPtr<SpdyStream> stream1 = | |
1249 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1250 test_url_, MEDIUM, NetLogWithSource()); | |
1251 | |
1252 SpdyStreamRequest request2; | |
1253 TestCompletionCallback callback2; | |
1254 EXPECT_EQ( | |
1255 ERR_IO_PENDING, | |
1256 request2.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, | |
1257 MEDIUM, NetLogWithSource(), callback2.callback())); | |
1258 | |
1259 EXPECT_EQ(1u, session_->num_created_streams()); | |
1260 EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1261 | |
1262 // Cancel the first stream. A callback to unstall the second stream was | |
1263 // posted. Don't run it yet. | |
1264 stream1->Cancel(); | |
1265 | |
1266 EXPECT_EQ(0u, session_->num_created_streams()); | |
1267 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1268 | |
1269 // Create a third stream prior to the second stream's callback. | |
1270 base::WeakPtr<SpdyStream> stream3 = | |
1271 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1272 test_url_, MEDIUM, NetLogWithSource()); | |
1273 | |
1274 EXPECT_EQ(1u, session_->num_created_streams()); | |
1275 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1276 | |
1277 // Now run the message loop. The unstalled stream will re-stall itself. | |
1278 base::RunLoop().RunUntilIdle(); | |
1279 EXPECT_EQ(1u, session_->num_created_streams()); | |
1280 EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1281 | |
1282 // Cancel the third stream and run the message loop. Verify that the second | |
1283 // stream creation now completes. | |
1284 stream3->Cancel(); | |
1285 base::RunLoop().RunUntilIdle(); | |
1286 | |
1287 EXPECT_EQ(1u, session_->num_created_streams()); | |
1288 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); | |
1289 EXPECT_THAT(callback2.WaitForResult(), IsOk()); | |
1290 } | |
1291 | |
1292 TEST_F(SpdySessionTest, CancelPushAfterSessionGoesAway) { | |
1293 base::HistogramTester histogram_tester; | |
1294 session_deps_.host_resolver->set_synchronous_mode(true); | |
1295 session_deps_.time_func = TheNearFuture; | |
1296 | |
1297 SpdySerializedFrame req( | |
1298 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
1299 SpdySerializedFrame priority_a( | |
1300 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
1301 SpdySerializedFrame priority_b( | |
1302 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true)); | |
1303 SpdySerializedFrame rst_a( | |
1304 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM)); | |
1305 MockWrite writes[] = { | |
1306 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 2), | |
1307 CreateMockWrite(priority_b, 6), CreateMockWrite(rst_a, 7), | |
1308 }; | |
1309 | |
1310 SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( | |
1311 nullptr, 0, 2, 1, "https://www.example.org/a.dat")); | |
1312 SpdySerializedFrame push_a_body(spdy_util_.ConstructSpdyDataFrame(2, false)); | |
1313 // In ascii "0" < "a". We use it to verify that we properly handle std::map | |
1314 // iterators inside. See http://crbug.com/443490 | |
1315 SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush( | |
1316 nullptr, 0, 4, 1, "https://www.example.org/0.dat")); | |
1317 MockRead reads[] = { | |
1318 CreateMockRead(push_a, 1), CreateMockRead(push_a_body, 3), | |
1319 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(push_b, 5), | |
1320 MockRead(ASYNC, ERR_IO_PENDING, 8), MockRead(ASYNC, 0, 9) // EOF | |
1321 }; | |
1322 | |
1323 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
1324 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1325 | |
1326 AddSSLSocketData(); | |
1327 | |
1328 CreateNetworkSession(); | |
1329 CreateSecureSpdySession(); | |
1330 | |
1331 // Process the principal request, and the first push stream request & body. | |
1332 base::WeakPtr<SpdyStream> spdy_stream = | |
1333 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1334 test_url_, MEDIUM, NetLogWithSource()); | |
1335 test::StreamDelegateDoNothing delegate(spdy_stream); | |
1336 spdy_stream->SetDelegate(&delegate); | |
1337 | |
1338 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1339 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
1340 | |
1341 base::RunLoop().RunUntilIdle(); | |
1342 | |
1343 // Verify that there is one unclaimed push stream. | |
1344 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1345 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1346 GURL("https://www.example.org/a.dat"))); | |
1347 | |
1348 // Unclaimed push body consumed bytes from the session window. | |
1349 EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, | |
1350 session_->session_recv_window_size_); | |
1351 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
1352 | |
1353 // Shift time to expire the push stream. Read the second HEADERS, | |
1354 // and verify a RST_STREAM was written. | |
1355 g_time_delta = base::TimeDelta::FromSeconds(301); | |
1356 data.Resume(); | |
1357 base::RunLoop().RunUntilIdle(); | |
1358 | |
1359 // Verify that the second pushed stream evicted the first pushed stream. | |
1360 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1361 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1362 GURL("https://www.example.org/0.dat"))); | |
1363 | |
1364 // Verify that the session window reclaimed the evicted stream body. | |
1365 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
1366 EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); | |
1367 EXPECT_TRUE(session_); | |
1368 | |
1369 // Read and process EOF. | |
1370 data.Resume(); | |
1371 base::RunLoop().RunUntilIdle(); | |
1372 | |
1373 // Cancel the first push after session goes away. Verify the test doesn't | |
1374 // crash. | |
1375 EXPECT_FALSE(session_); | |
1376 EXPECT_TRUE( | |
1377 test_push_delegate_->CancelPush(GURL("https://www.example.org/a.dat"))); | |
1378 | |
1379 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedBytes", 6, 1); | |
1380 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedAndUnclaimedBytes", | |
1381 6, 1); | |
1382 } | |
1383 | |
1384 TEST_F(SpdySessionTest, CancelPushAfterExpired) { | |
1385 base::HistogramTester histogram_tester; | |
1386 session_deps_.host_resolver->set_synchronous_mode(true); | |
1387 session_deps_.time_func = TheNearFuture; | |
1388 | |
1389 SpdySerializedFrame req( | |
1390 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
1391 SpdySerializedFrame priority_a( | |
1392 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
1393 SpdySerializedFrame priority_b( | |
1394 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true)); | |
1395 SpdySerializedFrame rst_a( | |
1396 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM)); | |
1397 MockWrite writes[] = { | |
1398 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 2), | |
1399 CreateMockWrite(priority_b, 6), CreateMockWrite(rst_a, 7), | |
1400 }; | |
1401 | |
1402 SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( | |
1403 nullptr, 0, 2, 1, "https://www.example.org/a.dat")); | |
1404 SpdySerializedFrame push_a_body(spdy_util_.ConstructSpdyDataFrame(2, false)); | |
1405 // In ascii "0" < "a". We use it to verify that we properly handle std::map | |
1406 // iterators inside. See http://crbug.com/443490 | |
1407 SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush( | |
1408 nullptr, 0, 4, 1, "https://www.example.org/0.dat")); | |
1409 MockRead reads[] = { | |
1410 CreateMockRead(push_a, 1), CreateMockRead(push_a_body, 3), | |
1411 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(push_b, 5), | |
1412 MockRead(ASYNC, ERR_IO_PENDING, 8), MockRead(ASYNC, 0, 9) // EOF | |
1413 }; | |
1414 | |
1415 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
1416 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1417 | |
1418 AddSSLSocketData(); | |
1419 | |
1420 CreateNetworkSession(); | |
1421 CreateSecureSpdySession(); | |
1422 | |
1423 // Process the principal request, and the first push stream request & body. | |
1424 base::WeakPtr<SpdyStream> spdy_stream = | |
1425 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1426 test_url_, MEDIUM, NetLogWithSource()); | |
1427 test::StreamDelegateDoNothing delegate(spdy_stream); | |
1428 spdy_stream->SetDelegate(&delegate); | |
1429 | |
1430 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1431 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
1432 | |
1433 base::RunLoop().RunUntilIdle(); | |
1434 | |
1435 // Verify that there is one unclaimed push stream. | |
1436 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1437 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1438 GURL("https://www.example.org/a.dat"))); | |
1439 | |
1440 // Unclaimed push body consumed bytes from the session window. | |
1441 EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, | |
1442 session_->session_recv_window_size_); | |
1443 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
1444 | |
1445 // Shift time to expire the push stream. Read the second HEADERS, | |
1446 // and verify a RST_STREAM was written. | |
1447 g_time_delta = base::TimeDelta::FromSeconds(301); | |
1448 data.Resume(); | |
1449 base::RunLoop().RunUntilIdle(); | |
1450 | |
1451 // Verify that the second pushed stream evicted the first pushed stream. | |
1452 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1453 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1454 GURL("https://www.example.org/0.dat"))); | |
1455 | |
1456 // Cancel the first push after its expiration. | |
1457 EXPECT_TRUE( | |
1458 test_push_delegate_->CancelPush(GURL("https://www.example.org/a.dat"))); | |
1459 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1460 EXPECT_TRUE(session_); | |
1461 | |
1462 // Verify that the session window reclaimed the evicted stream body. | |
1463 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
1464 EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); | |
1465 EXPECT_TRUE(session_); | |
1466 | |
1467 // Read and process EOF. | |
1468 data.Resume(); | |
1469 base::RunLoop().RunUntilIdle(); | |
1470 EXPECT_FALSE(session_); | |
1471 | |
1472 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedBytes", 6, 1); | |
1473 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedAndUnclaimedBytes", | |
1474 6, 1); | |
1475 } | |
1476 | |
1477 TEST_F(SpdySessionTest, CancelPushBeforeClaimed) { | |
1478 base::HistogramTester histogram_tester; | |
1479 session_deps_.host_resolver->set_synchronous_mode(true); | |
1480 session_deps_.time_func = TheNearFuture; | |
1481 | |
1482 SpdySerializedFrame req( | |
1483 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
1484 SpdySerializedFrame priority_a( | |
1485 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
1486 SpdySerializedFrame priority_b( | |
1487 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true)); | |
1488 SpdySerializedFrame rst_a( | |
1489 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM)); | |
1490 MockWrite writes[] = { | |
1491 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 2), | |
1492 CreateMockWrite(priority_b, 6), CreateMockWrite(rst_a, 7), | |
1493 }; | |
1494 | |
1495 SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( | |
1496 nullptr, 0, 2, 1, "https://www.example.org/a.dat")); | |
1497 SpdySerializedFrame push_a_body(spdy_util_.ConstructSpdyDataFrame(2, false)); | |
1498 // In ascii "0" < "a". We use it to verify that we properly handle std::map | |
1499 // iterators inside. See http://crbug.com/443490 | |
1500 SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush( | |
1501 nullptr, 0, 4, 1, "https://www.example.org/0.dat")); | |
1502 MockRead reads[] = { | |
1503 CreateMockRead(push_a, 1), CreateMockRead(push_a_body, 3), | |
1504 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(push_b, 5), | |
1505 MockRead(ASYNC, ERR_IO_PENDING, 8), MockRead(ASYNC, 0, 9) // EOF | |
1506 }; | |
1507 | |
1508 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
1509 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1510 | |
1511 AddSSLSocketData(); | |
1512 | |
1513 CreateNetworkSession(); | |
1514 CreateSecureSpdySession(); | |
1515 | |
1516 // Process the principal request, and the first push stream request & body. | |
1517 base::WeakPtr<SpdyStream> spdy_stream = | |
1518 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1519 test_url_, MEDIUM, NetLogWithSource()); | |
1520 test::StreamDelegateDoNothing delegate(spdy_stream); | |
1521 spdy_stream->SetDelegate(&delegate); | |
1522 | |
1523 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1524 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
1525 | |
1526 base::RunLoop().RunUntilIdle(); | |
1527 | |
1528 // Verify that there is one unclaimed push stream. | |
1529 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1530 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1531 GURL("https://www.example.org/a.dat"))); | |
1532 | |
1533 // Unclaimed push body consumed bytes from the session window. | |
1534 EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, | |
1535 session_->session_recv_window_size_); | |
1536 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
1537 | |
1538 // Shift time to expire the push stream. Read the second HEADERS, | |
1539 // and verify a RST_STREAM was written. | |
1540 g_time_delta = base::TimeDelta::FromSeconds(301); | |
1541 data.Resume(); | |
1542 base::RunLoop().RunUntilIdle(); | |
1543 | |
1544 // Verify that the second pushed stream evicted the first pushed stream. | |
1545 GURL pushed_url("https://www.example.org/0.dat"); | |
1546 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1547 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url(pushed_url)); | |
1548 | |
1549 // Verify that the session window reclaimed the evicted stream body. | |
1550 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
1551 EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); | |
1552 | |
1553 EXPECT_TRUE(session_); | |
1554 // Cancel the push before it's claimed. | |
1555 EXPECT_TRUE(test_push_delegate_->CancelPush(pushed_url)); | |
1556 EXPECT_EQ(0u, session_->num_unclaimed_pushed_streams()); | |
1557 EXPECT_EQ(0u, session_->count_unclaimed_pushed_streams_for_url(pushed_url)); | |
1558 | |
1559 // Read and process EOF. | |
1560 data.Resume(); | |
1561 base::RunLoop().RunUntilIdle(); | |
1562 EXPECT_FALSE(session_); | |
1563 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedBytes", 6, 1); | |
1564 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedAndUnclaimedBytes", | |
1565 6, 1); | |
1566 } | |
1567 | |
1568 TEST_F(SpdySessionTest, DeleteExpiredPushStreams) { | |
1569 base::HistogramTester histogram_tester; | |
1570 session_deps_.host_resolver->set_synchronous_mode(true); | |
1571 session_deps_.time_func = TheNearFuture; | |
1572 | |
1573 SpdySerializedFrame req( | |
1574 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
1575 SpdySerializedFrame priority_a( | |
1576 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
1577 SpdySerializedFrame priority_b( | |
1578 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true)); | |
1579 SpdySerializedFrame rst_a( | |
1580 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM)); | |
1581 MockWrite writes[] = { | |
1582 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 2), | |
1583 CreateMockWrite(priority_b, 6), CreateMockWrite(rst_a, 7), | |
1584 }; | |
1585 | |
1586 SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( | |
1587 nullptr, 0, 2, 1, "https://www.example.org/a.dat")); | |
1588 SpdySerializedFrame push_a_body(spdy_util_.ConstructSpdyDataFrame(2, false)); | |
1589 // In ascii "0" < "a". We use it to verify that we properly handle std::map | |
1590 // iterators inside. See http://crbug.com/443490 | |
1591 SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush( | |
1592 nullptr, 0, 4, 1, "https://www.example.org/0.dat")); | |
1593 MockRead reads[] = { | |
1594 CreateMockRead(push_a, 1), CreateMockRead(push_a_body, 3), | |
1595 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(push_b, 5), | |
1596 MockRead(ASYNC, ERR_IO_PENDING, 8), MockRead(ASYNC, 0, 9) // EOF | |
1597 }; | |
1598 | |
1599 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
1600 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1601 | |
1602 AddSSLSocketData(); | |
1603 | |
1604 CreateNetworkSession(); | |
1605 CreateSecureSpdySession(); | |
1606 | |
1607 // Process the principal request, and the first push stream request & body. | |
1608 base::WeakPtr<SpdyStream> spdy_stream = | |
1609 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1610 test_url_, MEDIUM, NetLogWithSource()); | |
1611 test::StreamDelegateDoNothing delegate(spdy_stream); | |
1612 spdy_stream->SetDelegate(&delegate); | |
1613 | |
1614 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1615 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
1616 | |
1617 base::RunLoop().RunUntilIdle(); | |
1618 | |
1619 // Verify that there is one unclaimed push stream. | |
1620 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1621 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1622 GURL("https://www.example.org/a.dat"))); | |
1623 | |
1624 // Unclaimed push body consumed bytes from the session window. | |
1625 EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, | |
1626 session_->session_recv_window_size_); | |
1627 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
1628 | |
1629 // Shift time to expire the push stream. Read the second HEADERS, | |
1630 // and verify a RST_STREAM was written. | |
1631 g_time_delta = base::TimeDelta::FromSeconds(301); | |
1632 data.Resume(); | |
1633 base::RunLoop().RunUntilIdle(); | |
1634 | |
1635 // Verify that the second pushed stream evicted the first pushed stream. | |
1636 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1637 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1638 GURL("https://www.example.org/0.dat"))); | |
1639 | |
1640 // Verify that the session window reclaimed the evicted stream body. | |
1641 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
1642 EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); | |
1643 | |
1644 // Read and process EOF. | |
1645 EXPECT_TRUE(session_); | |
1646 data.Resume(); | |
1647 base::RunLoop().RunUntilIdle(); | |
1648 EXPECT_FALSE(session_); | |
1649 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedBytes", 6, 1); | |
1650 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedAndUnclaimedBytes", | |
1651 6, 1); | |
1652 } | |
1653 | |
1654 TEST_F(SpdySessionTest, MetricsCollectionOnPushStreams) { | |
1655 base::HistogramTester histogram_tester; | |
1656 session_deps_.host_resolver->set_synchronous_mode(true); | |
1657 session_deps_.time_func = TheNearFuture; | |
1658 | |
1659 SpdySerializedFrame req( | |
1660 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
1661 SpdySerializedFrame priority_a( | |
1662 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
1663 SpdySerializedFrame priority_b( | |
1664 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true)); | |
1665 SpdySerializedFrame priority_c( | |
1666 spdy_util_.ConstructSpdyPriority(6, 4, IDLE, true)); | |
1667 SpdySerializedFrame rst_a( | |
1668 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM)); | |
1669 MockWrite writes[] = { | |
1670 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 2), | |
1671 CreateMockWrite(priority_b, 6), CreateMockWrite(rst_a, 7), | |
1672 CreateMockWrite(priority_c, 10), | |
1673 }; | |
1674 | |
1675 SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( | |
1676 nullptr, 0, 2, 1, "https://www.example.org/a.dat")); | |
1677 SpdySerializedFrame push_a_body(spdy_util_.ConstructSpdyDataFrame(2, false)); | |
1678 // In ascii "0" < "a". We use it to verify that we properly handle std::map | |
1679 // iterators inside. See http://crbug.com/443490 | |
1680 SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush( | |
1681 nullptr, 0, 4, 1, "https://www.example.org/0.dat")); | |
1682 SpdySerializedFrame push_c(spdy_util_.ConstructSpdyPush( | |
1683 nullptr, 0, 6, 1, "https://www.example.org/1.dat")); | |
1684 SpdySerializedFrame push_c_body(spdy_util_.ConstructSpdyDataFrame(6, false)); | |
1685 | |
1686 MockRead reads[] = { | |
1687 CreateMockRead(push_a, 1), | |
1688 CreateMockRead(push_a_body, 3), | |
1689 MockRead(ASYNC, ERR_IO_PENDING, 4), | |
1690 CreateMockRead(push_b, 5), | |
1691 MockRead(ASYNC, ERR_IO_PENDING, 8), | |
1692 CreateMockRead(push_c, 9), | |
1693 CreateMockRead(push_c_body, 11), | |
1694 MockRead(ASYNC, ERR_IO_PENDING, 12), | |
1695 MockRead(ASYNC, 0, 13) // EOF | |
1696 }; | |
1697 | |
1698 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
1699 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1700 | |
1701 AddSSLSocketData(); | |
1702 | |
1703 CreateNetworkSession(); | |
1704 CreateSecureSpdySession(); | |
1705 | |
1706 // Process the principal request, and the first push stream request & body. | |
1707 base::WeakPtr<SpdyStream> spdy_stream = | |
1708 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
1709 test_url_, MEDIUM, NetLogWithSource()); | |
1710 test::StreamDelegateDoNothing delegate(spdy_stream); | |
1711 spdy_stream->SetDelegate(&delegate); | |
1712 | |
1713 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
1714 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
1715 | |
1716 base::RunLoop().RunUntilIdle(); | |
1717 | |
1718 // Verify that there is one unclaimed push stream. | |
1719 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1720 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1721 GURL("https://www.example.org/a.dat"))); | |
1722 | |
1723 // Unclaimed push body consumed bytes from the session window. | |
1724 EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, | |
1725 session_->session_recv_window_size_); | |
1726 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
1727 | |
1728 // Shift time to expire the push stream. Read the second HEADERS, | |
1729 // and verify a RST_STREAM was written. | |
1730 g_time_delta = base::TimeDelta::FromSeconds(300); | |
1731 data.Resume(); | |
1732 base::RunLoop().RunUntilIdle(); | |
1733 | |
1734 // Verify that the second pushed stream evicted the first pushed stream. | |
1735 EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); | |
1736 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1737 GURL("https://www.example.org/0.dat"))); | |
1738 | |
1739 // Verify that the session window reclaimed the evicted stream body. | |
1740 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
1741 EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); | |
1742 | |
1743 // Read the third PUSH, this will not be expired when the test tear down. | |
1744 data.Resume(); | |
1745 base::RunLoop().RunUntilIdle(); | |
1746 | |
1747 EXPECT_EQ(2u, session_->num_unclaimed_pushed_streams()); | |
1748 EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( | |
1749 GURL("https://www.example.org/1.dat"))); | |
1750 | |
1751 // Read and process EOF. | |
1752 EXPECT_TRUE(session_); | |
1753 data.Resume(); | |
1754 base::RunLoop().RunUntilIdle(); | |
1755 EXPECT_FALSE(session_); | |
1756 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedBytes", 12, 1); | |
1757 histogram_tester.ExpectBucketCount("Net.SpdySession.PushedAndUnclaimedBytes", | |
1758 6, 1); | |
1759 } | |
1760 | |
1761 TEST_F(SpdySessionTest, FailedPing) { | |
1762 session_deps_.host_resolver->set_synchronous_mode(true); | |
1763 | |
1764 MockRead reads[] = { | |
1765 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
1766 }; | |
1767 SpdySerializedFrame write_ping(spdy_util_.ConstructSpdyPing(1, false)); | |
1768 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway( | |
1769 0, ERROR_CODE_PROTOCOL_ERROR, "Failed ping.")); | |
1770 MockWrite writes[] = {CreateMockWrite(write_ping), CreateMockWrite(goaway)}; | |
1771 | |
1772 StaticSocketDataProvider data( | |
1773 reads, arraysize(reads), writes, arraysize(writes)); | |
1774 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1775 | |
1776 AddSSLSocketData(); | |
1777 | |
1778 CreateNetworkSession(); | |
1779 CreateSecureSpdySession(); | |
1780 | |
1781 base::WeakPtr<SpdyStream> spdy_stream1 = | |
1782 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
1783 MEDIUM, NetLogWithSource()); | |
1784 ASSERT_TRUE(spdy_stream1); | |
1785 test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr); | |
1786 spdy_stream1->SetDelegate(&delegate); | |
1787 | |
1788 session_->set_connection_at_risk_of_loss_time( | |
1789 base::TimeDelta::FromSeconds(0)); | |
1790 session_->set_hung_interval(base::TimeDelta::FromSeconds(0)); | |
1791 | |
1792 // Send a PING frame. | |
1793 session_->WritePingFrame(1, false); | |
1794 EXPECT_LT(0, session_->pings_in_flight()); | |
1795 EXPECT_GE(session_->next_ping_id(), 1U); | |
1796 EXPECT_TRUE(session_->check_ping_status_pending()); | |
1797 | |
1798 // Assert session is not closed. | |
1799 EXPECT_TRUE(session_->IsAvailable()); | |
1800 EXPECT_LT(0u, | |
1801 session_->num_active_streams() + session_->num_created_streams()); | |
1802 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
1803 | |
1804 // We set last time we have received any data in 1 sec less than now. | |
1805 // CheckPingStatus will trigger timeout because hung interval is zero. | |
1806 base::TimeTicks now = base::TimeTicks::Now(); | |
1807 session_->last_activity_time_ = now - base::TimeDelta::FromSeconds(1); | |
1808 session_->CheckPingStatus(now); | |
1809 base::RunLoop().RunUntilIdle(); | |
1810 | |
1811 EXPECT_FALSE(session_); | |
1812 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
1813 EXPECT_FALSE(spdy_stream1); | |
1814 } | |
1815 | |
1816 // Request kInitialMaxConcurrentStreams + 1 streams. Receive a | |
1817 // settings frame increasing the max concurrent streams by 1. Make | |
1818 // sure nothing blows up. This is a regression test for | |
1819 // http://crbug.com/57331 . | |
1820 TEST_F(SpdySessionTest, OnSettings) { | |
1821 session_deps_.host_resolver->set_synchronous_mode(true); | |
1822 | |
1823 const SpdySettingsIds kSpdySettingsIds = SETTINGS_MAX_CONCURRENT_STREAMS; | |
1824 | |
1825 SettingsMap new_settings; | |
1826 const uint32_t max_concurrent_streams = kInitialMaxConcurrentStreams + 1; | |
1827 new_settings[kSpdySettingsIds] = max_concurrent_streams; | |
1828 SpdySerializedFrame settings_frame( | |
1829 spdy_util_.ConstructSpdySettings(new_settings)); | |
1830 MockRead reads[] = { | |
1831 CreateMockRead(settings_frame, 0), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
1832 MockRead(ASYNC, 0, 3), | |
1833 }; | |
1834 | |
1835 SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
1836 MockWrite writes[] = {CreateMockWrite(settings_ack, 1)}; | |
1837 | |
1838 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
1839 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1840 | |
1841 AddSSLSocketData(); | |
1842 | |
1843 CreateNetworkSession(); | |
1844 CreateSecureSpdySession(); | |
1845 | |
1846 // Create the maximum number of concurrent streams. | |
1847 for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) { | |
1848 base::WeakPtr<SpdyStream> spdy_stream = | |
1849 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, | |
1850 test_url_, MEDIUM, NetLogWithSource()); | |
1851 ASSERT_TRUE(spdy_stream); | |
1852 } | |
1853 | |
1854 StreamReleaserCallback stream_releaser; | |
1855 SpdyStreamRequest request; | |
1856 ASSERT_EQ(ERR_IO_PENDING, | |
1857 request.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
1858 MEDIUM, NetLogWithSource(), | |
1859 stream_releaser.MakeCallback(&request))); | |
1860 | |
1861 base::RunLoop().RunUntilIdle(); | |
1862 | |
1863 EXPECT_THAT(stream_releaser.WaitForResult(), IsOk()); | |
1864 | |
1865 data.Resume(); | |
1866 base::RunLoop().RunUntilIdle(); | |
1867 EXPECT_FALSE(session_); | |
1868 | |
1869 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
1870 EXPECT_TRUE(data.AllReadDataConsumed()); | |
1871 } | |
1872 | |
1873 // Create one more stream than maximum number of concurrent streams, | |
1874 // so that one of them is pending. Cancel one stream, which should trigger the | |
1875 // creation of the pending stream. Then cancel that one immediately as well, | |
1876 // and make sure this does not lead to a crash. | |
1877 // This is a regression test for https://crbug.com/63532. | |
1878 TEST_F(SpdySessionTest, CancelPendingCreateStream) { | |
1879 session_deps_.host_resolver->set_synchronous_mode(true); | |
1880 | |
1881 MockRead reads[] = { | |
1882 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
1883 }; | |
1884 | |
1885 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
1886 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1887 | |
1888 AddSSLSocketData(); | |
1889 | |
1890 CreateNetworkSession(); | |
1891 CreateSecureSpdySession(); | |
1892 | |
1893 // Leave room for only one more stream to be created. | |
1894 for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) { | |
1895 base::WeakPtr<SpdyStream> spdy_stream = | |
1896 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, | |
1897 test_url_, MEDIUM, NetLogWithSource()); | |
1898 ASSERT_TRUE(spdy_stream); | |
1899 } | |
1900 | |
1901 // Create 2 more streams. First will succeed. Second will be pending. | |
1902 base::WeakPtr<SpdyStream> spdy_stream1 = | |
1903 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
1904 MEDIUM, NetLogWithSource()); | |
1905 ASSERT_TRUE(spdy_stream1); | |
1906 | |
1907 // Use unique_ptr to let us invalidate the memory when we want to, to trigger | |
1908 // a valgrind error if the callback is invoked when it's not supposed to be. | |
1909 std::unique_ptr<TestCompletionCallback> callback(new TestCompletionCallback); | |
1910 | |
1911 SpdyStreamRequest request; | |
1912 ASSERT_THAT( | |
1913 request.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
1914 MEDIUM, NetLogWithSource(), callback->callback()), | |
1915 IsError(ERR_IO_PENDING)); | |
1916 | |
1917 // Release the first one, this will allow the second to be created. | |
1918 spdy_stream1->Cancel(); | |
1919 EXPECT_FALSE(spdy_stream1); | |
1920 | |
1921 request.CancelRequest(); | |
1922 callback.reset(); | |
1923 | |
1924 // Should not crash when running the pending callback. | |
1925 base::RunLoop().RunUntilIdle(); | |
1926 } | |
1927 | |
1928 TEST_F(SpdySessionTest, Initialize) { | |
1929 session_deps_.host_resolver->set_synchronous_mode(true); | |
1930 | |
1931 MockRead reads[] = { | |
1932 MockRead(ASYNC, 0, 0) // EOF | |
1933 }; | |
1934 | |
1935 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
1936 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1937 | |
1938 AddSSLSocketData(); | |
1939 | |
1940 CreateNetworkSession(); | |
1941 CreateSecureSpdySession(); | |
1942 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
1943 | |
1944 // Flush the read completion task. | |
1945 base::RunLoop().RunUntilIdle(); | |
1946 | |
1947 TestNetLogEntry::List entries; | |
1948 log_.GetEntries(&entries); | |
1949 EXPECT_LT(0u, entries.size()); | |
1950 | |
1951 // Check that we logged HTTP2_SESSION_INITIALIZED correctly. | |
1952 int pos = ExpectLogContainsSomewhere( | |
1953 entries, 0, NetLogEventType::HTTP2_SESSION_INITIALIZED, | |
1954 NetLogEventPhase::NONE); | |
1955 EXPECT_LT(0, pos); | |
1956 | |
1957 TestNetLogEntry entry = entries[pos]; | |
1958 NetLogSource socket_source; | |
1959 EXPECT_TRUE( | |
1960 NetLogSource::FromEventParameters(entry.params.get(), &socket_source)); | |
1961 EXPECT_TRUE(socket_source.IsValid()); | |
1962 EXPECT_NE(log_.bound().source().id, socket_source.id); | |
1963 } | |
1964 | |
1965 TEST_F(SpdySessionTest, NetLogOnSessionGoaway) { | |
1966 session_deps_.host_resolver->set_synchronous_mode(true); | |
1967 | |
1968 SpdySerializedFrame goaway( | |
1969 spdy_util_.ConstructSpdyGoAway(42, ERROR_CODE_ENHANCE_YOUR_CALM, "foo")); | |
1970 MockRead reads[] = { | |
1971 CreateMockRead(goaway), MockRead(SYNCHRONOUS, 0, 0) // EOF | |
1972 }; | |
1973 | |
1974 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
1975 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
1976 | |
1977 AddSSLSocketData(); | |
1978 | |
1979 CreateNetworkSession(); | |
1980 CreateSecureSpdySession(); | |
1981 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
1982 | |
1983 // Flush the read completion task. | |
1984 base::RunLoop().RunUntilIdle(); | |
1985 | |
1986 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
1987 EXPECT_FALSE(session_); | |
1988 | |
1989 // Check that the NetLog was filled reasonably. | |
1990 TestNetLogEntry::List entries; | |
1991 log_.GetEntries(&entries); | |
1992 EXPECT_LT(0u, entries.size()); | |
1993 | |
1994 int pos = ExpectLogContainsSomewhere( | |
1995 entries, 0, NetLogEventType::HTTP2_SESSION_RECV_GOAWAY, | |
1996 NetLogEventPhase::NONE); | |
1997 TestNetLogEntry entry = entries[pos]; | |
1998 int last_accepted_stream_id; | |
1999 ASSERT_TRUE(entry.GetIntegerValue("last_accepted_stream_id", | |
2000 &last_accepted_stream_id)); | |
2001 EXPECT_EQ(42, last_accepted_stream_id); | |
2002 int active_streams; | |
2003 ASSERT_TRUE(entry.GetIntegerValue("active_streams", &active_streams)); | |
2004 EXPECT_EQ(0, active_streams); | |
2005 int unclaimed_streams; | |
2006 ASSERT_TRUE(entry.GetIntegerValue("unclaimed_streams", &unclaimed_streams)); | |
2007 EXPECT_EQ(0, unclaimed_streams); | |
2008 SpdyString error_code; | |
2009 ASSERT_TRUE(entry.GetStringValue("error_code", &error_code)); | |
2010 EXPECT_EQ("11 (ENHANCE_YOUR_CALM)", error_code); | |
2011 SpdyString debug_data; | |
2012 ASSERT_TRUE(entry.GetStringValue("debug_data", &debug_data)); | |
2013 EXPECT_EQ("foo", debug_data); | |
2014 | |
2015 // Check that we logged SPDY_SESSION_CLOSE correctly. | |
2016 pos = ExpectLogContainsSomewhere( | |
2017 entries, 0, NetLogEventType::HTTP2_SESSION_CLOSE, NetLogEventPhase::NONE); | |
2018 entry = entries[pos]; | |
2019 int net_error_code = 0; | |
2020 ASSERT_TRUE(entry.GetNetErrorCode(&net_error_code)); | |
2021 EXPECT_THAT(net_error_code, IsOk()); | |
2022 } | |
2023 | |
2024 TEST_F(SpdySessionTest, NetLogOnSessionEOF) { | |
2025 session_deps_.host_resolver->set_synchronous_mode(true); | |
2026 | |
2027 MockRead reads[] = { | |
2028 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
2029 }; | |
2030 | |
2031 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
2032 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2033 | |
2034 AddSSLSocketData(); | |
2035 | |
2036 CreateNetworkSession(); | |
2037 CreateSecureSpdySession(); | |
2038 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
2039 | |
2040 // Flush the read completion task. | |
2041 base::RunLoop().RunUntilIdle(); | |
2042 | |
2043 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
2044 EXPECT_FALSE(session_); | |
2045 | |
2046 // Check that the NetLog was filled reasonably. | |
2047 TestNetLogEntry::List entries; | |
2048 log_.GetEntries(&entries); | |
2049 EXPECT_LT(0u, entries.size()); | |
2050 | |
2051 // Check that we logged SPDY_SESSION_CLOSE correctly. | |
2052 int pos = ExpectLogContainsSomewhere( | |
2053 entries, 0, NetLogEventType::HTTP2_SESSION_CLOSE, NetLogEventPhase::NONE); | |
2054 | |
2055 if (pos < static_cast<int>(entries.size())) { | |
2056 TestNetLogEntry entry = entries[pos]; | |
2057 int error_code = 0; | |
2058 ASSERT_TRUE(entry.GetNetErrorCode(&error_code)); | |
2059 EXPECT_THAT(error_code, IsError(ERR_CONNECTION_CLOSED)); | |
2060 } else { | |
2061 ADD_FAILURE(); | |
2062 } | |
2063 } | |
2064 | |
2065 TEST_F(SpdySessionTest, HeadersCompressionHistograms) { | |
2066 SpdySerializedFrame req( | |
2067 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
2068 MockWrite writes[] = { | |
2069 CreateMockWrite(req, 0), | |
2070 }; | |
2071 MockRead reads[] = { | |
2072 MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2) // EOF | |
2073 }; | |
2074 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2075 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2076 | |
2077 AddSSLSocketData(); | |
2078 | |
2079 CreateNetworkSession(); | |
2080 CreateSecureSpdySession(); | |
2081 | |
2082 base::WeakPtr<SpdyStream> spdy_stream = | |
2083 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2084 test_url_, MEDIUM, NetLogWithSource()); | |
2085 test::StreamDelegateDoNothing delegate(spdy_stream); | |
2086 spdy_stream->SetDelegate(&delegate); | |
2087 | |
2088 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2089 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
2090 | |
2091 // Write request headers & capture resulting histogram update. | |
2092 base::HistogramTester histogram_tester; | |
2093 | |
2094 base::RunLoop().RunUntilIdle(); | |
2095 // Regression test of compression performance under the request fixture. | |
2096 histogram_tester.ExpectBucketCount("Net.SpdyHeadersCompressionPercentage", 76, | |
2097 1); | |
2098 | |
2099 // Read and process EOF. | |
2100 EXPECT_TRUE(session_); | |
2101 data.Resume(); | |
2102 base::RunLoop().RunUntilIdle(); | |
2103 EXPECT_FALSE(session_); | |
2104 } | |
2105 | |
2106 // Queue up a low-priority HEADERS followed by a high-priority | |
2107 // one. The high priority one should still send first and receive | |
2108 // first. | |
2109 TEST_F(SpdySessionTest, OutOfOrderHeaders) { | |
2110 // Construct the request. | |
2111 SpdySerializedFrame req_highest( | |
2112 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST, true)); | |
2113 SpdySerializedFrame req_lowest( | |
2114 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true)); | |
2115 MockWrite writes[] = { | |
2116 CreateMockWrite(req_highest, 0), CreateMockWrite(req_lowest, 1), | |
2117 }; | |
2118 | |
2119 SpdySerializedFrame resp_highest( | |
2120 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
2121 SpdySerializedFrame body_highest(spdy_util_.ConstructSpdyDataFrame(1, true)); | |
2122 SpdySerializedFrame resp_lowest( | |
2123 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3)); | |
2124 SpdySerializedFrame body_lowest(spdy_util_.ConstructSpdyDataFrame(3, true)); | |
2125 MockRead reads[] = { | |
2126 CreateMockRead(resp_highest, 2), CreateMockRead(body_highest, 3), | |
2127 CreateMockRead(resp_lowest, 4), CreateMockRead(body_lowest, 5), | |
2128 MockRead(ASYNC, 0, 6) // EOF | |
2129 }; | |
2130 | |
2131 session_deps_.host_resolver->set_synchronous_mode(true); | |
2132 | |
2133 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2134 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2135 | |
2136 AddSSLSocketData(); | |
2137 | |
2138 CreateNetworkSession(); | |
2139 CreateSecureSpdySession(); | |
2140 | |
2141 base::WeakPtr<SpdyStream> spdy_stream_lowest = | |
2142 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2143 test_url_, LOWEST, NetLogWithSource()); | |
2144 ASSERT_TRUE(spdy_stream_lowest); | |
2145 EXPECT_EQ(0u, spdy_stream_lowest->stream_id()); | |
2146 test::StreamDelegateDoNothing delegate_lowest(spdy_stream_lowest); | |
2147 spdy_stream_lowest->SetDelegate(&delegate_lowest); | |
2148 | |
2149 base::WeakPtr<SpdyStream> spdy_stream_highest = | |
2150 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2151 test_url_, HIGHEST, NetLogWithSource()); | |
2152 ASSERT_TRUE(spdy_stream_highest); | |
2153 EXPECT_EQ(0u, spdy_stream_highest->stream_id()); | |
2154 test::StreamDelegateDoNothing delegate_highest(spdy_stream_highest); | |
2155 spdy_stream_highest->SetDelegate(&delegate_highest); | |
2156 | |
2157 // Queue the lower priority one first. | |
2158 | |
2159 SpdyHeaderBlock headers_lowest( | |
2160 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2161 spdy_stream_lowest->SendRequestHeaders(std::move(headers_lowest), | |
2162 NO_MORE_DATA_TO_SEND); | |
2163 | |
2164 SpdyHeaderBlock headers_highest( | |
2165 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2166 spdy_stream_highest->SendRequestHeaders(std::move(headers_highest), | |
2167 NO_MORE_DATA_TO_SEND); | |
2168 | |
2169 base::RunLoop().RunUntilIdle(); | |
2170 | |
2171 EXPECT_FALSE(spdy_stream_lowest); | |
2172 EXPECT_FALSE(spdy_stream_highest); | |
2173 EXPECT_EQ(3u, delegate_lowest.stream_id()); | |
2174 EXPECT_EQ(1u, delegate_highest.stream_id()); | |
2175 } | |
2176 | |
2177 TEST_F(SpdySessionTest, CancelStream) { | |
2178 // Request 1, at HIGHEST priority, will be cancelled before it writes data. | |
2179 // Request 2, at LOWEST priority, will be a full request and will be id 1. | |
2180 SpdySerializedFrame req2( | |
2181 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
2182 MockWrite writes[] = { | |
2183 CreateMockWrite(req2, 0), | |
2184 }; | |
2185 | |
2186 SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
2187 SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(1, true)); | |
2188 MockRead reads[] = { | |
2189 CreateMockRead(resp2, 1), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
2190 CreateMockRead(body2, 3), MockRead(ASYNC, 0, 4) // EOF | |
2191 }; | |
2192 | |
2193 session_deps_.host_resolver->set_synchronous_mode(true); | |
2194 | |
2195 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2196 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2197 | |
2198 AddSSLSocketData(); | |
2199 | |
2200 CreateNetworkSession(); | |
2201 CreateSecureSpdySession(); | |
2202 | |
2203 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2204 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2205 test_url_, HIGHEST, NetLogWithSource()); | |
2206 ASSERT_TRUE(spdy_stream1); | |
2207 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2208 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
2209 spdy_stream1->SetDelegate(&delegate1); | |
2210 | |
2211 base::WeakPtr<SpdyStream> spdy_stream2 = | |
2212 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2213 test_url_, LOWEST, NetLogWithSource()); | |
2214 ASSERT_TRUE(spdy_stream2); | |
2215 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2216 test::StreamDelegateDoNothing delegate2(spdy_stream2); | |
2217 spdy_stream2->SetDelegate(&delegate2); | |
2218 | |
2219 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2220 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
2221 | |
2222 SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2223 spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
2224 | |
2225 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2226 | |
2227 spdy_stream1->Cancel(); | |
2228 EXPECT_FALSE(spdy_stream1); | |
2229 | |
2230 EXPECT_EQ(0u, delegate1.stream_id()); | |
2231 | |
2232 base::RunLoop().RunUntilIdle(); | |
2233 | |
2234 EXPECT_EQ(0u, delegate1.stream_id()); | |
2235 EXPECT_EQ(1u, delegate2.stream_id()); | |
2236 | |
2237 spdy_stream2->Cancel(); | |
2238 EXPECT_FALSE(spdy_stream2); | |
2239 } | |
2240 | |
2241 // Create two streams that are set to re-close themselves on close, | |
2242 // and then close the session. Nothing should blow up. Also a | |
2243 // regression test for http://crbug.com/139518 . | |
2244 TEST_F(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) { | |
2245 session_deps_.host_resolver->set_synchronous_mode(true); | |
2246 | |
2247 | |
2248 // No actual data will be sent. | |
2249 MockWrite writes[] = { | |
2250 MockWrite(ASYNC, 0, 1) // EOF | |
2251 }; | |
2252 | |
2253 MockRead reads[] = { | |
2254 MockRead(ASYNC, 0, 0) // EOF | |
2255 }; | |
2256 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2257 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2258 | |
2259 AddSSLSocketData(); | |
2260 | |
2261 CreateNetworkSession(); | |
2262 CreateSecureSpdySession(); | |
2263 | |
2264 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2265 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
2266 HIGHEST, NetLogWithSource()); | |
2267 ASSERT_TRUE(spdy_stream1); | |
2268 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2269 | |
2270 base::WeakPtr<SpdyStream> spdy_stream2 = | |
2271 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
2272 LOWEST, NetLogWithSource()); | |
2273 ASSERT_TRUE(spdy_stream2); | |
2274 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2275 | |
2276 test::ClosingDelegate delegate1(spdy_stream1); | |
2277 spdy_stream1->SetDelegate(&delegate1); | |
2278 | |
2279 test::ClosingDelegate delegate2(spdy_stream2); | |
2280 spdy_stream2->SetDelegate(&delegate2); | |
2281 | |
2282 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2283 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
2284 | |
2285 SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2286 spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
2287 | |
2288 // Ensure that the streams have not yet been activated and assigned an id. | |
2289 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2290 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2291 | |
2292 // Ensure we don't crash while closing the session. | |
2293 session_->CloseSessionOnError(ERR_ABORTED, SpdyString()); | |
2294 | |
2295 EXPECT_FALSE(spdy_stream1); | |
2296 EXPECT_FALSE(spdy_stream2); | |
2297 | |
2298 EXPECT_TRUE(delegate1.StreamIsClosed()); | |
2299 EXPECT_TRUE(delegate2.StreamIsClosed()); | |
2300 | |
2301 base::RunLoop().RunUntilIdle(); | |
2302 EXPECT_FALSE(session_); | |
2303 } | |
2304 | |
2305 // Create two streams that are set to close each other on close, and | |
2306 // then close the session. Nothing should blow up. | |
2307 TEST_F(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) { | |
2308 session_deps_.host_resolver->set_synchronous_mode(true); | |
2309 | |
2310 SequencedSocketData data(nullptr, 0, nullptr, 0); | |
2311 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2312 | |
2313 AddSSLSocketData(); | |
2314 | |
2315 CreateNetworkSession(); | |
2316 CreateSecureSpdySession(); | |
2317 | |
2318 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2319 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
2320 HIGHEST, NetLogWithSource()); | |
2321 ASSERT_TRUE(spdy_stream1); | |
2322 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2323 | |
2324 base::WeakPtr<SpdyStream> spdy_stream2 = | |
2325 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
2326 LOWEST, NetLogWithSource()); | |
2327 ASSERT_TRUE(spdy_stream2); | |
2328 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2329 | |
2330 // Make |spdy_stream1| close |spdy_stream2|. | |
2331 test::ClosingDelegate delegate1(spdy_stream2); | |
2332 spdy_stream1->SetDelegate(&delegate1); | |
2333 | |
2334 // Make |spdy_stream2| close |spdy_stream1|. | |
2335 test::ClosingDelegate delegate2(spdy_stream1); | |
2336 spdy_stream2->SetDelegate(&delegate2); | |
2337 | |
2338 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2339 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
2340 | |
2341 SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2342 spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
2343 | |
2344 // Ensure that the streams have not yet been activated and assigned an id. | |
2345 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2346 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2347 | |
2348 // Ensure we don't crash while closing the session. | |
2349 session_->CloseSessionOnError(ERR_ABORTED, SpdyString()); | |
2350 | |
2351 EXPECT_FALSE(spdy_stream1); | |
2352 EXPECT_FALSE(spdy_stream2); | |
2353 | |
2354 EXPECT_TRUE(delegate1.StreamIsClosed()); | |
2355 EXPECT_TRUE(delegate2.StreamIsClosed()); | |
2356 | |
2357 base::RunLoop().RunUntilIdle(); | |
2358 EXPECT_FALSE(session_); | |
2359 } | |
2360 | |
2361 // Create two streams that are set to re-close themselves on close, | |
2362 // activate them, and then close the session. Nothing should blow up. | |
2363 TEST_F(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) { | |
2364 session_deps_.host_resolver->set_synchronous_mode(true); | |
2365 | |
2366 SpdySerializedFrame req1( | |
2367 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
2368 SpdySerializedFrame req2( | |
2369 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true)); | |
2370 MockWrite writes[] = { | |
2371 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
2372 }; | |
2373 | |
2374 MockRead reads[] = { | |
2375 MockRead(ASYNC, ERR_IO_PENDING, 2), MockRead(ASYNC, 0, 3) // EOF | |
2376 }; | |
2377 | |
2378 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2379 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2380 | |
2381 AddSSLSocketData(); | |
2382 | |
2383 CreateNetworkSession(); | |
2384 CreateSecureSpdySession(); | |
2385 | |
2386 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2387 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2388 test_url_, MEDIUM, NetLogWithSource()); | |
2389 ASSERT_TRUE(spdy_stream1); | |
2390 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2391 | |
2392 base::WeakPtr<SpdyStream> spdy_stream2 = | |
2393 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2394 test_url_, MEDIUM, NetLogWithSource()); | |
2395 ASSERT_TRUE(spdy_stream2); | |
2396 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2397 | |
2398 test::ClosingDelegate delegate1(spdy_stream1); | |
2399 spdy_stream1->SetDelegate(&delegate1); | |
2400 | |
2401 test::ClosingDelegate delegate2(spdy_stream2); | |
2402 spdy_stream2->SetDelegate(&delegate2); | |
2403 | |
2404 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2405 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
2406 | |
2407 SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2408 spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
2409 | |
2410 // Ensure that the streams have not yet been activated and assigned an id. | |
2411 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2412 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2413 | |
2414 base::RunLoop().RunUntilIdle(); | |
2415 | |
2416 EXPECT_EQ(1u, spdy_stream1->stream_id()); | |
2417 EXPECT_EQ(3u, spdy_stream2->stream_id()); | |
2418 | |
2419 // Ensure we don't crash while closing the session. | |
2420 session_->CloseSessionOnError(ERR_ABORTED, SpdyString()); | |
2421 | |
2422 EXPECT_FALSE(spdy_stream1); | |
2423 EXPECT_FALSE(spdy_stream2); | |
2424 | |
2425 EXPECT_TRUE(delegate1.StreamIsClosed()); | |
2426 EXPECT_TRUE(delegate2.StreamIsClosed()); | |
2427 | |
2428 EXPECT_TRUE(session_); | |
2429 data.Resume(); | |
2430 base::RunLoop().RunUntilIdle(); | |
2431 EXPECT_FALSE(session_); | |
2432 } | |
2433 | |
2434 // Create two streams that are set to close each other on close, | |
2435 // activate them, and then close the session. Nothing should blow up. | |
2436 TEST_F(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) { | |
2437 session_deps_.host_resolver->set_synchronous_mode(true); | |
2438 | |
2439 SpdySerializedFrame req1( | |
2440 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
2441 SpdySerializedFrame req2( | |
2442 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true)); | |
2443 MockWrite writes[] = { | |
2444 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
2445 }; | |
2446 | |
2447 MockRead reads[] = { | |
2448 MockRead(ASYNC, ERR_IO_PENDING, 2), MockRead(ASYNC, 0, 3) // EOF | |
2449 }; | |
2450 | |
2451 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2452 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2453 | |
2454 AddSSLSocketData(); | |
2455 | |
2456 CreateNetworkSession(); | |
2457 CreateSecureSpdySession(); | |
2458 | |
2459 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2460 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2461 test_url_, MEDIUM, NetLogWithSource()); | |
2462 ASSERT_TRUE(spdy_stream1); | |
2463 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2464 | |
2465 base::WeakPtr<SpdyStream> spdy_stream2 = | |
2466 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2467 test_url_, MEDIUM, NetLogWithSource()); | |
2468 ASSERT_TRUE(spdy_stream2); | |
2469 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2470 | |
2471 // Make |spdy_stream1| close |spdy_stream2|. | |
2472 test::ClosingDelegate delegate1(spdy_stream2); | |
2473 spdy_stream1->SetDelegate(&delegate1); | |
2474 | |
2475 // Make |spdy_stream2| close |spdy_stream1|. | |
2476 test::ClosingDelegate delegate2(spdy_stream1); | |
2477 spdy_stream2->SetDelegate(&delegate2); | |
2478 | |
2479 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2480 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
2481 | |
2482 SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2483 spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
2484 | |
2485 // Ensure that the streams have not yet been activated and assigned an id. | |
2486 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2487 EXPECT_EQ(0u, spdy_stream2->stream_id()); | |
2488 | |
2489 base::RunLoop().RunUntilIdle(); | |
2490 | |
2491 EXPECT_EQ(1u, spdy_stream1->stream_id()); | |
2492 EXPECT_EQ(3u, spdy_stream2->stream_id()); | |
2493 | |
2494 // Ensure we don't crash while closing the session. | |
2495 session_->CloseSessionOnError(ERR_ABORTED, SpdyString()); | |
2496 | |
2497 EXPECT_FALSE(spdy_stream1); | |
2498 EXPECT_FALSE(spdy_stream2); | |
2499 | |
2500 EXPECT_TRUE(delegate1.StreamIsClosed()); | |
2501 EXPECT_TRUE(delegate2.StreamIsClosed()); | |
2502 | |
2503 EXPECT_TRUE(session_); | |
2504 data.Resume(); | |
2505 base::RunLoop().RunUntilIdle(); | |
2506 EXPECT_FALSE(session_); | |
2507 } | |
2508 | |
2509 // Delegate that closes a given session when the stream is closed. | |
2510 class SessionClosingDelegate : public test::StreamDelegateDoNothing { | |
2511 public: | |
2512 SessionClosingDelegate(const base::WeakPtr<SpdyStream>& stream, | |
2513 const base::WeakPtr<SpdySession>& session_to_close) | |
2514 : StreamDelegateDoNothing(stream), | |
2515 session_to_close_(session_to_close) {} | |
2516 | |
2517 ~SessionClosingDelegate() override {} | |
2518 | |
2519 void OnClose(int status) override { | |
2520 session_to_close_->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error"); | |
2521 } | |
2522 | |
2523 private: | |
2524 base::WeakPtr<SpdySession> session_to_close_; | |
2525 }; | |
2526 | |
2527 // Close an activated stream that closes its session. Nothing should | |
2528 // blow up. This is a regression test for https://crbug.com/263691. | |
2529 TEST_F(SpdySessionTest, CloseActivatedStreamThatClosesSession) { | |
2530 session_deps_.host_resolver->set_synchronous_mode(true); | |
2531 | |
2532 SpdySerializedFrame req( | |
2533 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
2534 SpdySerializedFrame rst( | |
2535 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
2536 SpdySerializedFrame goaway( | |
2537 spdy_util_.ConstructSpdyGoAway(0, ERROR_CODE_PROTOCOL_ERROR, "Error")); | |
2538 // The GOAWAY has higher-priority than the RST_STREAM, and is written first | |
2539 // despite being queued second. | |
2540 MockWrite writes[] = { | |
2541 CreateMockWrite(req, 0), CreateMockWrite(goaway, 1), | |
2542 CreateMockWrite(rst, 3), | |
2543 }; | |
2544 | |
2545 MockRead reads[] = { | |
2546 MockRead(ASYNC, 0, 2) // EOF | |
2547 }; | |
2548 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2549 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2550 | |
2551 AddSSLSocketData(); | |
2552 | |
2553 CreateNetworkSession(); | |
2554 CreateSecureSpdySession(); | |
2555 | |
2556 base::WeakPtr<SpdyStream> spdy_stream = | |
2557 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2558 test_url_, MEDIUM, NetLogWithSource()); | |
2559 ASSERT_TRUE(spdy_stream); | |
2560 EXPECT_EQ(0u, spdy_stream->stream_id()); | |
2561 | |
2562 SessionClosingDelegate delegate(spdy_stream, session_); | |
2563 spdy_stream->SetDelegate(&delegate); | |
2564 | |
2565 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2566 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
2567 | |
2568 EXPECT_EQ(0u, spdy_stream->stream_id()); | |
2569 | |
2570 base::RunLoop().RunUntilIdle(); | |
2571 | |
2572 EXPECT_EQ(1u, spdy_stream->stream_id()); | |
2573 | |
2574 // Ensure we don't crash while closing the stream (which closes the | |
2575 // session). | |
2576 spdy_stream->Cancel(); | |
2577 | |
2578 EXPECT_FALSE(spdy_stream); | |
2579 EXPECT_TRUE(delegate.StreamIsClosed()); | |
2580 | |
2581 // Write the RST_STREAM & GOAWAY. | |
2582 base::RunLoop().RunUntilIdle(); | |
2583 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
2584 EXPECT_TRUE(data.AllReadDataConsumed()); | |
2585 } | |
2586 | |
2587 TEST_F(SpdySessionTest, VerifyDomainAuthentication) { | |
2588 session_deps_.host_resolver->set_synchronous_mode(true); | |
2589 | |
2590 SequencedSocketData data(nullptr, 0, nullptr, 0); | |
2591 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2592 | |
2593 AddSSLSocketData(); | |
2594 | |
2595 CreateNetworkSession(); | |
2596 CreateSecureSpdySession(); | |
2597 | |
2598 EXPECT_TRUE(session_->VerifyDomainAuthentication("www.example.org")); | |
2599 EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.org")); | |
2600 EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.com")); | |
2601 EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.google.com")); | |
2602 } | |
2603 | |
2604 TEST_F(SpdySessionTest, ConnectionPooledWithTlsChannelId) { | |
2605 session_deps_.host_resolver->set_synchronous_mode(true); | |
2606 | |
2607 SequencedSocketData data(nullptr, 0, nullptr, 0); | |
2608 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2609 | |
2610 ssl_.channel_id_sent = true; | |
2611 AddSSLSocketData(); | |
2612 | |
2613 CreateNetworkSession(); | |
2614 CreateSecureSpdySession(); | |
2615 | |
2616 EXPECT_TRUE(session_->VerifyDomainAuthentication("www.example.org")); | |
2617 EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.org")); | |
2618 EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.example.com")); | |
2619 EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.google.com")); | |
2620 } | |
2621 | |
2622 TEST_F(SpdySessionTest, CloseTwoStalledCreateStream) { | |
2623 // TODO(rtenneti): Define a helper class/methods and move the common code in | |
2624 // this file. | |
2625 SettingsMap new_settings; | |
2626 const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS; | |
2627 const uint32_t max_concurrent_streams = 1; | |
2628 new_settings[kSpdySettingsIds1] = max_concurrent_streams; | |
2629 | |
2630 SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
2631 SpdySerializedFrame req1( | |
2632 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
2633 spdy_util_.UpdateWithStreamDestruction(1); | |
2634 SpdySerializedFrame req2( | |
2635 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true)); | |
2636 spdy_util_.UpdateWithStreamDestruction(3); | |
2637 SpdySerializedFrame req3( | |
2638 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST, true)); | |
2639 MockWrite writes[] = { | |
2640 CreateMockWrite(settings_ack, 1), CreateMockWrite(req1, 2), | |
2641 CreateMockWrite(req2, 5), CreateMockWrite(req3, 8), | |
2642 }; | |
2643 | |
2644 // Set up the socket so we read a SETTINGS frame that sets max concurrent | |
2645 // streams to 1. | |
2646 SpdySerializedFrame settings_frame( | |
2647 spdy_util_.ConstructSpdySettings(new_settings)); | |
2648 | |
2649 SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
2650 SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true)); | |
2651 | |
2652 SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3)); | |
2653 SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true)); | |
2654 | |
2655 SpdySerializedFrame resp3(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5)); | |
2656 SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, true)); | |
2657 | |
2658 MockRead reads[] = { | |
2659 CreateMockRead(settings_frame, 0), | |
2660 CreateMockRead(resp1, 3), | |
2661 CreateMockRead(body1, 4), | |
2662 CreateMockRead(resp2, 6), | |
2663 CreateMockRead(body2, 7), | |
2664 CreateMockRead(resp3, 9), | |
2665 CreateMockRead(body3, 10), | |
2666 MockRead(ASYNC, ERR_IO_PENDING, 11), | |
2667 MockRead(ASYNC, 0, 12) // EOF | |
2668 }; | |
2669 | |
2670 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2671 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2672 | |
2673 AddSSLSocketData(); | |
2674 | |
2675 CreateNetworkSession(); | |
2676 CreateSecureSpdySession(); | |
2677 | |
2678 // Read the settings frame. | |
2679 base::RunLoop().RunUntilIdle(); | |
2680 | |
2681 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2682 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2683 test_url_, LOWEST, NetLogWithSource()); | |
2684 ASSERT_TRUE(spdy_stream1); | |
2685 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2686 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
2687 spdy_stream1->SetDelegate(&delegate1); | |
2688 | |
2689 TestCompletionCallback callback2; | |
2690 SpdyStreamRequest request2; | |
2691 ASSERT_EQ( | |
2692 ERR_IO_PENDING, | |
2693 request2.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, | |
2694 LOWEST, NetLogWithSource(), callback2.callback())); | |
2695 | |
2696 TestCompletionCallback callback3; | |
2697 SpdyStreamRequest request3; | |
2698 ASSERT_EQ( | |
2699 ERR_IO_PENDING, | |
2700 request3.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, | |
2701 LOWEST, NetLogWithSource(), callback3.callback())); | |
2702 | |
2703 EXPECT_EQ(0u, session_->num_active_streams()); | |
2704 EXPECT_EQ(1u, session_->num_created_streams()); | |
2705 EXPECT_EQ(2u, session_->pending_create_stream_queue_size(LOWEST)); | |
2706 | |
2707 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2708 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
2709 | |
2710 // Run until 1st stream is activated and then closed. | |
2711 EXPECT_EQ(0u, delegate1.stream_id()); | |
2712 base::RunLoop().RunUntilIdle(); | |
2713 EXPECT_FALSE(spdy_stream1); | |
2714 EXPECT_EQ(1u, delegate1.stream_id()); | |
2715 | |
2716 EXPECT_EQ(0u, session_->num_active_streams()); | |
2717 EXPECT_EQ(1u, session_->pending_create_stream_queue_size(LOWEST)); | |
2718 | |
2719 // Pump loop for SpdySession::ProcessPendingStreamRequests() to | |
2720 // create the 2nd stream. | |
2721 base::RunLoop().RunUntilIdle(); | |
2722 | |
2723 EXPECT_EQ(0u, session_->num_active_streams()); | |
2724 EXPECT_EQ(1u, session_->num_created_streams()); | |
2725 EXPECT_EQ(1u, session_->pending_create_stream_queue_size(LOWEST)); | |
2726 | |
2727 base::WeakPtr<SpdyStream> stream2 = request2.ReleaseStream(); | |
2728 test::StreamDelegateDoNothing delegate2(stream2); | |
2729 stream2->SetDelegate(&delegate2); | |
2730 SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2731 stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND); | |
2732 | |
2733 // Run until 2nd stream is activated and then closed. | |
2734 EXPECT_EQ(0u, delegate2.stream_id()); | |
2735 base::RunLoop().RunUntilIdle(); | |
2736 EXPECT_FALSE(stream2); | |
2737 EXPECT_EQ(3u, delegate2.stream_id()); | |
2738 | |
2739 EXPECT_EQ(0u, session_->num_active_streams()); | |
2740 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); | |
2741 | |
2742 // Pump loop for SpdySession::ProcessPendingStreamRequests() to | |
2743 // create the 3rd stream. | |
2744 base::RunLoop().RunUntilIdle(); | |
2745 | |
2746 EXPECT_EQ(0u, session_->num_active_streams()); | |
2747 EXPECT_EQ(1u, session_->num_created_streams()); | |
2748 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); | |
2749 | |
2750 base::WeakPtr<SpdyStream> stream3 = request3.ReleaseStream(); | |
2751 test::StreamDelegateDoNothing delegate3(stream3); | |
2752 stream3->SetDelegate(&delegate3); | |
2753 SpdyHeaderBlock headers3(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2754 stream3->SendRequestHeaders(std::move(headers3), NO_MORE_DATA_TO_SEND); | |
2755 | |
2756 // Run until 2nd stream is activated and then closed. | |
2757 EXPECT_EQ(0u, delegate3.stream_id()); | |
2758 base::RunLoop().RunUntilIdle(); | |
2759 EXPECT_FALSE(stream3); | |
2760 EXPECT_EQ(5u, delegate3.stream_id()); | |
2761 | |
2762 EXPECT_EQ(0u, session_->num_active_streams()); | |
2763 EXPECT_EQ(0u, session_->num_created_streams()); | |
2764 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); | |
2765 | |
2766 data.Resume(); | |
2767 base::RunLoop().RunUntilIdle(); | |
2768 } | |
2769 | |
2770 TEST_F(SpdySessionTest, CancelTwoStalledCreateStream) { | |
2771 session_deps_.host_resolver->set_synchronous_mode(true); | |
2772 | |
2773 MockRead reads[] = { | |
2774 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
2775 }; | |
2776 | |
2777 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
2778 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2779 | |
2780 AddSSLSocketData(); | |
2781 | |
2782 CreateNetworkSession(); | |
2783 CreateSecureSpdySession(); | |
2784 | |
2785 // Leave room for only one more stream to be created. | |
2786 for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) { | |
2787 base::WeakPtr<SpdyStream> spdy_stream = | |
2788 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, | |
2789 test_url_, MEDIUM, NetLogWithSource()); | |
2790 ASSERT_TRUE(spdy_stream); | |
2791 } | |
2792 | |
2793 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2794 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
2795 LOWEST, NetLogWithSource()); | |
2796 ASSERT_TRUE(spdy_stream1); | |
2797 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2798 | |
2799 TestCompletionCallback callback2; | |
2800 SpdyStreamRequest request2; | |
2801 ASSERT_EQ( | |
2802 ERR_IO_PENDING, | |
2803 request2.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
2804 LOWEST, NetLogWithSource(), callback2.callback())); | |
2805 | |
2806 TestCompletionCallback callback3; | |
2807 SpdyStreamRequest request3; | |
2808 ASSERT_EQ( | |
2809 ERR_IO_PENDING, | |
2810 request3.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
2811 LOWEST, NetLogWithSource(), callback3.callback())); | |
2812 | |
2813 EXPECT_EQ(0u, session_->num_active_streams()); | |
2814 EXPECT_EQ(kInitialMaxConcurrentStreams, session_->num_created_streams()); | |
2815 EXPECT_EQ(2u, session_->pending_create_stream_queue_size(LOWEST)); | |
2816 | |
2817 // Cancel the first stream; this will allow the second stream to be created. | |
2818 EXPECT_TRUE(spdy_stream1); | |
2819 spdy_stream1->Cancel(); | |
2820 EXPECT_FALSE(spdy_stream1); | |
2821 | |
2822 EXPECT_THAT(callback2.WaitForResult(), IsOk()); | |
2823 EXPECT_EQ(0u, session_->num_active_streams()); | |
2824 EXPECT_EQ(kInitialMaxConcurrentStreams, session_->num_created_streams()); | |
2825 EXPECT_EQ(1u, session_->pending_create_stream_queue_size(LOWEST)); | |
2826 | |
2827 // Cancel the second stream; this will allow the third stream to be created. | |
2828 base::WeakPtr<SpdyStream> spdy_stream2 = request2.ReleaseStream(); | |
2829 spdy_stream2->Cancel(); | |
2830 EXPECT_FALSE(spdy_stream2); | |
2831 | |
2832 EXPECT_THAT(callback3.WaitForResult(), IsOk()); | |
2833 EXPECT_EQ(0u, session_->num_active_streams()); | |
2834 EXPECT_EQ(kInitialMaxConcurrentStreams, session_->num_created_streams()); | |
2835 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); | |
2836 | |
2837 // Cancel the third stream. | |
2838 base::WeakPtr<SpdyStream> spdy_stream3 = request3.ReleaseStream(); | |
2839 spdy_stream3->Cancel(); | |
2840 EXPECT_FALSE(spdy_stream3); | |
2841 EXPECT_EQ(0u, session_->num_active_streams()); | |
2842 EXPECT_EQ(kInitialMaxConcurrentStreams - 1, session_->num_created_streams()); | |
2843 EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); | |
2844 } | |
2845 | |
2846 // Test that SpdySession::DoReadLoop reads data from the socket | |
2847 // without yielding. This test makes 32k - 1 bytes of data available | |
2848 // on the socket for reading. It then verifies that it has read all | |
2849 // the available data without yielding. | |
2850 TEST_F(SpdySessionTest, ReadDataWithoutYielding) { | |
2851 session_deps_.host_resolver->set_synchronous_mode(true); | |
2852 session_deps_.time_func = InstantaneousReads; | |
2853 | |
2854 BufferedSpdyFramer framer; | |
2855 | |
2856 SpdySerializedFrame req1( | |
2857 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
2858 MockWrite writes[] = { | |
2859 CreateMockWrite(req1, 0), | |
2860 }; | |
2861 | |
2862 // Build buffer of size kYieldAfterBytesRead / 4 | |
2863 // (-spdy_data_frame_size). | |
2864 ASSERT_EQ(32 * 1024, kYieldAfterBytesRead); | |
2865 const int kPayloadSize = | |
2866 kYieldAfterBytesRead / 4 - framer.GetFrameHeaderSize(); | |
2867 TestDataStream test_stream; | |
2868 scoped_refptr<IOBuffer> payload(new IOBuffer(kPayloadSize)); | |
2869 char* payload_data = payload->data(); | |
2870 test_stream.GetBytes(payload_data, kPayloadSize); | |
2871 | |
2872 SpdySerializedFrame partial_data_frame(spdy_util_.ConstructSpdyDataFrame( | |
2873 1, payload_data, kPayloadSize, /*fin=*/false)); | |
2874 SpdySerializedFrame finish_data_frame(spdy_util_.ConstructSpdyDataFrame( | |
2875 1, payload_data, kPayloadSize - 1, /*fin=*/true)); | |
2876 | |
2877 SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
2878 | |
2879 // Write 1 byte less than kMaxReadBytes to check that DoRead reads up to 32k | |
2880 // bytes. | |
2881 MockRead reads[] = { | |
2882 CreateMockRead(resp1, 1), | |
2883 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
2884 CreateMockRead(partial_data_frame, 3), | |
2885 CreateMockRead(partial_data_frame, 4, SYNCHRONOUS), | |
2886 CreateMockRead(partial_data_frame, 5, SYNCHRONOUS), | |
2887 CreateMockRead(finish_data_frame, 6, SYNCHRONOUS), | |
2888 MockRead(ASYNC, 0, 7) // EOF | |
2889 }; | |
2890 | |
2891 // Create SpdySession and SpdyStream and send the request. | |
2892 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2893 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2894 | |
2895 AddSSLSocketData(); | |
2896 | |
2897 CreateNetworkSession(); | |
2898 CreateSecureSpdySession(); | |
2899 | |
2900 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2901 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2902 test_url_, MEDIUM, NetLogWithSource()); | |
2903 ASSERT_TRUE(spdy_stream1); | |
2904 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2905 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
2906 spdy_stream1->SetDelegate(&delegate1); | |
2907 | |
2908 SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2909 spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND); | |
2910 | |
2911 // Set up the TaskObserver to verify SpdySession::DoReadLoop doesn't | |
2912 // post a task. | |
2913 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop"); | |
2914 | |
2915 // Run until 1st read. | |
2916 EXPECT_EQ(0u, delegate1.stream_id()); | |
2917 base::RunLoop().RunUntilIdle(); | |
2918 EXPECT_EQ(1u, delegate1.stream_id()); | |
2919 EXPECT_EQ(0u, observer.executed_count()); | |
2920 | |
2921 // Read all the data and verify SpdySession::DoReadLoop has not | |
2922 // posted a task. | |
2923 data.Resume(); | |
2924 base::RunLoop().RunUntilIdle(); | |
2925 EXPECT_FALSE(spdy_stream1); | |
2926 | |
2927 // Verify task observer's executed_count is zero, which indicates DoRead read | |
2928 // all the available data. | |
2929 EXPECT_EQ(0u, observer.executed_count()); | |
2930 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
2931 EXPECT_TRUE(data.AllReadDataConsumed()); | |
2932 } | |
2933 | |
2934 // Test that SpdySession::DoReadLoop yields if more than | |
2935 // |kYieldAfterDurationMilliseconds| has passed. This test uses a mock time | |
2936 // function that makes the response frame look very slow to read. | |
2937 TEST_F(SpdySessionTest, TestYieldingSlowReads) { | |
2938 session_deps_.host_resolver->set_synchronous_mode(true); | |
2939 session_deps_.time_func = SlowReads; | |
2940 | |
2941 SpdySerializedFrame req1( | |
2942 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
2943 MockWrite writes[] = { | |
2944 CreateMockWrite(req1, 0), | |
2945 }; | |
2946 | |
2947 SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
2948 | |
2949 MockRead reads[] = { | |
2950 CreateMockRead(resp1, 1), MockRead(ASYNC, 0, 2) // EOF | |
2951 }; | |
2952 | |
2953 // Create SpdySession and SpdyStream and send the request. | |
2954 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
2955 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2956 | |
2957 AddSSLSocketData(); | |
2958 | |
2959 CreateNetworkSession(); | |
2960 CreateSecureSpdySession(); | |
2961 | |
2962 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2963 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
2964 test_url_, MEDIUM, NetLogWithSource()); | |
2965 ASSERT_TRUE(spdy_stream1); | |
2966 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
2967 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
2968 spdy_stream1->SetDelegate(&delegate1); | |
2969 | |
2970 SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
2971 spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND); | |
2972 | |
2973 // Set up the TaskObserver to verify that SpdySession::DoReadLoop posts a | |
2974 // task. | |
2975 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop"); | |
2976 | |
2977 EXPECT_EQ(0u, delegate1.stream_id()); | |
2978 EXPECT_EQ(0u, observer.executed_count()); | |
2979 | |
2980 // Read all the data and verify that SpdySession::DoReadLoop has posted a | |
2981 // task. | |
2982 base::RunLoop().RunUntilIdle(); | |
2983 EXPECT_EQ(1u, delegate1.stream_id()); | |
2984 EXPECT_FALSE(spdy_stream1); | |
2985 | |
2986 // Verify task that the observer's executed_count is 1, which indicates DoRead | |
2987 // has posted only one task and thus yielded though there is data available | |
2988 // for it to read. | |
2989 EXPECT_EQ(1u, observer.executed_count()); | |
2990 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
2991 EXPECT_TRUE(data.AllReadDataConsumed()); | |
2992 } | |
2993 | |
2994 // Regression test for https://crbug.com/531570. | |
2995 // Test the case where DoRead() takes long but returns synchronously. | |
2996 TEST_F(SpdySessionTest, TestYieldingSlowSynchronousReads) { | |
2997 session_deps_.host_resolver->set_synchronous_mode(true); | |
2998 session_deps_.time_func = SlowReads; | |
2999 | |
3000 SpdySerializedFrame req1( | |
3001 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
3002 MockWrite writes[] = { | |
3003 CreateMockWrite(req1, 0), | |
3004 }; | |
3005 | |
3006 SpdySerializedFrame partial_data_frame( | |
3007 spdy_util_.ConstructSpdyDataFrame(1, "foo ", 4, /*fin=*/false)); | |
3008 SpdySerializedFrame finish_data_frame( | |
3009 spdy_util_.ConstructSpdyDataFrame(1, "bar", 3, /*fin=*/true)); | |
3010 | |
3011 SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
3012 | |
3013 MockRead reads[] = { | |
3014 CreateMockRead(resp1, 1), | |
3015 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
3016 CreateMockRead(partial_data_frame, 3, ASYNC), | |
3017 CreateMockRead(partial_data_frame, 4, SYNCHRONOUS), | |
3018 CreateMockRead(partial_data_frame, 5, SYNCHRONOUS), | |
3019 CreateMockRead(finish_data_frame, 6, SYNCHRONOUS), | |
3020 MockRead(ASYNC, 0, 7) // EOF | |
3021 }; | |
3022 | |
3023 // Create SpdySession and SpdyStream and send the request. | |
3024 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3025 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3026 | |
3027 AddSSLSocketData(); | |
3028 | |
3029 CreateNetworkSession(); | |
3030 CreateSecureSpdySession(); | |
3031 | |
3032 base::WeakPtr<SpdyStream> spdy_stream1 = | |
3033 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
3034 test_url_, MEDIUM, NetLogWithSource()); | |
3035 ASSERT_TRUE(spdy_stream1); | |
3036 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
3037 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
3038 spdy_stream1->SetDelegate(&delegate1); | |
3039 | |
3040 SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
3041 spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND); | |
3042 | |
3043 // Run until 1st read. | |
3044 EXPECT_EQ(0u, delegate1.stream_id()); | |
3045 base::RunLoop().RunUntilIdle(); | |
3046 EXPECT_EQ(1u, delegate1.stream_id()); | |
3047 | |
3048 // Read all the data and verify SpdySession::DoReadLoop has posted a task. | |
3049 data.Resume(); | |
3050 base::RunLoop().RunUntilIdle(); | |
3051 EXPECT_EQ("foo foo foo bar", delegate1.TakeReceivedData()); | |
3052 EXPECT_FALSE(spdy_stream1); | |
3053 | |
3054 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
3055 EXPECT_TRUE(data.AllReadDataConsumed()); | |
3056 } | |
3057 | |
3058 // Test that SpdySession::DoReadLoop yields while reading the | |
3059 // data. This test makes 32k + 1 bytes of data available on the socket | |
3060 // for reading. It then verifies that DoRead has yielded even though | |
3061 // there is data available for it to read (i.e, socket()->Read didn't | |
3062 // return ERR_IO_PENDING during socket reads). | |
3063 TEST_F(SpdySessionTest, TestYieldingDuringReadData) { | |
3064 session_deps_.host_resolver->set_synchronous_mode(true); | |
3065 session_deps_.time_func = InstantaneousReads; | |
3066 | |
3067 BufferedSpdyFramer framer; | |
3068 | |
3069 SpdySerializedFrame req1( | |
3070 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
3071 MockWrite writes[] = { | |
3072 CreateMockWrite(req1, 0), | |
3073 }; | |
3074 | |
3075 // Build buffer of size kYieldAfterBytesRead / 4 | |
3076 // (-spdy_data_frame_size). | |
3077 ASSERT_EQ(32 * 1024, kYieldAfterBytesRead); | |
3078 const int kPayloadSize = | |
3079 kYieldAfterBytesRead / 4 - framer.GetFrameHeaderSize(); | |
3080 TestDataStream test_stream; | |
3081 scoped_refptr<IOBuffer> payload(new IOBuffer(kPayloadSize)); | |
3082 char* payload_data = payload->data(); | |
3083 test_stream.GetBytes(payload_data, kPayloadSize); | |
3084 | |
3085 SpdySerializedFrame partial_data_frame(spdy_util_.ConstructSpdyDataFrame( | |
3086 1, payload_data, kPayloadSize, /*fin=*/false)); | |
3087 SpdySerializedFrame finish_data_frame( | |
3088 spdy_util_.ConstructSpdyDataFrame(1, "h", 1, /*fin=*/true)); | |
3089 | |
3090 SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
3091 | |
3092 // Write 1 byte more than kMaxReadBytes to check that DoRead yields. | |
3093 MockRead reads[] = { | |
3094 CreateMockRead(resp1, 1), | |
3095 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
3096 CreateMockRead(partial_data_frame, 3), | |
3097 CreateMockRead(partial_data_frame, 4, SYNCHRONOUS), | |
3098 CreateMockRead(partial_data_frame, 5, SYNCHRONOUS), | |
3099 CreateMockRead(partial_data_frame, 6, SYNCHRONOUS), | |
3100 CreateMockRead(finish_data_frame, 7, SYNCHRONOUS), | |
3101 MockRead(ASYNC, 0, 8) // EOF | |
3102 }; | |
3103 | |
3104 // Create SpdySession and SpdyStream and send the request. | |
3105 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3106 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3107 | |
3108 AddSSLSocketData(); | |
3109 | |
3110 CreateNetworkSession(); | |
3111 CreateSecureSpdySession(); | |
3112 | |
3113 base::WeakPtr<SpdyStream> spdy_stream1 = | |
3114 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
3115 test_url_, MEDIUM, NetLogWithSource()); | |
3116 ASSERT_TRUE(spdy_stream1); | |
3117 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
3118 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
3119 spdy_stream1->SetDelegate(&delegate1); | |
3120 | |
3121 SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
3122 spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND); | |
3123 | |
3124 // Set up the TaskObserver to verify SpdySession::DoReadLoop posts a task. | |
3125 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop"); | |
3126 | |
3127 // Run until 1st read. | |
3128 EXPECT_EQ(0u, delegate1.stream_id()); | |
3129 base::RunLoop().RunUntilIdle(); | |
3130 EXPECT_EQ(1u, delegate1.stream_id()); | |
3131 EXPECT_EQ(0u, observer.executed_count()); | |
3132 | |
3133 // Read all the data and verify SpdySession::DoReadLoop has posted a task. | |
3134 data.Resume(); | |
3135 base::RunLoop().RunUntilIdle(); | |
3136 EXPECT_FALSE(spdy_stream1); | |
3137 | |
3138 // Verify task observer's executed_count is 1, which indicates DoRead has | |
3139 // posted only one task and thus yielded though there is data available for it | |
3140 // to read. | |
3141 EXPECT_EQ(1u, observer.executed_count()); | |
3142 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
3143 EXPECT_TRUE(data.AllReadDataConsumed()); | |
3144 } | |
3145 | |
3146 // Test that SpdySession::DoReadLoop() tests interactions of yielding | |
3147 // + async, by doing the following MockReads. | |
3148 // | |
3149 // MockRead of SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K | |
3150 // ASYNC 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K. | |
3151 // | |
3152 // The above reads 26K synchronously. Since that is less that 32K, we | |
3153 // will attempt to read again. However, that DoRead() will return | |
3154 // ERR_IO_PENDING (because of async read), so DoReadLoop() will | |
3155 // yield. When we come back, DoRead() will read the results from the | |
3156 // async read, and rest of the data synchronously. | |
3157 TEST_F(SpdySessionTest, TestYieldingDuringAsyncReadData) { | |
3158 session_deps_.host_resolver->set_synchronous_mode(true); | |
3159 session_deps_.time_func = InstantaneousReads; | |
3160 | |
3161 BufferedSpdyFramer framer; | |
3162 | |
3163 SpdySerializedFrame req1( | |
3164 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
3165 MockWrite writes[] = { | |
3166 CreateMockWrite(req1, 0), | |
3167 }; | |
3168 | |
3169 // Build buffer of size kYieldAfterBytesRead / 4 | |
3170 // (-spdy_data_frame_size). | |
3171 ASSERT_EQ(32 * 1024, kYieldAfterBytesRead); | |
3172 TestDataStream test_stream; | |
3173 const int kEightKPayloadSize = | |
3174 kYieldAfterBytesRead / 4 - framer.GetFrameHeaderSize(); | |
3175 scoped_refptr<IOBuffer> eightk_payload(new IOBuffer(kEightKPayloadSize)); | |
3176 char* eightk_payload_data = eightk_payload->data(); | |
3177 test_stream.GetBytes(eightk_payload_data, kEightKPayloadSize); | |
3178 | |
3179 // Build buffer of 2k size. | |
3180 TestDataStream test_stream2; | |
3181 const int kTwoKPayloadSize = kEightKPayloadSize - 6 * 1024; | |
3182 scoped_refptr<IOBuffer> twok_payload(new IOBuffer(kTwoKPayloadSize)); | |
3183 char* twok_payload_data = twok_payload->data(); | |
3184 test_stream2.GetBytes(twok_payload_data, kTwoKPayloadSize); | |
3185 | |
3186 SpdySerializedFrame eightk_data_frame(spdy_util_.ConstructSpdyDataFrame( | |
3187 1, eightk_payload_data, kEightKPayloadSize, /*fin=*/false)); | |
3188 SpdySerializedFrame twok_data_frame(spdy_util_.ConstructSpdyDataFrame( | |
3189 1, twok_payload_data, kTwoKPayloadSize, /*fin=*/false)); | |
3190 SpdySerializedFrame finish_data_frame( | |
3191 spdy_util_.ConstructSpdyDataFrame(1, "h", 1, /*fin=*/true)); | |
3192 | |
3193 SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
3194 | |
3195 MockRead reads[] = { | |
3196 CreateMockRead(resp1, 1), | |
3197 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
3198 CreateMockRead(eightk_data_frame, 3), | |
3199 CreateMockRead(eightk_data_frame, 4, SYNCHRONOUS), | |
3200 CreateMockRead(eightk_data_frame, 5, SYNCHRONOUS), | |
3201 CreateMockRead(twok_data_frame, 6, SYNCHRONOUS), | |
3202 CreateMockRead(eightk_data_frame, 7, ASYNC), | |
3203 CreateMockRead(eightk_data_frame, 8, SYNCHRONOUS), | |
3204 CreateMockRead(eightk_data_frame, 9, SYNCHRONOUS), | |
3205 CreateMockRead(eightk_data_frame, 10, SYNCHRONOUS), | |
3206 CreateMockRead(twok_data_frame, 11, SYNCHRONOUS), | |
3207 CreateMockRead(finish_data_frame, 12, SYNCHRONOUS), | |
3208 MockRead(ASYNC, 0, 13) // EOF | |
3209 }; | |
3210 | |
3211 // Create SpdySession and SpdyStream and send the request. | |
3212 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3213 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3214 | |
3215 AddSSLSocketData(); | |
3216 | |
3217 CreateNetworkSession(); | |
3218 CreateSecureSpdySession(); | |
3219 | |
3220 base::WeakPtr<SpdyStream> spdy_stream1 = | |
3221 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
3222 test_url_, MEDIUM, NetLogWithSource()); | |
3223 ASSERT_TRUE(spdy_stream1); | |
3224 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
3225 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
3226 spdy_stream1->SetDelegate(&delegate1); | |
3227 | |
3228 SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
3229 spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND); | |
3230 | |
3231 // Set up the TaskObserver to monitor SpdySession::DoReadLoop | |
3232 // posting of tasks. | |
3233 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop"); | |
3234 | |
3235 // Run until 1st read. | |
3236 EXPECT_EQ(0u, delegate1.stream_id()); | |
3237 base::RunLoop().RunUntilIdle(); | |
3238 EXPECT_EQ(1u, delegate1.stream_id()); | |
3239 EXPECT_EQ(0u, observer.executed_count()); | |
3240 | |
3241 // Read all the data and verify SpdySession::DoReadLoop has posted a | |
3242 // task. | |
3243 data.Resume(); | |
3244 base::RunLoop().RunUntilIdle(); | |
3245 EXPECT_FALSE(spdy_stream1); | |
3246 | |
3247 // Verify task observer's executed_count is 1, which indicates DoRead has | |
3248 // posted only one task and thus yielded though there is data available for | |
3249 // it to read. | |
3250 EXPECT_EQ(1u, observer.executed_count()); | |
3251 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
3252 EXPECT_TRUE(data.AllReadDataConsumed()); | |
3253 } | |
3254 | |
3255 // Send a GoAway frame when SpdySession is in DoReadLoop. Make sure | |
3256 // nothing blows up. | |
3257 TEST_F(SpdySessionTest, GoAwayWhileInDoReadLoop) { | |
3258 session_deps_.host_resolver->set_synchronous_mode(true); | |
3259 | |
3260 SpdySerializedFrame req1( | |
3261 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
3262 MockWrite writes[] = { | |
3263 CreateMockWrite(req1, 0), | |
3264 }; | |
3265 | |
3266 SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
3267 SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true)); | |
3268 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway()); | |
3269 | |
3270 MockRead reads[] = { | |
3271 CreateMockRead(resp1, 1), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
3272 CreateMockRead(body1, 3), CreateMockRead(goaway, 4), | |
3273 }; | |
3274 | |
3275 // Create SpdySession and SpdyStream and send the request. | |
3276 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3277 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3278 | |
3279 AddSSLSocketData(); | |
3280 | |
3281 CreateNetworkSession(); | |
3282 CreateSecureSpdySession(); | |
3283 | |
3284 base::WeakPtr<SpdyStream> spdy_stream1 = | |
3285 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
3286 test_url_, MEDIUM, NetLogWithSource()); | |
3287 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
3288 spdy_stream1->SetDelegate(&delegate1); | |
3289 ASSERT_TRUE(spdy_stream1); | |
3290 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
3291 | |
3292 SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
3293 spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND); | |
3294 | |
3295 // Run until 1st read. | |
3296 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
3297 base::RunLoop().RunUntilIdle(); | |
3298 EXPECT_EQ(1u, spdy_stream1->stream_id()); | |
3299 | |
3300 // Run until GoAway. | |
3301 data.Resume(); | |
3302 base::RunLoop().RunUntilIdle(); | |
3303 EXPECT_FALSE(spdy_stream1); | |
3304 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
3305 EXPECT_TRUE(data.AllReadDataConsumed()); | |
3306 EXPECT_FALSE(session_); | |
3307 } | |
3308 | |
3309 // Within this framework, a SpdySession should be initialized with | |
3310 // flow control disabled for protocol version 2, with flow control | |
3311 // enabled only for streams for protocol version 3, and with flow | |
3312 // control enabled for streams and sessions for higher versions. | |
3313 TEST_F(SpdySessionTest, ProtocolNegotiation) { | |
3314 session_deps_.host_resolver->set_synchronous_mode(true); | |
3315 | |
3316 MockRead reads[] = { | |
3317 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
3318 }; | |
3319 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
3320 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3321 | |
3322 CreateNetworkSession(); | |
3323 session_ = CreateFakeSpdySession(spdy_session_pool_, key_); | |
3324 | |
3325 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_send_window_size_); | |
3326 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
3327 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
3328 } | |
3329 | |
3330 // Tests the case of a non-SPDY request closing an idle SPDY session when no | |
3331 // pointers to the idle session are currently held. | |
3332 TEST_F(SpdySessionTest, CloseOneIdleConnection) { | |
3333 ClientSocketPoolManager::set_max_sockets_per_group( | |
3334 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3335 ClientSocketPoolManager::set_max_sockets_per_pool( | |
3336 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3337 | |
3338 MockRead reads[] = { | |
3339 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
3340 }; | |
3341 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
3342 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3343 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3344 | |
3345 AddSSLSocketData(); | |
3346 | |
3347 CreateNetworkSession(); | |
3348 | |
3349 TransportClientSocketPool* pool = | |
3350 http_session_->GetTransportSocketPool( | |
3351 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
3352 | |
3353 // Create an idle SPDY session. | |
3354 CreateSecureSpdySession(); | |
3355 EXPECT_FALSE(pool->IsStalled()); | |
3356 | |
3357 // Trying to create a new connection should cause the pool to be stalled, and | |
3358 // post a task asynchronously to try and close the session. | |
3359 TestCompletionCallback callback2; | |
3360 HostPortPair host_port2("2.com", 80); | |
3361 scoped_refptr<TransportSocketParams> params2(new TransportSocketParams( | |
3362 host_port2, false, OnHostResolutionCallback(), | |
3363 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); | |
3364 std::unique_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); | |
3365 EXPECT_EQ(ERR_IO_PENDING, | |
3366 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, | |
3367 ClientSocketPool::RespectLimits::ENABLED, | |
3368 callback2.callback(), pool, NetLogWithSource())); | |
3369 EXPECT_TRUE(pool->IsStalled()); | |
3370 | |
3371 // The socket pool should close the connection asynchronously and establish a | |
3372 // new connection. | |
3373 EXPECT_THAT(callback2.WaitForResult(), IsOk()); | |
3374 EXPECT_FALSE(pool->IsStalled()); | |
3375 EXPECT_FALSE(session_); | |
3376 } | |
3377 | |
3378 // Tests the case of a non-SPDY request closing an idle SPDY session when no | |
3379 // pointers to the idle session are currently held, in the case the SPDY session | |
3380 // has an alias. | |
3381 TEST_F(SpdySessionTest, CloseOneIdleConnectionWithAlias) { | |
3382 ClientSocketPoolManager::set_max_sockets_per_group( | |
3383 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3384 ClientSocketPoolManager::set_max_sockets_per_pool( | |
3385 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3386 | |
3387 MockRead reads[] = { | |
3388 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
3389 }; | |
3390 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
3391 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3392 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3393 | |
3394 AddSSLSocketData(); | |
3395 | |
3396 session_deps_.host_resolver->set_synchronous_mode(true); | |
3397 session_deps_.host_resolver->rules()->AddIPLiteralRule( | |
3398 "www.example.org", "192.168.0.2", SpdyString()); | |
3399 session_deps_.host_resolver->rules()->AddIPLiteralRule( | |
3400 "mail.example.org", "192.168.0.2", SpdyString()); | |
3401 // Not strictly needed. | |
3402 session_deps_.host_resolver->rules()->AddIPLiteralRule("3.com", "192.168.0.3", | |
3403 SpdyString()); | |
3404 | |
3405 CreateNetworkSession(); | |
3406 | |
3407 TransportClientSocketPool* pool = | |
3408 http_session_->GetTransportSocketPool( | |
3409 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
3410 | |
3411 // Create an idle SPDY session. | |
3412 SpdySessionKey key1(HostPortPair("www.example.org", 80), | |
3413 ProxyServer::Direct(), PRIVACY_MODE_DISABLED); | |
3414 base::WeakPtr<SpdySession> session1 = ::net::CreateSecureSpdySession( | |
3415 http_session_.get(), key1, NetLogWithSource()); | |
3416 EXPECT_FALSE(pool->IsStalled()); | |
3417 | |
3418 // Set up an alias for the idle SPDY session, increasing its ref count to 2. | |
3419 SpdySessionKey key2(HostPortPair("mail.example.org", 80), | |
3420 ProxyServer::Direct(), PRIVACY_MODE_DISABLED); | |
3421 HostResolver::RequestInfo info(key2.host_port_pair()); | |
3422 AddressList addresses; | |
3423 std::unique_ptr<HostResolver::Request> request; | |
3424 // Pre-populate the DNS cache, since a synchronous resolution is required in | |
3425 // order to create the alias. | |
3426 session_deps_.host_resolver->Resolve(info, DEFAULT_PRIORITY, &addresses, | |
3427 CompletionCallback(), &request, | |
3428 NetLogWithSource()); | |
3429 // Get a session for |key2|, which should return the session created earlier. | |
3430 base::WeakPtr<SpdySession> session2 = | |
3431 spdy_session_pool_->FindAvailableSession( | |
3432 key2, GURL(), | |
3433 /* enable_ip_based_pooling = */ true, NetLogWithSource()); | |
3434 ASSERT_EQ(session1.get(), session2.get()); | |
3435 EXPECT_FALSE(pool->IsStalled()); | |
3436 | |
3437 // Trying to create a new connection should cause the pool to be stalled, and | |
3438 // post a task asynchronously to try and close the session. | |
3439 TestCompletionCallback callback3; | |
3440 HostPortPair host_port3("3.com", 80); | |
3441 scoped_refptr<TransportSocketParams> params3(new TransportSocketParams( | |
3442 host_port3, false, OnHostResolutionCallback(), | |
3443 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); | |
3444 std::unique_ptr<ClientSocketHandle> connection3(new ClientSocketHandle); | |
3445 EXPECT_EQ(ERR_IO_PENDING, | |
3446 connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY, | |
3447 ClientSocketPool::RespectLimits::ENABLED, | |
3448 callback3.callback(), pool, NetLogWithSource())); | |
3449 EXPECT_TRUE(pool->IsStalled()); | |
3450 | |
3451 // The socket pool should close the connection asynchronously and establish a | |
3452 // new connection. | |
3453 EXPECT_THAT(callback3.WaitForResult(), IsOk()); | |
3454 EXPECT_FALSE(pool->IsStalled()); | |
3455 EXPECT_FALSE(session1); | |
3456 EXPECT_FALSE(session2); | |
3457 } | |
3458 | |
3459 // Tests that when a SPDY session becomes idle, it closes itself if there is | |
3460 // a lower layer pool stalled on the per-pool socket limit. | |
3461 TEST_F(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) { | |
3462 ClientSocketPoolManager::set_max_sockets_per_group( | |
3463 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3464 ClientSocketPoolManager::set_max_sockets_per_pool( | |
3465 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3466 | |
3467 MockRead reads[] = { | |
3468 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
3469 }; | |
3470 SpdySerializedFrame req1( | |
3471 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
3472 SpdySerializedFrame cancel1( | |
3473 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
3474 MockWrite writes[] = { | |
3475 CreateMockWrite(req1, 1), CreateMockWrite(cancel1, 1), | |
3476 }; | |
3477 StaticSocketDataProvider data(reads, arraysize(reads), | |
3478 writes, arraysize(writes)); | |
3479 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3480 | |
3481 MockRead http_reads[] = { | |
3482 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
3483 }; | |
3484 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr, | |
3485 0); | |
3486 session_deps_.socket_factory->AddSocketDataProvider(&http_data); | |
3487 | |
3488 AddSSLSocketData(); | |
3489 | |
3490 CreateNetworkSession(); | |
3491 | |
3492 TransportClientSocketPool* pool = | |
3493 http_session_->GetTransportSocketPool( | |
3494 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
3495 | |
3496 // Create a SPDY session. | |
3497 CreateSecureSpdySession(); | |
3498 EXPECT_FALSE(pool->IsStalled()); | |
3499 | |
3500 // Create a stream using the session, and send a request. | |
3501 | |
3502 TestCompletionCallback callback1; | |
3503 base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously( | |
3504 SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, DEFAULT_PRIORITY, | |
3505 NetLogWithSource()); | |
3506 ASSERT_TRUE(spdy_stream1.get()); | |
3507 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
3508 spdy_stream1->SetDelegate(&delegate1); | |
3509 | |
3510 SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
3511 EXPECT_EQ(ERR_IO_PENDING, spdy_stream1->SendRequestHeaders( | |
3512 std::move(headers1), NO_MORE_DATA_TO_SEND)); | |
3513 | |
3514 base::RunLoop().RunUntilIdle(); | |
3515 | |
3516 // Trying to create a new connection should cause the pool to be stalled, and | |
3517 // post a task asynchronously to try and close the session. | |
3518 TestCompletionCallback callback2; | |
3519 HostPortPair host_port2("2.com", 80); | |
3520 scoped_refptr<TransportSocketParams> params2(new TransportSocketParams( | |
3521 host_port2, false, OnHostResolutionCallback(), | |
3522 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); | |
3523 std::unique_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); | |
3524 EXPECT_EQ(ERR_IO_PENDING, | |
3525 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, | |
3526 ClientSocketPool::RespectLimits::ENABLED, | |
3527 callback2.callback(), pool, NetLogWithSource())); | |
3528 EXPECT_TRUE(pool->IsStalled()); | |
3529 | |
3530 // Running the message loop should cause the socket pool to ask the SPDY | |
3531 // session to close an idle socket, but since the socket is in use, nothing | |
3532 // happens. | |
3533 base::RunLoop().RunUntilIdle(); | |
3534 EXPECT_TRUE(pool->IsStalled()); | |
3535 EXPECT_FALSE(callback2.have_result()); | |
3536 | |
3537 // Cancelling the request should result in the session's socket being | |
3538 // closed, since the pool is stalled. | |
3539 ASSERT_TRUE(spdy_stream1.get()); | |
3540 spdy_stream1->Cancel(); | |
3541 base::RunLoop().RunUntilIdle(); | |
3542 ASSERT_FALSE(pool->IsStalled()); | |
3543 EXPECT_THAT(callback2.WaitForResult(), IsOk()); | |
3544 } | |
3545 | |
3546 // Verify that SpdySessionKey and therefore SpdySession is different when | |
3547 // privacy mode is enabled or disabled. | |
3548 TEST_F(SpdySessionTest, SpdySessionKeyPrivacyMode) { | |
3549 CreateNetworkSession(); | |
3550 | |
3551 HostPortPair host_port_pair("www.example.org", 443); | |
3552 SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(), | |
3553 PRIVACY_MODE_ENABLED); | |
3554 SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(), | |
3555 PRIVACY_MODE_DISABLED); | |
3556 | |
3557 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); | |
3558 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); | |
3559 | |
3560 // Add SpdySession with PrivacyMode Enabled to the pool. | |
3561 base::WeakPtr<SpdySession> session_privacy_enabled = | |
3562 CreateFakeSpdySession(spdy_session_pool_, key_privacy_enabled); | |
3563 | |
3564 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); | |
3565 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); | |
3566 | |
3567 // Add SpdySession with PrivacyMode Disabled to the pool. | |
3568 base::WeakPtr<SpdySession> session_privacy_disabled = | |
3569 CreateFakeSpdySession(spdy_session_pool_, key_privacy_disabled); | |
3570 | |
3571 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); | |
3572 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); | |
3573 | |
3574 session_privacy_enabled->CloseSessionOnError(ERR_ABORTED, SpdyString()); | |
3575 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); | |
3576 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); | |
3577 | |
3578 session_privacy_disabled->CloseSessionOnError(ERR_ABORTED, SpdyString()); | |
3579 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); | |
3580 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); | |
3581 } | |
3582 | |
3583 // Delegate that creates another stream when its stream is closed. | |
3584 class StreamCreatingDelegate : public test::StreamDelegateDoNothing { | |
3585 public: | |
3586 StreamCreatingDelegate(const base::WeakPtr<SpdyStream>& stream, | |
3587 const base::WeakPtr<SpdySession>& session) | |
3588 : StreamDelegateDoNothing(stream), | |
3589 session_(session) {} | |
3590 | |
3591 ~StreamCreatingDelegate() override {} | |
3592 | |
3593 void OnClose(int status) override { | |
3594 GURL url(kDefaultUrl); | |
3595 ignore_result(CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, | |
3596 session_, url, MEDIUM, | |
3597 NetLogWithSource())); | |
3598 } | |
3599 | |
3600 private: | |
3601 const base::WeakPtr<SpdySession> session_; | |
3602 }; | |
3603 | |
3604 // Create another stream in response to a stream being reset. Nothing | |
3605 // should blow up. This is a regression test for | |
3606 // http://crbug.com/263690 . | |
3607 TEST_F(SpdySessionTest, CreateStreamOnStreamReset) { | |
3608 session_deps_.host_resolver->set_synchronous_mode(true); | |
3609 | |
3610 SpdySerializedFrame req( | |
3611 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true)); | |
3612 MockWrite writes[] = { | |
3613 CreateMockWrite(req, 0), | |
3614 }; | |
3615 | |
3616 SpdySerializedFrame rst( | |
3617 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_REFUSED_STREAM)); | |
3618 MockRead reads[] = { | |
3619 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(rst, 2), | |
3620 MockRead(ASYNC, ERR_IO_PENDING, 3), MockRead(ASYNC, 0, 4) // EOF | |
3621 }; | |
3622 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3623 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3624 | |
3625 AddSSLSocketData(); | |
3626 | |
3627 CreateNetworkSession(); | |
3628 CreateSecureSpdySession(); | |
3629 | |
3630 base::WeakPtr<SpdyStream> spdy_stream = | |
3631 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
3632 test_url_, MEDIUM, NetLogWithSource()); | |
3633 ASSERT_TRUE(spdy_stream); | |
3634 EXPECT_EQ(0u, spdy_stream->stream_id()); | |
3635 | |
3636 StreamCreatingDelegate delegate(spdy_stream, session_); | |
3637 spdy_stream->SetDelegate(&delegate); | |
3638 | |
3639 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
3640 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
3641 | |
3642 EXPECT_EQ(0u, spdy_stream->stream_id()); | |
3643 | |
3644 base::RunLoop().RunUntilIdle(); | |
3645 | |
3646 EXPECT_EQ(1u, spdy_stream->stream_id()); | |
3647 | |
3648 // Cause the stream to be reset, which should cause another stream | |
3649 // to be created. | |
3650 data.Resume(); | |
3651 base::RunLoop().RunUntilIdle(); | |
3652 | |
3653 EXPECT_FALSE(spdy_stream); | |
3654 EXPECT_TRUE(delegate.StreamIsClosed()); | |
3655 EXPECT_EQ(0u, session_->num_active_streams()); | |
3656 EXPECT_EQ(1u, session_->num_created_streams()); | |
3657 | |
3658 data.Resume(); | |
3659 base::RunLoop().RunUntilIdle(); | |
3660 EXPECT_FALSE(session_); | |
3661 } | |
3662 | |
3663 TEST_F(SpdySessionTest, UpdateStreamsSendWindowSize) { | |
3664 // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE | |
3665 // gets sent. | |
3666 SettingsMap new_settings; | |
3667 int32_t window_size = 1; | |
3668 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] = window_size; | |
3669 | |
3670 // Set up the socket so we read a SETTINGS frame that sets | |
3671 // INITIAL_WINDOW_SIZE. | |
3672 SpdySerializedFrame settings_frame( | |
3673 spdy_util_.ConstructSpdySettings(new_settings)); | |
3674 MockRead reads[] = { | |
3675 CreateMockRead(settings_frame, 0), MockRead(ASYNC, ERR_IO_PENDING, 1), | |
3676 MockRead(ASYNC, 0, 2) // EOF | |
3677 }; | |
3678 | |
3679 SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
3680 MockWrite writes[] = { | |
3681 CreateMockWrite(settings_ack, 3), | |
3682 }; | |
3683 | |
3684 session_deps_.host_resolver->set_synchronous_mode(true); | |
3685 | |
3686 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3687 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3688 | |
3689 AddSSLSocketData(); | |
3690 | |
3691 CreateNetworkSession(); | |
3692 CreateSecureSpdySession(); | |
3693 base::WeakPtr<SpdyStream> spdy_stream1 = | |
3694 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
3695 MEDIUM, NetLogWithSource()); | |
3696 ASSERT_TRUE(spdy_stream1); | |
3697 TestCompletionCallback callback1; | |
3698 EXPECT_NE(spdy_stream1->send_window_size(), window_size); | |
3699 | |
3700 // Process the SETTINGS frame. | |
3701 base::RunLoop().RunUntilIdle(); | |
3702 EXPECT_EQ(session_->stream_initial_send_window_size(), window_size); | |
3703 EXPECT_EQ(spdy_stream1->send_window_size(), window_size); | |
3704 | |
3705 // Release the first one, this will allow the second to be created. | |
3706 spdy_stream1->Cancel(); | |
3707 EXPECT_FALSE(spdy_stream1); | |
3708 | |
3709 base::WeakPtr<SpdyStream> spdy_stream2 = | |
3710 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
3711 MEDIUM, NetLogWithSource()); | |
3712 ASSERT_TRUE(spdy_stream2); | |
3713 EXPECT_EQ(spdy_stream2->send_window_size(), window_size); | |
3714 spdy_stream2->Cancel(); | |
3715 EXPECT_FALSE(spdy_stream2); | |
3716 | |
3717 EXPECT_TRUE(session_); | |
3718 data.Resume(); | |
3719 base::RunLoop().RunUntilIdle(); | |
3720 EXPECT_FALSE(session_); | |
3721 } | |
3722 | |
3723 // SpdySession::{Increase,Decrease}RecvWindowSize should properly | |
3724 // adjust the session receive window size. In addition, | |
3725 // SpdySession::IncreaseRecvWindowSize should trigger | |
3726 // sending a WINDOW_UPDATE frame for a large enough delta. | |
3727 TEST_F(SpdySessionTest, AdjustRecvWindowSize) { | |
3728 session_deps_.host_resolver->set_synchronous_mode(true); | |
3729 | |
3730 const int32_t initial_window_size = kDefaultInitialWindowSize; | |
3731 const int32_t delta_window_size = 100; | |
3732 | |
3733 MockRead reads[] = { | |
3734 MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2) // EOF | |
3735 }; | |
3736 SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate( | |
3737 kSessionFlowControlStreamId, initial_window_size + delta_window_size)); | |
3738 MockWrite writes[] = { | |
3739 CreateMockWrite(window_update, 0), | |
3740 }; | |
3741 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3742 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3743 | |
3744 AddSSLSocketData(); | |
3745 | |
3746 CreateNetworkSession(); | |
3747 CreateSecureSpdySession(); | |
3748 | |
3749 EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); | |
3750 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
3751 | |
3752 session_->IncreaseRecvWindowSize(delta_window_size); | |
3753 EXPECT_EQ(initial_window_size + delta_window_size, | |
3754 session_->session_recv_window_size_); | |
3755 EXPECT_EQ(delta_window_size, session_->session_unacked_recv_window_bytes_); | |
3756 | |
3757 // Should trigger sending a WINDOW_UPDATE frame. | |
3758 session_->IncreaseRecvWindowSize(initial_window_size); | |
3759 EXPECT_EQ(initial_window_size + delta_window_size + initial_window_size, | |
3760 session_->session_recv_window_size_); | |
3761 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
3762 | |
3763 base::RunLoop().RunUntilIdle(); | |
3764 | |
3765 // DecreaseRecvWindowSize() expects |in_io_loop_| to be true. | |
3766 session_->in_io_loop_ = true; | |
3767 session_->DecreaseRecvWindowSize(initial_window_size + delta_window_size + | |
3768 initial_window_size); | |
3769 session_->in_io_loop_ = false; | |
3770 EXPECT_EQ(0, session_->session_recv_window_size_); | |
3771 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
3772 | |
3773 EXPECT_TRUE(session_); | |
3774 data.Resume(); | |
3775 base::RunLoop().RunUntilIdle(); | |
3776 EXPECT_FALSE(session_); | |
3777 } | |
3778 | |
3779 // SpdySession::{Increase,Decrease}SendWindowSize should properly | |
3780 // adjust the session send window size when the "enable_spdy_31" flag | |
3781 // is set. | |
3782 TEST_F(SpdySessionTest, AdjustSendWindowSize) { | |
3783 session_deps_.host_resolver->set_synchronous_mode(true); | |
3784 | |
3785 MockRead reads[] = { | |
3786 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
3787 }; | |
3788 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
3789 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3790 | |
3791 CreateNetworkSession(); | |
3792 session_ = CreateFakeSpdySession(spdy_session_pool_, key_); | |
3793 | |
3794 const int32_t initial_window_size = kDefaultInitialWindowSize; | |
3795 const int32_t delta_window_size = 100; | |
3796 | |
3797 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
3798 | |
3799 session_->IncreaseSendWindowSize(delta_window_size); | |
3800 EXPECT_EQ(initial_window_size + delta_window_size, | |
3801 session_->session_send_window_size_); | |
3802 | |
3803 session_->DecreaseSendWindowSize(delta_window_size); | |
3804 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
3805 } | |
3806 | |
3807 // Incoming data for an inactive stream should not cause the session | |
3808 // receive window size to decrease, but it should cause the unacked | |
3809 // bytes to increase. | |
3810 TEST_F(SpdySessionTest, SessionFlowControlInactiveStream) { | |
3811 session_deps_.host_resolver->set_synchronous_mode(true); | |
3812 | |
3813 SpdySerializedFrame resp(spdy_util_.ConstructSpdyDataFrame(1, false)); | |
3814 MockRead reads[] = { | |
3815 CreateMockRead(resp, 0), MockRead(ASYNC, ERR_IO_PENDING, 1), | |
3816 MockRead(ASYNC, 0, 2) // EOF | |
3817 }; | |
3818 SequencedSocketData data(reads, arraysize(reads), nullptr, 0); | |
3819 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3820 | |
3821 AddSSLSocketData(); | |
3822 | |
3823 CreateNetworkSession(); | |
3824 CreateSecureSpdySession(); | |
3825 | |
3826 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
3827 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
3828 | |
3829 base::RunLoop().RunUntilIdle(); | |
3830 | |
3831 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
3832 EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); | |
3833 | |
3834 EXPECT_TRUE(session_); | |
3835 data.Resume(); | |
3836 base::RunLoop().RunUntilIdle(); | |
3837 EXPECT_FALSE(session_); | |
3838 } | |
3839 | |
3840 // The frame header is not included in flow control, but frame payload | |
3841 // (including optional pad length and padding) is. | |
3842 TEST_F(SpdySessionTest, SessionFlowControlPadding) { | |
3843 session_deps_.host_resolver->set_synchronous_mode(true); | |
3844 | |
3845 const int padding_length = 42; | |
3846 SpdySerializedFrame resp(spdy_util_.ConstructSpdyDataFrame( | |
3847 1, kUploadData, kUploadDataSize, false, padding_length)); | |
3848 MockRead reads[] = { | |
3849 CreateMockRead(resp, 0), MockRead(ASYNC, ERR_IO_PENDING, 1), | |
3850 MockRead(ASYNC, 0, 2) // EOF | |
3851 }; | |
3852 SequencedSocketData data(reads, arraysize(reads), nullptr, 0); | |
3853 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3854 | |
3855 AddSSLSocketData(); | |
3856 | |
3857 CreateNetworkSession(); | |
3858 CreateSecureSpdySession(); | |
3859 | |
3860 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
3861 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
3862 | |
3863 base::RunLoop().RunUntilIdle(); | |
3864 | |
3865 EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); | |
3866 EXPECT_EQ(kUploadDataSize + padding_length, | |
3867 session_->session_unacked_recv_window_bytes_); | |
3868 | |
3869 data.Resume(); | |
3870 base::RunLoop().RunUntilIdle(); | |
3871 EXPECT_FALSE(session_); | |
3872 } | |
3873 | |
3874 // Peer sends more data than stream level receiving flow control window. | |
3875 TEST_F(SpdySessionTest, StreamFlowControlTooMuchData) { | |
3876 const int32_t stream_max_recv_window_size = 1024; | |
3877 const int32_t data_frame_size = 2 * stream_max_recv_window_size; | |
3878 | |
3879 SpdySerializedFrame req( | |
3880 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
3881 SpdySerializedFrame rst( | |
3882 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_FLOW_CONTROL_ERROR)); | |
3883 MockWrite writes[] = { | |
3884 CreateMockWrite(req, 0), CreateMockWrite(rst, 4), | |
3885 }; | |
3886 | |
3887 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
3888 const SpdyString payload(data_frame_size, 'a'); | |
3889 SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame( | |
3890 1, payload.data(), data_frame_size, false)); | |
3891 MockRead reads[] = { | |
3892 CreateMockRead(resp, 1), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
3893 CreateMockRead(data_frame, 3), MockRead(ASYNC, ERR_IO_PENDING, 5), | |
3894 MockRead(ASYNC, 0, 6), | |
3895 }; | |
3896 | |
3897 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3898 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3899 | |
3900 AddSSLSocketData(); | |
3901 | |
3902 session_deps_.http2_settings[SETTINGS_INITIAL_WINDOW_SIZE] = | |
3903 stream_max_recv_window_size; | |
3904 CreateNetworkSession(); | |
3905 | |
3906 CreateSecureSpdySession(); | |
3907 | |
3908 base::WeakPtr<SpdyStream> spdy_stream = | |
3909 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
3910 test_url_, LOWEST, NetLogWithSource()); | |
3911 EXPECT_EQ(stream_max_recv_window_size, spdy_stream->recv_window_size()); | |
3912 | |
3913 test::StreamDelegateDoNothing delegate(spdy_stream); | |
3914 spdy_stream->SetDelegate(&delegate); | |
3915 | |
3916 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
3917 EXPECT_EQ(ERR_IO_PENDING, spdy_stream->SendRequestHeaders( | |
3918 std::move(headers), NO_MORE_DATA_TO_SEND)); | |
3919 | |
3920 // Request and response. | |
3921 base::RunLoop().RunUntilIdle(); | |
3922 EXPECT_EQ(1u, spdy_stream->stream_id()); | |
3923 | |
3924 // Too large data frame causes flow control error, should close stream. | |
3925 data.Resume(); | |
3926 base::RunLoop().RunUntilIdle(); | |
3927 EXPECT_FALSE(spdy_stream); | |
3928 | |
3929 EXPECT_TRUE(session_); | |
3930 data.Resume(); | |
3931 base::RunLoop().RunUntilIdle(); | |
3932 EXPECT_FALSE(session_); | |
3933 } | |
3934 | |
3935 // Regression test for a bug that was caused by including unsent WINDOW_UPDATE | |
3936 // deltas in the receiving window size when checking incoming frames for flow | |
3937 // control errors at session level. | |
3938 TEST_F(SpdySessionTest, SessionFlowControlTooMuchDataTwoDataFrames) { | |
3939 const int32_t session_max_recv_window_size = 500; | |
3940 const int32_t first_data_frame_size = 200; | |
3941 const int32_t second_data_frame_size = 400; | |
3942 | |
3943 // First data frame should not trigger a WINDOW_UPDATE. | |
3944 ASSERT_GT(session_max_recv_window_size / 2, first_data_frame_size); | |
3945 // Second data frame would be fine had there been a WINDOW_UPDATE. | |
3946 ASSERT_GT(session_max_recv_window_size, second_data_frame_size); | |
3947 // But in fact, the two data frames together overflow the receiving window at | |
3948 // session level. | |
3949 ASSERT_LT(session_max_recv_window_size, | |
3950 first_data_frame_size + second_data_frame_size); | |
3951 | |
3952 session_deps_.host_resolver->set_synchronous_mode(true); | |
3953 | |
3954 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway( | |
3955 0, ERROR_CODE_FLOW_CONTROL_ERROR, | |
3956 "delta_window_size is 400 in DecreaseRecvWindowSize, which is larger " | |
3957 "than the receive window size of 500")); | |
3958 MockWrite writes[] = { | |
3959 CreateMockWrite(goaway, 4), | |
3960 }; | |
3961 | |
3962 const SpdyString first_data_frame(first_data_frame_size, 'a'); | |
3963 SpdySerializedFrame first(spdy_util_.ConstructSpdyDataFrame( | |
3964 1, first_data_frame.data(), first_data_frame_size, false)); | |
3965 const SpdyString second_data_frame(second_data_frame_size, 'b'); | |
3966 SpdySerializedFrame second(spdy_util_.ConstructSpdyDataFrame( | |
3967 1, second_data_frame.data(), second_data_frame_size, false)); | |
3968 MockRead reads[] = { | |
3969 CreateMockRead(first, 0), MockRead(ASYNC, ERR_IO_PENDING, 1), | |
3970 CreateMockRead(second, 2), MockRead(ASYNC, 0, 3), | |
3971 }; | |
3972 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
3973 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3974 | |
3975 AddSSLSocketData(); | |
3976 | |
3977 CreateNetworkSession(); | |
3978 CreateSecureSpdySession(); | |
3979 // Setting session level receiving window size to smaller than initial is not | |
3980 // possible via SpdySessionPoolPeer. | |
3981 session_->session_recv_window_size_ = session_max_recv_window_size; | |
3982 | |
3983 // First data frame is immediately consumed and does not trigger | |
3984 // WINDOW_UPDATE. | |
3985 base::RunLoop().RunUntilIdle(); | |
3986 EXPECT_EQ(first_data_frame_size, | |
3987 session_->session_unacked_recv_window_bytes_); | |
3988 EXPECT_EQ(session_max_recv_window_size, session_->session_recv_window_size_); | |
3989 EXPECT_EQ(SpdySession::STATE_AVAILABLE, session_->availability_state_); | |
3990 | |
3991 // Second data frame overflows receiving window, causes session to close. | |
3992 data.Resume(); | |
3993 base::RunLoop().RunUntilIdle(); | |
3994 EXPECT_EQ(SpdySession::STATE_DRAINING, session_->availability_state_); | |
3995 } | |
3996 | |
3997 // Regression test for a bug that was caused by including unsent WINDOW_UPDATE | |
3998 // deltas in the receiving window size when checking incoming data frames for | |
3999 // flow control errors at stream level. | |
4000 TEST_F(SpdySessionTest, StreamFlowControlTooMuchDataTwoDataFrames) { | |
4001 const int32_t stream_max_recv_window_size = 500; | |
4002 const int32_t first_data_frame_size = 200; | |
4003 const int32_t second_data_frame_size = 400; | |
4004 | |
4005 // First data frame should not trigger a WINDOW_UPDATE. | |
4006 ASSERT_GT(stream_max_recv_window_size / 2, first_data_frame_size); | |
4007 // Second data frame would be fine had there been a WINDOW_UPDATE. | |
4008 ASSERT_GT(stream_max_recv_window_size, second_data_frame_size); | |
4009 // But in fact, they should overflow the receiving window at stream level. | |
4010 ASSERT_LT(stream_max_recv_window_size, | |
4011 first_data_frame_size + second_data_frame_size); | |
4012 | |
4013 SpdySerializedFrame req( | |
4014 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
4015 SpdySerializedFrame rst( | |
4016 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_FLOW_CONTROL_ERROR)); | |
4017 MockWrite writes[] = { | |
4018 CreateMockWrite(req, 0), CreateMockWrite(rst, 6), | |
4019 }; | |
4020 | |
4021 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
4022 const SpdyString first_data_frame(first_data_frame_size, 'a'); | |
4023 SpdySerializedFrame first(spdy_util_.ConstructSpdyDataFrame( | |
4024 1, first_data_frame.data(), first_data_frame_size, false)); | |
4025 const SpdyString second_data_frame(second_data_frame_size, 'b'); | |
4026 SpdySerializedFrame second(spdy_util_.ConstructSpdyDataFrame( | |
4027 1, second_data_frame.data(), second_data_frame_size, false)); | |
4028 MockRead reads[] = { | |
4029 CreateMockRead(resp, 1), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
4030 CreateMockRead(first, 3), MockRead(ASYNC, ERR_IO_PENDING, 4), | |
4031 CreateMockRead(second, 5), MockRead(ASYNC, ERR_IO_PENDING, 7), | |
4032 MockRead(ASYNC, 0, 8), | |
4033 }; | |
4034 | |
4035 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4036 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4037 | |
4038 AddSSLSocketData(); | |
4039 | |
4040 session_deps_.http2_settings[SETTINGS_INITIAL_WINDOW_SIZE] = | |
4041 stream_max_recv_window_size; | |
4042 CreateNetworkSession(); | |
4043 | |
4044 CreateSecureSpdySession(); | |
4045 | |
4046 base::WeakPtr<SpdyStream> spdy_stream = | |
4047 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4048 test_url_, LOWEST, NetLogWithSource()); | |
4049 test::StreamDelegateDoNothing delegate(spdy_stream); | |
4050 spdy_stream->SetDelegate(&delegate); | |
4051 | |
4052 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
4053 EXPECT_EQ(ERR_IO_PENDING, spdy_stream->SendRequestHeaders( | |
4054 std::move(headers), NO_MORE_DATA_TO_SEND)); | |
4055 | |
4056 // Request and response. | |
4057 base::RunLoop().RunUntilIdle(); | |
4058 EXPECT_TRUE(spdy_stream->IsLocallyClosed()); | |
4059 EXPECT_EQ(stream_max_recv_window_size, spdy_stream->recv_window_size()); | |
4060 | |
4061 // First data frame. | |
4062 data.Resume(); | |
4063 base::RunLoop().RunUntilIdle(); | |
4064 EXPECT_TRUE(spdy_stream->IsLocallyClosed()); | |
4065 EXPECT_EQ(stream_max_recv_window_size - first_data_frame_size, | |
4066 spdy_stream->recv_window_size()); | |
4067 | |
4068 // Consume first data frame. This does not trigger a WINDOW_UPDATE. | |
4069 SpdyString received_data = delegate.TakeReceivedData(); | |
4070 EXPECT_EQ(static_cast<size_t>(first_data_frame_size), received_data.size()); | |
4071 EXPECT_EQ(stream_max_recv_window_size, spdy_stream->recv_window_size()); | |
4072 | |
4073 // Second data frame overflows receiving window, causes the stream to close. | |
4074 data.Resume(); | |
4075 base::RunLoop().RunUntilIdle(); | |
4076 EXPECT_FALSE(spdy_stream.get()); | |
4077 | |
4078 // RST_STREAM | |
4079 EXPECT_TRUE(session_); | |
4080 data.Resume(); | |
4081 base::RunLoop().RunUntilIdle(); | |
4082 EXPECT_FALSE(session_); | |
4083 } | |
4084 | |
4085 // A delegate that drops any received data. | |
4086 class DropReceivedDataDelegate : public test::StreamDelegateSendImmediate { | |
4087 public: | |
4088 DropReceivedDataDelegate(const base::WeakPtr<SpdyStream>& stream, | |
4089 SpdyStringPiece data) | |
4090 : StreamDelegateSendImmediate(stream, data) {} | |
4091 | |
4092 ~DropReceivedDataDelegate() override {} | |
4093 | |
4094 // Drop any received data. | |
4095 void OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) override {} | |
4096 }; | |
4097 | |
4098 // Send data back and forth but use a delegate that drops its received | |
4099 // data. The receive window should still increase to its original | |
4100 // value, i.e. we shouldn't "leak" receive window bytes. | |
4101 TEST_F(SpdySessionTest, SessionFlowControlNoReceiveLeaks) { | |
4102 const int32_t kMsgDataSize = 100; | |
4103 const SpdyString msg_data(kMsgDataSize, 'a'); | |
4104 | |
4105 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
4106 kDefaultUrl, 1, kMsgDataSize, MEDIUM, nullptr, 0)); | |
4107 SpdySerializedFrame msg(spdy_util_.ConstructSpdyDataFrame( | |
4108 1, msg_data.data(), kMsgDataSize, false)); | |
4109 MockWrite writes[] = { | |
4110 CreateMockWrite(req, 0), CreateMockWrite(msg, 2), | |
4111 }; | |
4112 | |
4113 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
4114 SpdySerializedFrame echo(spdy_util_.ConstructSpdyDataFrame( | |
4115 1, msg_data.data(), kMsgDataSize, false)); | |
4116 SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate( | |
4117 kSessionFlowControlStreamId, kMsgDataSize)); | |
4118 MockRead reads[] = { | |
4119 CreateMockRead(resp, 1), CreateMockRead(echo, 3), | |
4120 MockRead(ASYNC, ERR_IO_PENDING, 4), MockRead(ASYNC, 0, 5) // EOF | |
4121 }; | |
4122 | |
4123 // Create SpdySession and SpdyStream and send the request. | |
4124 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4125 session_deps_.host_resolver->set_synchronous_mode(true); | |
4126 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4127 | |
4128 AddSSLSocketData(); | |
4129 | |
4130 CreateNetworkSession(); | |
4131 CreateSecureSpdySession(); | |
4132 | |
4133 base::WeakPtr<SpdyStream> stream = | |
4134 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
4135 MEDIUM, NetLogWithSource()); | |
4136 ASSERT_TRUE(stream); | |
4137 EXPECT_EQ(0u, stream->stream_id()); | |
4138 | |
4139 DropReceivedDataDelegate delegate(stream, msg_data); | |
4140 stream->SetDelegate(&delegate); | |
4141 | |
4142 SpdyHeaderBlock headers( | |
4143 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize)); | |
4144 EXPECT_EQ(ERR_IO_PENDING, | |
4145 stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND)); | |
4146 | |
4147 const int32_t initial_window_size = kDefaultInitialWindowSize; | |
4148 EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); | |
4149 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
4150 | |
4151 base::RunLoop().RunUntilIdle(); | |
4152 | |
4153 EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); | |
4154 EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_); | |
4155 | |
4156 stream->Close(); | |
4157 EXPECT_FALSE(stream); | |
4158 | |
4159 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
4160 | |
4161 EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); | |
4162 EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_); | |
4163 | |
4164 data.Resume(); | |
4165 base::RunLoop().RunUntilIdle(); | |
4166 EXPECT_FALSE(session_); | |
4167 } | |
4168 | |
4169 // Send data back and forth but close the stream before its data frame | |
4170 // can be written to the socket. The send window should then increase | |
4171 // to its original value, i.e. we shouldn't "leak" send window bytes. | |
4172 TEST_F(SpdySessionTest, SessionFlowControlNoSendLeaks) { | |
4173 const int32_t kMsgDataSize = 100; | |
4174 const SpdyString msg_data(kMsgDataSize, 'a'); | |
4175 | |
4176 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
4177 kDefaultUrl, 1, kMsgDataSize, MEDIUM, nullptr, 0)); | |
4178 MockWrite writes[] = { | |
4179 CreateMockWrite(req, 0), | |
4180 }; | |
4181 | |
4182 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
4183 MockRead reads[] = { | |
4184 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(resp, 2), | |
4185 MockRead(ASYNC, 0, 3) // EOF | |
4186 }; | |
4187 | |
4188 // Create SpdySession and SpdyStream and send the request. | |
4189 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4190 session_deps_.host_resolver->set_synchronous_mode(true); | |
4191 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4192 | |
4193 AddSSLSocketData(); | |
4194 | |
4195 CreateNetworkSession(); | |
4196 CreateSecureSpdySession(); | |
4197 | |
4198 base::WeakPtr<SpdyStream> stream = | |
4199 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
4200 MEDIUM, NetLogWithSource()); | |
4201 ASSERT_TRUE(stream); | |
4202 EXPECT_EQ(0u, stream->stream_id()); | |
4203 | |
4204 test::StreamDelegateSendImmediate delegate(stream, msg_data); | |
4205 stream->SetDelegate(&delegate); | |
4206 | |
4207 SpdyHeaderBlock headers( | |
4208 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize)); | |
4209 EXPECT_EQ(ERR_IO_PENDING, | |
4210 stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND)); | |
4211 | |
4212 const int32_t initial_window_size = kDefaultInitialWindowSize; | |
4213 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
4214 | |
4215 // Write request. | |
4216 base::RunLoop().RunUntilIdle(); | |
4217 | |
4218 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
4219 | |
4220 // Read response, but do not run the message loop, so that the body is not | |
4221 // written to the socket. | |
4222 data.Resume(); | |
4223 | |
4224 EXPECT_EQ(initial_window_size - kMsgDataSize, | |
4225 session_->session_send_window_size_); | |
4226 | |
4227 // Closing the stream should increase the session's send window. | |
4228 stream->Close(); | |
4229 EXPECT_FALSE(stream); | |
4230 | |
4231 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
4232 | |
4233 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
4234 | |
4235 base::RunLoop().RunUntilIdle(); | |
4236 EXPECT_FALSE(session_); | |
4237 | |
4238 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
4239 EXPECT_TRUE(data.AllReadDataConsumed()); | |
4240 } | |
4241 | |
4242 // Send data back and forth; the send and receive windows should | |
4243 // change appropriately. | |
4244 TEST_F(SpdySessionTest, SessionFlowControlEndToEnd) { | |
4245 const int32_t kMsgDataSize = 100; | |
4246 const SpdyString msg_data(kMsgDataSize, 'a'); | |
4247 | |
4248 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
4249 kDefaultUrl, 1, kMsgDataSize, MEDIUM, nullptr, 0)); | |
4250 SpdySerializedFrame msg(spdy_util_.ConstructSpdyDataFrame( | |
4251 1, msg_data.data(), kMsgDataSize, false)); | |
4252 MockWrite writes[] = { | |
4253 CreateMockWrite(req, 0), CreateMockWrite(msg, 2), | |
4254 }; | |
4255 | |
4256 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
4257 SpdySerializedFrame echo(spdy_util_.ConstructSpdyDataFrame( | |
4258 1, msg_data.data(), kMsgDataSize, false)); | |
4259 SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate( | |
4260 kSessionFlowControlStreamId, kMsgDataSize)); | |
4261 MockRead reads[] = { | |
4262 CreateMockRead(resp, 1), | |
4263 MockRead(ASYNC, ERR_IO_PENDING, 3), | |
4264 CreateMockRead(echo, 4), | |
4265 MockRead(ASYNC, ERR_IO_PENDING, 5), | |
4266 CreateMockRead(window_update, 6), | |
4267 MockRead(ASYNC, ERR_IO_PENDING, 7), | |
4268 MockRead(ASYNC, 0, 8) // EOF | |
4269 }; | |
4270 | |
4271 // Create SpdySession and SpdyStream and send the request. | |
4272 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4273 session_deps_.host_resolver->set_synchronous_mode(true); | |
4274 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4275 | |
4276 AddSSLSocketData(); | |
4277 | |
4278 CreateNetworkSession(); | |
4279 CreateSecureSpdySession(); | |
4280 | |
4281 base::WeakPtr<SpdyStream> stream = | |
4282 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, | |
4283 MEDIUM, NetLogWithSource()); | |
4284 ASSERT_TRUE(stream); | |
4285 EXPECT_EQ(0u, stream->stream_id()); | |
4286 | |
4287 test::StreamDelegateSendImmediate delegate(stream, msg_data); | |
4288 stream->SetDelegate(&delegate); | |
4289 | |
4290 SpdyHeaderBlock headers( | |
4291 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize)); | |
4292 EXPECT_EQ(ERR_IO_PENDING, | |
4293 stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND)); | |
4294 | |
4295 const int32_t initial_window_size = kDefaultInitialWindowSize; | |
4296 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
4297 EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); | |
4298 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
4299 | |
4300 // Send request and message. | |
4301 base::RunLoop().RunUntilIdle(); | |
4302 | |
4303 EXPECT_EQ(initial_window_size - kMsgDataSize, | |
4304 session_->session_send_window_size_); | |
4305 EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); | |
4306 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
4307 | |
4308 // Read echo. | |
4309 data.Resume(); | |
4310 base::RunLoop().RunUntilIdle(); | |
4311 | |
4312 EXPECT_EQ(initial_window_size - kMsgDataSize, | |
4313 session_->session_send_window_size_); | |
4314 EXPECT_EQ(initial_window_size - kMsgDataSize, | |
4315 session_->session_recv_window_size_); | |
4316 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
4317 | |
4318 // Read window update. | |
4319 data.Resume(); | |
4320 base::RunLoop().RunUntilIdle(); | |
4321 | |
4322 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
4323 EXPECT_EQ(initial_window_size - kMsgDataSize, | |
4324 session_->session_recv_window_size_); | |
4325 EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); | |
4326 | |
4327 EXPECT_EQ(msg_data, delegate.TakeReceivedData()); | |
4328 | |
4329 // Draining the delegate's read queue should increase the session's | |
4330 // receive window. | |
4331 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
4332 EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); | |
4333 EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_); | |
4334 | |
4335 stream->Close(); | |
4336 EXPECT_FALSE(stream); | |
4337 | |
4338 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
4339 | |
4340 EXPECT_EQ(initial_window_size, session_->session_send_window_size_); | |
4341 EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); | |
4342 EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_); | |
4343 | |
4344 data.Resume(); | |
4345 base::RunLoop().RunUntilIdle(); | |
4346 EXPECT_FALSE(session_); | |
4347 } | |
4348 | |
4349 // Given a stall function and an unstall function, runs a test to make | |
4350 // sure that a stream resumes after unstall. | |
4351 void SpdySessionTest::RunResumeAfterUnstallTest( | |
4352 const base::Callback<void(SpdyStream*)>& stall_function, | |
4353 const base::Callback<void(SpdyStream*, int32_t)>& unstall_function) { | |
4354 session_deps_.host_resolver->set_synchronous_mode(true); | |
4355 | |
4356 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
4357 kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0)); | |
4358 SpdySerializedFrame body( | |
4359 spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, true)); | |
4360 MockWrite writes[] = { | |
4361 CreateMockWrite(req, 0), CreateMockWrite(body, 1), | |
4362 }; | |
4363 | |
4364 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
4365 SpdySerializedFrame echo( | |
4366 spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, false)); | |
4367 MockRead reads[] = { | |
4368 CreateMockRead(resp, 2), MockRead(ASYNC, 0, 3) // EOF | |
4369 }; | |
4370 | |
4371 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4372 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4373 | |
4374 AddSSLSocketData(); | |
4375 | |
4376 CreateNetworkSession(); | |
4377 CreateSecureSpdySession(); | |
4378 | |
4379 base::WeakPtr<SpdyStream> stream = | |
4380 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4381 test_url_, LOWEST, NetLogWithSource()); | |
4382 ASSERT_TRUE(stream); | |
4383 | |
4384 test::StreamDelegateWithBody delegate(stream, kBodyDataStringPiece); | |
4385 stream->SetDelegate(&delegate); | |
4386 | |
4387 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
4388 | |
4389 SpdyHeaderBlock headers( | |
4390 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)); | |
4391 EXPECT_EQ(ERR_IO_PENDING, | |
4392 stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND)); | |
4393 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
4394 | |
4395 stall_function.Run(stream.get()); | |
4396 | |
4397 base::RunLoop().RunUntilIdle(); | |
4398 | |
4399 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
4400 | |
4401 unstall_function.Run(stream.get(), kBodyDataSize); | |
4402 | |
4403 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
4404 | |
4405 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
4406 | |
4407 EXPECT_TRUE(delegate.send_headers_completed()); | |
4408 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); | |
4409 EXPECT_EQ(SpdyString(), delegate.TakeReceivedData()); | |
4410 | |
4411 // Run SpdySession::PumpWriteLoop which destroys |session_|. | |
4412 base::RunLoop().RunUntilIdle(); | |
4413 | |
4414 EXPECT_FALSE(session_); | |
4415 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
4416 } | |
4417 | |
4418 // Run the resume-after-unstall test with all possible stall and | |
4419 // unstall sequences. | |
4420 | |
4421 TEST_F(SpdySessionTest, ResumeAfterUnstallSession) { | |
4422 RunResumeAfterUnstallTest( | |
4423 base::Bind(&SpdySessionTest::StallSessionOnly, | |
4424 base::Unretained(this)), | |
4425 base::Bind(&SpdySessionTest::UnstallSessionOnly, | |
4426 base::Unretained(this))); | |
4427 } | |
4428 | |
4429 // Equivalent to | |
4430 // SpdyStreamTest.ResumeAfterSendWindowSizeIncrease. | |
4431 TEST_F(SpdySessionTest, ResumeAfterUnstallStream) { | |
4432 RunResumeAfterUnstallTest( | |
4433 base::Bind(&SpdySessionTest::StallStreamOnly, | |
4434 base::Unretained(this)), | |
4435 base::Bind(&SpdySessionTest::UnstallStreamOnly, | |
4436 base::Unretained(this))); | |
4437 } | |
4438 | |
4439 TEST_F(SpdySessionTest, StallSessionStreamResumeAfterUnstallSessionStream) { | |
4440 RunResumeAfterUnstallTest( | |
4441 base::Bind(&SpdySessionTest::StallSessionStream, | |
4442 base::Unretained(this)), | |
4443 base::Bind(&SpdySessionTest::UnstallSessionStream, | |
4444 base::Unretained(this))); | |
4445 } | |
4446 | |
4447 TEST_F(SpdySessionTest, StallStreamSessionResumeAfterUnstallSessionStream) { | |
4448 RunResumeAfterUnstallTest( | |
4449 base::Bind(&SpdySessionTest::StallStreamSession, | |
4450 base::Unretained(this)), | |
4451 base::Bind(&SpdySessionTest::UnstallSessionStream, | |
4452 base::Unretained(this))); | |
4453 } | |
4454 | |
4455 TEST_F(SpdySessionTest, StallStreamSessionResumeAfterUnstallStreamSession) { | |
4456 RunResumeAfterUnstallTest( | |
4457 base::Bind(&SpdySessionTest::StallStreamSession, | |
4458 base::Unretained(this)), | |
4459 base::Bind(&SpdySessionTest::UnstallStreamSession, | |
4460 base::Unretained(this))); | |
4461 } | |
4462 | |
4463 TEST_F(SpdySessionTest, StallSessionStreamResumeAfterUnstallStreamSession) { | |
4464 RunResumeAfterUnstallTest( | |
4465 base::Bind(&SpdySessionTest::StallSessionStream, | |
4466 base::Unretained(this)), | |
4467 base::Bind(&SpdySessionTest::UnstallStreamSession, | |
4468 base::Unretained(this))); | |
4469 } | |
4470 | |
4471 // Cause a stall by reducing the flow control send window to 0. The | |
4472 // streams should resume in priority order when that window is then | |
4473 // increased. | |
4474 TEST_F(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) { | |
4475 session_deps_.host_resolver->set_synchronous_mode(true); | |
4476 | |
4477 SpdySerializedFrame req1(spdy_util_.ConstructSpdyPost( | |
4478 kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0)); | |
4479 SpdySerializedFrame req2(spdy_util_.ConstructSpdyPost( | |
4480 kDefaultUrl, 3, kBodyDataSize, MEDIUM, nullptr, 0)); | |
4481 SpdySerializedFrame body1( | |
4482 spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, true)); | |
4483 SpdySerializedFrame body2( | |
4484 spdy_util_.ConstructSpdyDataFrame(3, kBodyData, kBodyDataSize, true)); | |
4485 MockWrite writes[] = { | |
4486 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
4487 CreateMockWrite(body2, 2), CreateMockWrite(body1, 3), | |
4488 }; | |
4489 | |
4490 SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
4491 SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3)); | |
4492 MockRead reads[] = { | |
4493 CreateMockRead(resp1, 4), CreateMockRead(resp2, 5), | |
4494 MockRead(ASYNC, 0, 6) // EOF | |
4495 }; | |
4496 | |
4497 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4498 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4499 | |
4500 AddSSLSocketData(); | |
4501 | |
4502 CreateNetworkSession(); | |
4503 CreateSecureSpdySession(); | |
4504 | |
4505 base::WeakPtr<SpdyStream> stream1 = | |
4506 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4507 test_url_, LOWEST, NetLogWithSource()); | |
4508 ASSERT_TRUE(stream1); | |
4509 | |
4510 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); | |
4511 stream1->SetDelegate(&delegate1); | |
4512 | |
4513 base::WeakPtr<SpdyStream> stream2 = | |
4514 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4515 test_url_, MEDIUM, NetLogWithSource()); | |
4516 ASSERT_TRUE(stream2); | |
4517 | |
4518 test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece); | |
4519 stream2->SetDelegate(&delegate2); | |
4520 | |
4521 EXPECT_FALSE(stream1->send_stalled_by_flow_control()); | |
4522 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
4523 | |
4524 StallSessionSend(); | |
4525 | |
4526 SpdyHeaderBlock headers1( | |
4527 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)); | |
4528 EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequestHeaders(std::move(headers1), | |
4529 MORE_DATA_TO_SEND)); | |
4530 EXPECT_EQ(kDefaultUrl, stream1->GetUrlFromHeaders().spec()); | |
4531 | |
4532 base::RunLoop().RunUntilIdle(); | |
4533 EXPECT_EQ(1u, stream1->stream_id()); | |
4534 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); | |
4535 | |
4536 SpdyHeaderBlock headers2( | |
4537 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)); | |
4538 EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequestHeaders(std::move(headers2), | |
4539 MORE_DATA_TO_SEND)); | |
4540 EXPECT_EQ(kDefaultUrl, stream2->GetUrlFromHeaders().spec()); | |
4541 | |
4542 base::RunLoop().RunUntilIdle(); | |
4543 EXPECT_EQ(3u, stream2->stream_id()); | |
4544 EXPECT_TRUE(stream2->send_stalled_by_flow_control()); | |
4545 | |
4546 // This should unstall only stream2. | |
4547 UnstallSessionSend(kBodyDataSize); | |
4548 | |
4549 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); | |
4550 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
4551 | |
4552 base::RunLoop().RunUntilIdle(); | |
4553 | |
4554 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); | |
4555 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
4556 | |
4557 // This should then unstall stream1. | |
4558 UnstallSessionSend(kBodyDataSize); | |
4559 | |
4560 EXPECT_FALSE(stream1->send_stalled_by_flow_control()); | |
4561 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
4562 | |
4563 base::RunLoop().RunUntilIdle(); | |
4564 | |
4565 EXPECT_THAT(delegate1.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
4566 EXPECT_THAT(delegate2.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
4567 | |
4568 EXPECT_TRUE(delegate1.send_headers_completed()); | |
4569 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); | |
4570 EXPECT_EQ(SpdyString(), delegate1.TakeReceivedData()); | |
4571 | |
4572 EXPECT_TRUE(delegate2.send_headers_completed()); | |
4573 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); | |
4574 EXPECT_EQ(SpdyString(), delegate2.TakeReceivedData()); | |
4575 | |
4576 EXPECT_FALSE(session_); | |
4577 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
4578 EXPECT_TRUE(data.AllReadDataConsumed()); | |
4579 } | |
4580 | |
4581 // Delegate that closes a given stream after sending its body. | |
4582 class StreamClosingDelegate : public test::StreamDelegateWithBody { | |
4583 public: | |
4584 StreamClosingDelegate(const base::WeakPtr<SpdyStream>& stream, | |
4585 SpdyStringPiece data) | |
4586 : StreamDelegateWithBody(stream, data) {} | |
4587 | |
4588 ~StreamClosingDelegate() override {} | |
4589 | |
4590 void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) { | |
4591 stream_to_close_ = stream_to_close; | |
4592 } | |
4593 | |
4594 void OnDataSent() override { | |
4595 test::StreamDelegateWithBody::OnDataSent(); | |
4596 if (stream_to_close_.get()) { | |
4597 stream_to_close_->Close(); | |
4598 EXPECT_FALSE(stream_to_close_); | |
4599 } | |
4600 } | |
4601 | |
4602 private: | |
4603 base::WeakPtr<SpdyStream> stream_to_close_; | |
4604 }; | |
4605 | |
4606 // Cause a stall by reducing the flow control send window to | |
4607 // 0. Unstalling the session should properly handle deleted streams. | |
4608 TEST_F(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) { | |
4609 session_deps_.host_resolver->set_synchronous_mode(true); | |
4610 | |
4611 SpdySerializedFrame req1(spdy_util_.ConstructSpdyPost( | |
4612 kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0)); | |
4613 SpdySerializedFrame req2(spdy_util_.ConstructSpdyPost( | |
4614 kDefaultUrl, 3, kBodyDataSize, LOWEST, nullptr, 0)); | |
4615 SpdySerializedFrame req3(spdy_util_.ConstructSpdyPost( | |
4616 kDefaultUrl, 5, kBodyDataSize, LOWEST, nullptr, 0)); | |
4617 SpdySerializedFrame body2( | |
4618 spdy_util_.ConstructSpdyDataFrame(3, kBodyData, kBodyDataSize, true)); | |
4619 MockWrite writes[] = { | |
4620 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
4621 CreateMockWrite(req3, 2), CreateMockWrite(body2, 3), | |
4622 }; | |
4623 | |
4624 SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3)); | |
4625 MockRead reads[] = { | |
4626 CreateMockRead(resp2, 4), MockRead(ASYNC, ERR_IO_PENDING, 5), | |
4627 MockRead(ASYNC, 0, 6) // EOF | |
4628 }; | |
4629 | |
4630 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4631 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4632 | |
4633 AddSSLSocketData(); | |
4634 | |
4635 CreateNetworkSession(); | |
4636 CreateSecureSpdySession(); | |
4637 | |
4638 base::WeakPtr<SpdyStream> stream1 = | |
4639 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4640 test_url_, LOWEST, NetLogWithSource()); | |
4641 ASSERT_TRUE(stream1); | |
4642 | |
4643 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); | |
4644 stream1->SetDelegate(&delegate1); | |
4645 | |
4646 base::WeakPtr<SpdyStream> stream2 = | |
4647 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4648 test_url_, LOWEST, NetLogWithSource()); | |
4649 ASSERT_TRUE(stream2); | |
4650 | |
4651 StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece); | |
4652 stream2->SetDelegate(&delegate2); | |
4653 | |
4654 base::WeakPtr<SpdyStream> stream3 = | |
4655 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4656 test_url_, LOWEST, NetLogWithSource()); | |
4657 ASSERT_TRUE(stream3); | |
4658 | |
4659 test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece); | |
4660 stream3->SetDelegate(&delegate3); | |
4661 | |
4662 EXPECT_FALSE(stream1->send_stalled_by_flow_control()); | |
4663 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
4664 EXPECT_FALSE(stream3->send_stalled_by_flow_control()); | |
4665 | |
4666 StallSessionSend(); | |
4667 | |
4668 SpdyHeaderBlock headers1( | |
4669 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)); | |
4670 EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequestHeaders(std::move(headers1), | |
4671 MORE_DATA_TO_SEND)); | |
4672 EXPECT_EQ(kDefaultUrl, stream1->GetUrlFromHeaders().spec()); | |
4673 | |
4674 base::RunLoop().RunUntilIdle(); | |
4675 EXPECT_EQ(1u, stream1->stream_id()); | |
4676 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); | |
4677 | |
4678 SpdyHeaderBlock headers2( | |
4679 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)); | |
4680 EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequestHeaders(std::move(headers2), | |
4681 MORE_DATA_TO_SEND)); | |
4682 EXPECT_EQ(kDefaultUrl, stream2->GetUrlFromHeaders().spec()); | |
4683 | |
4684 base::RunLoop().RunUntilIdle(); | |
4685 EXPECT_EQ(3u, stream2->stream_id()); | |
4686 EXPECT_TRUE(stream2->send_stalled_by_flow_control()); | |
4687 | |
4688 SpdyHeaderBlock headers3( | |
4689 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)); | |
4690 EXPECT_EQ(ERR_IO_PENDING, stream3->SendRequestHeaders(std::move(headers3), | |
4691 MORE_DATA_TO_SEND)); | |
4692 EXPECT_EQ(kDefaultUrl, stream3->GetUrlFromHeaders().spec()); | |
4693 | |
4694 base::RunLoop().RunUntilIdle(); | |
4695 EXPECT_EQ(5u, stream3->stream_id()); | |
4696 EXPECT_TRUE(stream3->send_stalled_by_flow_control()); | |
4697 | |
4698 SpdyStreamId stream_id1 = stream1->stream_id(); | |
4699 SpdyStreamId stream_id2 = stream2->stream_id(); | |
4700 SpdyStreamId stream_id3 = stream3->stream_id(); | |
4701 | |
4702 // Close stream1 preemptively. | |
4703 session_->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED); | |
4704 EXPECT_FALSE(stream1); | |
4705 | |
4706 EXPECT_FALSE(session_->IsStreamActive(stream_id1)); | |
4707 EXPECT_TRUE(session_->IsStreamActive(stream_id2)); | |
4708 EXPECT_TRUE(session_->IsStreamActive(stream_id3)); | |
4709 | |
4710 // Unstall stream2, which should then close stream3. | |
4711 delegate2.set_stream_to_close(stream3); | |
4712 UnstallSessionSend(kBodyDataSize); | |
4713 | |
4714 base::RunLoop().RunUntilIdle(); | |
4715 EXPECT_FALSE(stream3); | |
4716 | |
4717 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
4718 EXPECT_FALSE(session_->IsStreamActive(stream_id1)); | |
4719 EXPECT_TRUE(session_->IsStreamActive(stream_id2)); | |
4720 EXPECT_FALSE(session_->IsStreamActive(stream_id3)); | |
4721 | |
4722 data.Resume(); | |
4723 base::RunLoop().RunUntilIdle(); | |
4724 EXPECT_FALSE(stream2); | |
4725 EXPECT_FALSE(session_); | |
4726 | |
4727 EXPECT_THAT(delegate1.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
4728 EXPECT_THAT(delegate2.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
4729 EXPECT_THAT(delegate3.WaitForClose(), IsOk()); | |
4730 | |
4731 EXPECT_TRUE(delegate1.send_headers_completed()); | |
4732 EXPECT_EQ(SpdyString(), delegate1.TakeReceivedData()); | |
4733 | |
4734 EXPECT_TRUE(delegate2.send_headers_completed()); | |
4735 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); | |
4736 EXPECT_EQ(SpdyString(), delegate2.TakeReceivedData()); | |
4737 | |
4738 EXPECT_TRUE(delegate3.send_headers_completed()); | |
4739 EXPECT_EQ(SpdyString(), delegate3.TakeReceivedData()); | |
4740 | |
4741 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
4742 } | |
4743 | |
4744 // Cause a stall by reducing the flow control send window to | |
4745 // 0. Unstalling the session should properly handle the session itself | |
4746 // being closed. | |
4747 TEST_F(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { | |
4748 session_deps_.host_resolver->set_synchronous_mode(true); | |
4749 | |
4750 SpdySerializedFrame req1(spdy_util_.ConstructSpdyPost( | |
4751 kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0)); | |
4752 SpdySerializedFrame req2(spdy_util_.ConstructSpdyPost( | |
4753 kDefaultUrl, 3, kBodyDataSize, LOWEST, nullptr, 0)); | |
4754 SpdySerializedFrame body1( | |
4755 spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, false)); | |
4756 MockWrite writes[] = { | |
4757 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1), | |
4758 }; | |
4759 | |
4760 MockRead reads[] = { | |
4761 MockRead(ASYNC, ERR_IO_PENDING, 2), MockRead(ASYNC, 0, 3) // EOF | |
4762 }; | |
4763 | |
4764 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4765 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4766 | |
4767 AddSSLSocketData(); | |
4768 | |
4769 CreateNetworkSession(); | |
4770 CreateSecureSpdySession(); | |
4771 | |
4772 base::WeakPtr<SpdyStream> stream1 = | |
4773 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4774 test_url_, LOWEST, NetLogWithSource()); | |
4775 ASSERT_TRUE(stream1); | |
4776 | |
4777 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); | |
4778 stream1->SetDelegate(&delegate1); | |
4779 | |
4780 base::WeakPtr<SpdyStream> stream2 = | |
4781 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4782 test_url_, LOWEST, NetLogWithSource()); | |
4783 ASSERT_TRUE(stream2); | |
4784 | |
4785 test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece); | |
4786 stream2->SetDelegate(&delegate2); | |
4787 | |
4788 EXPECT_FALSE(stream1->send_stalled_by_flow_control()); | |
4789 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
4790 | |
4791 StallSessionSend(); | |
4792 | |
4793 SpdyHeaderBlock headers1( | |
4794 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)); | |
4795 EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequestHeaders(std::move(headers1), | |
4796 MORE_DATA_TO_SEND)); | |
4797 EXPECT_EQ(kDefaultUrl, stream1->GetUrlFromHeaders().spec()); | |
4798 | |
4799 base::RunLoop().RunUntilIdle(); | |
4800 EXPECT_EQ(1u, stream1->stream_id()); | |
4801 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); | |
4802 | |
4803 SpdyHeaderBlock headers2( | |
4804 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)); | |
4805 EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequestHeaders(std::move(headers2), | |
4806 MORE_DATA_TO_SEND)); | |
4807 EXPECT_EQ(kDefaultUrl, stream2->GetUrlFromHeaders().spec()); | |
4808 | |
4809 base::RunLoop().RunUntilIdle(); | |
4810 EXPECT_EQ(3u, stream2->stream_id()); | |
4811 EXPECT_TRUE(stream2->send_stalled_by_flow_control()); | |
4812 | |
4813 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); | |
4814 | |
4815 // Unstall stream1. | |
4816 UnstallSessionSend(kBodyDataSize); | |
4817 | |
4818 // Close the session (since we can't do it from within the delegate | |
4819 // method, since it's in the stream's loop). | |
4820 session_->CloseSessionOnError(ERR_CONNECTION_CLOSED, "Closing session"); | |
4821 data.Resume(); | |
4822 base::RunLoop().RunUntilIdle(); | |
4823 EXPECT_FALSE(session_); | |
4824 | |
4825 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); | |
4826 | |
4827 EXPECT_THAT(delegate1.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
4828 EXPECT_THAT(delegate2.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
4829 | |
4830 EXPECT_TRUE(delegate1.send_headers_completed()); | |
4831 EXPECT_EQ(SpdyString(), delegate1.TakeReceivedData()); | |
4832 | |
4833 EXPECT_TRUE(delegate2.send_headers_completed()); | |
4834 EXPECT_EQ(SpdyString(), delegate2.TakeReceivedData()); | |
4835 | |
4836 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
4837 } | |
4838 | |
4839 TEST_F(SpdySessionTest, GoAwayOnSessionFlowControlError) { | |
4840 SpdySerializedFrame req( | |
4841 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
4842 SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway( | |
4843 0, ERROR_CODE_FLOW_CONTROL_ERROR, | |
4844 "delta_window_size is 6 in DecreaseRecvWindowSize, which is larger than " | |
4845 "the receive window size of 1")); | |
4846 MockWrite writes[] = { | |
4847 CreateMockWrite(req, 0), CreateMockWrite(goaway, 4), | |
4848 }; | |
4849 | |
4850 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
4851 SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); | |
4852 MockRead reads[] = { | |
4853 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(resp, 2), | |
4854 CreateMockRead(body, 3), | |
4855 }; | |
4856 | |
4857 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4858 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4859 | |
4860 AddSSLSocketData(); | |
4861 | |
4862 CreateNetworkSession(); | |
4863 CreateSecureSpdySession(); | |
4864 | |
4865 base::WeakPtr<SpdyStream> spdy_stream = | |
4866 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4867 test_url_, LOWEST, NetLogWithSource()); | |
4868 ASSERT_TRUE(spdy_stream); | |
4869 test::StreamDelegateDoNothing delegate(spdy_stream); | |
4870 spdy_stream->SetDelegate(&delegate); | |
4871 | |
4872 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
4873 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
4874 | |
4875 // Write request. | |
4876 base::RunLoop().RunUntilIdle(); | |
4877 | |
4878 // Put session on the edge of overflowing it's recv window. | |
4879 session_->session_recv_window_size_ = 1; | |
4880 | |
4881 // Read response headers & body. Body overflows the session window, and a | |
4882 // goaway is written. | |
4883 data.Resume(); | |
4884 base::RunLoop().RunUntilIdle(); | |
4885 | |
4886 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_FLOW_CONTROL_ERROR)); | |
4887 EXPECT_FALSE(session_); | |
4888 } | |
4889 | |
4890 // Regression. Sorta. Push streams and client streams were sharing a single | |
4891 // limit for a long time. | |
4892 TEST_F(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) { | |
4893 SettingsMap new_settings; | |
4894 new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = 2; | |
4895 SpdySerializedFrame settings_frame( | |
4896 spdy_util_.ConstructSpdySettings(new_settings)); | |
4897 SpdySerializedFrame pushed(spdy_util_.ConstructSpdyPush( | |
4898 nullptr, 0, 2, 1, "https://www.example.org/a.dat")); | |
4899 MockRead reads[] = { | |
4900 CreateMockRead(settings_frame, 0), | |
4901 MockRead(ASYNC, ERR_IO_PENDING, 3), | |
4902 CreateMockRead(pushed, 4), | |
4903 MockRead(ASYNC, ERR_IO_PENDING, 6), | |
4904 MockRead(ASYNC, 0, 7), | |
4905 }; | |
4906 | |
4907 SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
4908 SpdySerializedFrame req( | |
4909 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
4910 SpdySerializedFrame priority( | |
4911 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
4912 MockWrite writes[] = { | |
4913 CreateMockWrite(settings_ack, 1), CreateMockWrite(req, 2), | |
4914 CreateMockWrite(priority, 5), | |
4915 }; | |
4916 | |
4917 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
4918 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
4919 | |
4920 AddSSLSocketData(); | |
4921 | |
4922 CreateNetworkSession(); | |
4923 CreateSecureSpdySession(); | |
4924 | |
4925 // Read the settings frame. | |
4926 base::RunLoop().RunUntilIdle(); | |
4927 | |
4928 base::WeakPtr<SpdyStream> spdy_stream1 = | |
4929 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4930 test_url_, LOWEST, NetLogWithSource()); | |
4931 ASSERT_TRUE(spdy_stream1); | |
4932 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
4933 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
4934 spdy_stream1->SetDelegate(&delegate1); | |
4935 | |
4936 EXPECT_EQ(0u, session_->num_active_streams()); | |
4937 EXPECT_EQ(1u, session_->num_created_streams()); | |
4938 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
4939 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
4940 | |
4941 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
4942 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
4943 | |
4944 // Run until 1st stream is activated. | |
4945 EXPECT_EQ(0u, delegate1.stream_id()); | |
4946 base::RunLoop().RunUntilIdle(); | |
4947 EXPECT_EQ(1u, delegate1.stream_id()); | |
4948 EXPECT_EQ(1u, session_->num_active_streams()); | |
4949 EXPECT_EQ(0u, session_->num_created_streams()); | |
4950 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
4951 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
4952 | |
4953 // Run until pushed stream is created. | |
4954 data.Resume(); | |
4955 base::RunLoop().RunUntilIdle(); | |
4956 EXPECT_EQ(2u, session_->num_active_streams()); | |
4957 EXPECT_EQ(0u, session_->num_created_streams()); | |
4958 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
4959 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
4960 | |
4961 // Second stream should not be stalled, although we have 2 active streams, but | |
4962 // one of them is push stream and should not be taken into account when we | |
4963 // create streams on the client. | |
4964 base::WeakPtr<SpdyStream> spdy_stream2 = | |
4965 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
4966 test_url_, LOWEST, NetLogWithSource()); | |
4967 EXPECT_TRUE(spdy_stream2); | |
4968 EXPECT_EQ(2u, session_->num_active_streams()); | |
4969 EXPECT_EQ(1u, session_->num_created_streams()); | |
4970 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
4971 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
4972 | |
4973 // Read EOF. | |
4974 data.Resume(); | |
4975 base::RunLoop().RunUntilIdle(); | |
4976 EXPECT_FALSE(session_); | |
4977 } | |
4978 | |
4979 TEST_F(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) { | |
4980 SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( | |
4981 nullptr, 0, 2, 1, "https://www.example.org/a.dat")); | |
4982 SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush( | |
4983 nullptr, 0, 4, 1, "https://www.example.org/b.dat")); | |
4984 MockRead reads[] = { | |
4985 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(push_a, 2), | |
4986 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(push_b, 5), | |
4987 MockRead(ASYNC, ERR_IO_PENDING, 8), MockRead(ASYNC, 0, 9), | |
4988 }; | |
4989 | |
4990 SpdySerializedFrame req( | |
4991 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
4992 SpdySerializedFrame priority_a( | |
4993 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
4994 SpdySerializedFrame priority_b( | |
4995 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true)); | |
4996 SpdySerializedFrame rst_b( | |
4997 spdy_util_.ConstructSpdyRstStream(4, ERROR_CODE_REFUSED_STREAM)); | |
4998 MockWrite writes[] = { | |
4999 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 3), | |
5000 CreateMockWrite(priority_b, 6), CreateMockWrite(rst_b, 7), | |
5001 }; | |
5002 | |
5003 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
5004 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5005 | |
5006 AddSSLSocketData(); | |
5007 | |
5008 CreateNetworkSession(); | |
5009 CreateSecureSpdySession(); | |
5010 session_->set_max_concurrent_pushed_streams(1); | |
5011 | |
5012 base::WeakPtr<SpdyStream> spdy_stream1 = | |
5013 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
5014 test_url_, LOWEST, NetLogWithSource()); | |
5015 ASSERT_TRUE(spdy_stream1); | |
5016 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
5017 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
5018 spdy_stream1->SetDelegate(&delegate1); | |
5019 | |
5020 EXPECT_EQ(0u, session_->num_active_streams()); | |
5021 EXPECT_EQ(1u, session_->num_created_streams()); | |
5022 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5023 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5024 | |
5025 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
5026 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
5027 | |
5028 // Run until 1st stream is activated. | |
5029 EXPECT_EQ(0u, delegate1.stream_id()); | |
5030 base::RunLoop().RunUntilIdle(); | |
5031 EXPECT_EQ(1u, delegate1.stream_id()); | |
5032 EXPECT_EQ(1u, session_->num_active_streams()); | |
5033 EXPECT_EQ(0u, session_->num_created_streams()); | |
5034 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5035 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5036 | |
5037 // Run until pushed stream is created. | |
5038 data.Resume(); | |
5039 base::RunLoop().RunUntilIdle(); | |
5040 EXPECT_EQ(2u, session_->num_active_streams()); | |
5041 EXPECT_EQ(0u, session_->num_created_streams()); | |
5042 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
5043 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
5044 | |
5045 // Reset incoming pushed stream. | |
5046 data.Resume(); | |
5047 base::RunLoop().RunUntilIdle(); | |
5048 EXPECT_EQ(2u, session_->num_active_streams()); | |
5049 EXPECT_EQ(0u, session_->num_created_streams()); | |
5050 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
5051 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
5052 | |
5053 // Read EOF. | |
5054 data.Resume(); | |
5055 base::RunLoop().RunUntilIdle(); | |
5056 EXPECT_FALSE(session_); | |
5057 } | |
5058 | |
5059 // Tests that HTTP SPDY push streams that advertise an origin different from the | |
5060 // associated stream are accepted from a trusted SPDY proxy. | |
5061 TEST_F(SpdySessionTest, TrustedSpdyProxy) { | |
5062 // Origin of kDefaultUrl should be different from the origin of | |
5063 // kHttpURLFromAnotherOrigin and kHttpsURLFromAnotherOrigin. | |
5064 ASSERT_NE(GURL(kDefaultUrl).host(), GURL(kHttpURLFromAnotherOrigin).host()); | |
5065 ASSERT_NE(GURL(kDefaultUrl).host(), GURL(kHttpsURLFromAnotherOrigin).host()); | |
5066 | |
5067 // cross_origin_push contains HTTP resource for an origin different from the | |
5068 // origin of kDefaultUrl, and should be accepted. | |
5069 SpdySerializedFrame cross_origin_push(spdy_util_.ConstructSpdyPush( | |
5070 nullptr, 0, 2, 1, kHttpURLFromAnotherOrigin)); | |
5071 // cross_origin_https_push contains HTTPS resource, and should be refused. | |
5072 SpdySerializedFrame cross_origin_https_push(spdy_util_.ConstructSpdyPush( | |
5073 nullptr, 0, 4, 1, kHttpsURLFromAnotherOrigin)); | |
5074 MockRead reads[] = { | |
5075 MockRead(ASYNC, ERR_IO_PENDING, 1), | |
5076 CreateMockRead(cross_origin_push, 2), | |
5077 MockRead(ASYNC, ERR_IO_PENDING, 4), | |
5078 CreateMockRead(cross_origin_https_push, 5), | |
5079 MockRead(ASYNC, ERR_IO_PENDING, 7), | |
5080 MockRead(ASYNC, 0, 8), | |
5081 }; | |
5082 | |
5083 SpdySerializedFrame req( | |
5084 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
5085 SpdySerializedFrame priority_http( | |
5086 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
5087 SpdySerializedFrame rst_https( | |
5088 spdy_util_.ConstructSpdyRstStream(4, ERROR_CODE_REFUSED_STREAM)); | |
5089 MockWrite writes[] = { | |
5090 CreateMockWrite(req, 0), CreateMockWrite(priority_http, 3), | |
5091 CreateMockWrite(rst_https, 6), | |
5092 }; | |
5093 | |
5094 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
5095 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5096 | |
5097 std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate()); | |
5098 proxy_delegate->set_trusted_spdy_proxy( | |
5099 net::ProxyServer(net::ProxyServer::SCHEME_HTTPS, | |
5100 HostPortPair(GURL(kDefaultUrl).host(), 443))); | |
5101 session_deps_.proxy_delegate = std::move(proxy_delegate); | |
5102 | |
5103 AddSSLSocketData(); | |
5104 | |
5105 CreateNetworkSession(); | |
5106 CreateSecureSpdySession(); | |
5107 | |
5108 base::WeakPtr<SpdyStream> spdy_stream = | |
5109 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
5110 test_url_, LOWEST, NetLogWithSource()); | |
5111 ASSERT_TRUE(spdy_stream); | |
5112 EXPECT_EQ(0u, spdy_stream->stream_id()); | |
5113 test::StreamDelegateDoNothing delegate(spdy_stream); | |
5114 spdy_stream->SetDelegate(&delegate); | |
5115 | |
5116 EXPECT_EQ(0u, session_->num_active_streams()); | |
5117 EXPECT_EQ(1u, session_->num_created_streams()); | |
5118 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5119 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5120 | |
5121 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
5122 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
5123 | |
5124 // Run until 1st stream is activated. | |
5125 EXPECT_EQ(0u, delegate.stream_id()); | |
5126 base::RunLoop().RunUntilIdle(); | |
5127 EXPECT_EQ(1u, delegate.stream_id()); | |
5128 EXPECT_EQ(1u, session_->num_active_streams()); | |
5129 EXPECT_EQ(0u, session_->num_created_streams()); | |
5130 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5131 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5132 | |
5133 // Run until pushed stream is created. | |
5134 data.Resume(); | |
5135 base::RunLoop().RunUntilIdle(); | |
5136 EXPECT_EQ(2u, session_->num_active_streams()); | |
5137 EXPECT_EQ(0u, session_->num_created_streams()); | |
5138 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
5139 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
5140 | |
5141 // Reset incoming pushed stream. | |
5142 data.Resume(); | |
5143 base::RunLoop().RunUntilIdle(); | |
5144 EXPECT_EQ(2u, session_->num_active_streams()); | |
5145 EXPECT_EQ(0u, session_->num_created_streams()); | |
5146 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
5147 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
5148 | |
5149 // Read EOF. | |
5150 data.Resume(); | |
5151 base::RunLoop().RunUntilIdle(); | |
5152 EXPECT_FALSE(session_); | |
5153 } | |
5154 | |
5155 // Tests that if the SPDY trusted proxy is not set, then push streams that | |
5156 // advertise an origin different from the associated stream are refused. | |
5157 TEST_F(SpdySessionTest, TrustedSpdyProxyNotSet) { | |
5158 // Origin of kDefaultUrl should be different from the origin of | |
5159 // kHttpURLFromAnotherOrigin. | |
5160 ASSERT_NE(GURL(kDefaultUrl).host(), GURL(kHttpURLFromAnotherOrigin).host()); | |
5161 | |
5162 // cross_origin_push contains resource for an origin different from the | |
5163 // origin of kDefaultUrl, and should be refused. | |
5164 SpdySerializedFrame cross_origin_push(spdy_util_.ConstructSpdyPush( | |
5165 nullptr, 0, 2, 1, kHttpURLFromAnotherOrigin)); | |
5166 MockRead reads[] = { | |
5167 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(cross_origin_push, 2), | |
5168 MockRead(ASYNC, 0, 4), | |
5169 }; | |
5170 | |
5171 SpdySerializedFrame req( | |
5172 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
5173 SpdySerializedFrame rst( | |
5174 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM)); | |
5175 MockWrite writes[] = { | |
5176 CreateMockWrite(req, 0), CreateMockWrite(rst, 3), | |
5177 }; | |
5178 | |
5179 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
5180 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5181 | |
5182 AddSSLSocketData(); | |
5183 | |
5184 CreateNetworkSession(); | |
5185 CreateSecureSpdySession(); | |
5186 | |
5187 base::WeakPtr<SpdyStream> spdy_stream = | |
5188 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
5189 test_url_, LOWEST, NetLogWithSource()); | |
5190 ASSERT_TRUE(spdy_stream); | |
5191 EXPECT_EQ(0u, spdy_stream->stream_id()); | |
5192 test::StreamDelegateDoNothing delegate(spdy_stream); | |
5193 spdy_stream->SetDelegate(&delegate); | |
5194 | |
5195 EXPECT_EQ(0u, session_->num_active_streams()); | |
5196 EXPECT_EQ(1u, session_->num_created_streams()); | |
5197 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5198 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5199 | |
5200 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
5201 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
5202 | |
5203 // Run until 1st stream is activated. | |
5204 EXPECT_EQ(0u, delegate.stream_id()); | |
5205 base::RunLoop().RunUntilIdle(); | |
5206 EXPECT_EQ(1u, delegate.stream_id()); | |
5207 EXPECT_EQ(1u, session_->num_active_streams()); | |
5208 EXPECT_EQ(0u, session_->num_created_streams()); | |
5209 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5210 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5211 | |
5212 // Read EOF. | |
5213 data.Resume(); | |
5214 base::RunLoop().RunUntilIdle(); | |
5215 EXPECT_FALSE(session_); | |
5216 } | |
5217 | |
5218 TEST_F(SpdySessionTest, IgnoreReservedRemoteStreamsCount) { | |
5219 SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( | |
5220 nullptr, 0, 2, 1, "https://www.example.org/a.dat")); | |
5221 SpdyHeaderBlock push_headers; | |
5222 spdy_util_.AddUrlToHeaderBlock("https://www.example.org/b.dat", | |
5223 &push_headers); | |
5224 SpdySerializedFrame push_b( | |
5225 spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 4, 1)); | |
5226 SpdySerializedFrame headers_b( | |
5227 spdy_util_.ConstructSpdyPushHeaders(4, nullptr, 0)); | |
5228 MockRead reads[] = { | |
5229 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(push_a, 2), | |
5230 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(push_b, 5), | |
5231 MockRead(ASYNC, ERR_IO_PENDING, 7), CreateMockRead(headers_b, 8), | |
5232 MockRead(ASYNC, ERR_IO_PENDING, 10), MockRead(ASYNC, 0, 11), | |
5233 }; | |
5234 | |
5235 SpdySerializedFrame req( | |
5236 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
5237 SpdySerializedFrame priority_a( | |
5238 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
5239 SpdySerializedFrame priority_b( | |
5240 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true)); | |
5241 SpdySerializedFrame rst_b( | |
5242 spdy_util_.ConstructSpdyRstStream(4, ERROR_CODE_REFUSED_STREAM)); | |
5243 MockWrite writes[] = { | |
5244 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 3), | |
5245 CreateMockWrite(priority_b, 6), CreateMockWrite(rst_b, 9), | |
5246 }; | |
5247 | |
5248 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
5249 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5250 | |
5251 AddSSLSocketData(); | |
5252 | |
5253 CreateNetworkSession(); | |
5254 CreateSecureSpdySession(); | |
5255 session_->set_max_concurrent_pushed_streams(1); | |
5256 | |
5257 base::WeakPtr<SpdyStream> spdy_stream1 = | |
5258 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
5259 test_url_, LOWEST, NetLogWithSource()); | |
5260 ASSERT_TRUE(spdy_stream1); | |
5261 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
5262 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
5263 spdy_stream1->SetDelegate(&delegate1); | |
5264 | |
5265 EXPECT_EQ(0u, session_->num_active_streams()); | |
5266 EXPECT_EQ(1u, session_->num_created_streams()); | |
5267 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5268 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5269 | |
5270 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
5271 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
5272 | |
5273 // Run until 1st stream is activated. | |
5274 EXPECT_EQ(0u, delegate1.stream_id()); | |
5275 base::RunLoop().RunUntilIdle(); | |
5276 EXPECT_EQ(1u, delegate1.stream_id()); | |
5277 EXPECT_EQ(1u, session_->num_active_streams()); | |
5278 EXPECT_EQ(0u, session_->num_created_streams()); | |
5279 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5280 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5281 | |
5282 // Run until pushed stream is created. | |
5283 data.Resume(); | |
5284 base::RunLoop().RunUntilIdle(); | |
5285 EXPECT_EQ(2u, session_->num_active_streams()); | |
5286 EXPECT_EQ(0u, session_->num_created_streams()); | |
5287 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
5288 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
5289 | |
5290 // Accept promised stream. It should not count towards pushed stream limit. | |
5291 data.Resume(); | |
5292 base::RunLoop().RunUntilIdle(); | |
5293 EXPECT_EQ(3u, session_->num_active_streams()); | |
5294 EXPECT_EQ(0u, session_->num_created_streams()); | |
5295 EXPECT_EQ(2u, session_->num_pushed_streams()); | |
5296 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
5297 | |
5298 // Reset last pushed stream upon headers reception as it is going to be 2nd, | |
5299 // while we accept only one. | |
5300 data.Resume(); | |
5301 base::RunLoop().RunUntilIdle(); | |
5302 EXPECT_EQ(2u, session_->num_active_streams()); | |
5303 EXPECT_EQ(0u, session_->num_created_streams()); | |
5304 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
5305 EXPECT_EQ(1u, session_->num_active_pushed_streams()); | |
5306 | |
5307 // Read EOF. | |
5308 data.Resume(); | |
5309 base::RunLoop().RunUntilIdle(); | |
5310 EXPECT_FALSE(session_); | |
5311 } | |
5312 | |
5313 TEST_F(SpdySessionTest, CancelReservedStreamOnHeadersReceived) { | |
5314 const char kPushedUrl[] = "https://www.example.org/a.dat"; | |
5315 SpdyHeaderBlock push_headers; | |
5316 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_headers); | |
5317 SpdySerializedFrame push_promise( | |
5318 spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 2, 1)); | |
5319 SpdySerializedFrame headers_frame( | |
5320 spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0)); | |
5321 MockRead reads[] = { | |
5322 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(push_promise, 2), | |
5323 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(headers_frame, 5), | |
5324 MockRead(ASYNC, ERR_IO_PENDING, 7), MockRead(ASYNC, 0, 8), | |
5325 }; | |
5326 | |
5327 SpdySerializedFrame req( | |
5328 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
5329 SpdySerializedFrame priority( | |
5330 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
5331 SpdySerializedFrame rst( | |
5332 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_CANCEL)); | |
5333 MockWrite writes[] = { | |
5334 CreateMockWrite(req, 0), CreateMockWrite(priority, 3), | |
5335 CreateMockWrite(rst, 6), | |
5336 }; | |
5337 | |
5338 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
5339 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5340 | |
5341 AddSSLSocketData(); | |
5342 | |
5343 CreateNetworkSession(); | |
5344 CreateSecureSpdySession(); | |
5345 | |
5346 base::WeakPtr<SpdyStream> spdy_stream1 = | |
5347 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
5348 test_url_, LOWEST, NetLogWithSource()); | |
5349 ASSERT_TRUE(spdy_stream1); | |
5350 EXPECT_EQ(0u, spdy_stream1->stream_id()); | |
5351 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
5352 spdy_stream1->SetDelegate(&delegate1); | |
5353 | |
5354 EXPECT_EQ(0u, session_->num_active_streams()); | |
5355 EXPECT_EQ(1u, session_->num_created_streams()); | |
5356 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5357 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5358 | |
5359 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
5360 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
5361 | |
5362 // Run until 1st stream is activated. | |
5363 EXPECT_EQ(0u, delegate1.stream_id()); | |
5364 base::RunLoop().RunUntilIdle(); | |
5365 EXPECT_EQ(1u, delegate1.stream_id()); | |
5366 EXPECT_EQ(1u, session_->num_active_streams()); | |
5367 EXPECT_EQ(0u, session_->num_created_streams()); | |
5368 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5369 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5370 | |
5371 // Run until pushed stream is created. | |
5372 data.Resume(); | |
5373 base::RunLoop().RunUntilIdle(); | |
5374 EXPECT_EQ(2u, session_->num_active_streams()); | |
5375 EXPECT_EQ(0u, session_->num_created_streams()); | |
5376 EXPECT_EQ(1u, session_->num_pushed_streams()); | |
5377 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5378 | |
5379 SpdyStream* pushed_stream; | |
5380 int rv = session_->GetPushStream(GURL(kPushedUrl), IDLE, &pushed_stream, | |
5381 NetLogWithSource()); | |
5382 ASSERT_THAT(rv, IsOk()); | |
5383 ASSERT_TRUE(pushed_stream); | |
5384 test::StreamDelegateCloseOnHeaders delegate2(pushed_stream->GetWeakPtr()); | |
5385 pushed_stream->SetDelegate(&delegate2); | |
5386 | |
5387 // Receive headers for pushed stream. Delegate will cancel the stream, ensure | |
5388 // that all our counters are in consistent state. | |
5389 data.Resume(); | |
5390 base::RunLoop().RunUntilIdle(); | |
5391 EXPECT_EQ(1u, session_->num_active_streams()); | |
5392 EXPECT_EQ(0u, session_->num_created_streams()); | |
5393 EXPECT_EQ(0u, session_->num_pushed_streams()); | |
5394 EXPECT_EQ(0u, session_->num_active_pushed_streams()); | |
5395 | |
5396 // Read EOF. | |
5397 data.Resume(); | |
5398 base::RunLoop().RunUntilIdle(); | |
5399 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
5400 EXPECT_TRUE(data.AllReadDataConsumed()); | |
5401 } | |
5402 | |
5403 TEST_F(SpdySessionTest, RejectInvalidUnknownFrames) { | |
5404 session_deps_.host_resolver->set_synchronous_mode(true); | |
5405 | |
5406 MockRead reads[] = { | |
5407 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
5408 }; | |
5409 | |
5410 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); | |
5411 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5412 | |
5413 AddSSLSocketData(); | |
5414 | |
5415 CreateNetworkSession(); | |
5416 CreateSecureSpdySession(); | |
5417 | |
5418 session_->stream_hi_water_mark_ = 5; | |
5419 // Low client (odd) ids are fine. | |
5420 EXPECT_TRUE(session_->OnUnknownFrame(3, 0)); | |
5421 // Client id exceeding watermark. | |
5422 EXPECT_FALSE(session_->OnUnknownFrame(9, 0)); | |
5423 | |
5424 session_->last_accepted_push_stream_id_ = 6; | |
5425 // Low server (even) ids are fine. | |
5426 EXPECT_TRUE(session_->OnUnknownFrame(2, 0)); | |
5427 // Server id exceeding last accepted id. | |
5428 EXPECT_FALSE(session_->OnUnknownFrame(8, 0)); | |
5429 } | |
5430 | |
5431 enum ReadIfReadySupport { | |
5432 // ReadIfReady() field trial is enabled, and ReadIfReady() is implemented. | |
5433 READ_IF_READY_ENABLED_SUPPORTED, | |
5434 // ReadIfReady() field trial is enabled, but ReadIfReady() is unimplemented. | |
5435 READ_IF_READY_ENABLED_NOT_SUPPORTED, | |
5436 // ReadIfReady() field trial is disabled. | |
5437 READ_IF_READY_DISABLED, | |
5438 }; | |
5439 | |
5440 class SpdySessionReadIfReadyTest | |
5441 : public SpdySessionTest, | |
5442 public testing::WithParamInterface<ReadIfReadySupport> { | |
5443 public: | |
5444 void SetUp() override { | |
5445 if (GetParam() != READ_IF_READY_DISABLED) | |
5446 scoped_feature_list_.InitAndEnableFeature(Socket::kReadIfReadyExperiment); | |
5447 if (GetParam() == READ_IF_READY_ENABLED_SUPPORTED) | |
5448 session_deps_.socket_factory->set_enable_read_if_ready(true); | |
5449 SpdySessionTest::SetUp(); | |
5450 } | |
5451 | |
5452 private: | |
5453 base::test::ScopedFeatureList scoped_feature_list_; | |
5454 }; | |
5455 | |
5456 INSTANTIATE_TEST_CASE_P(/* no prefix */, | |
5457 SpdySessionReadIfReadyTest, | |
5458 testing::Values(READ_IF_READY_ENABLED_SUPPORTED, | |
5459 READ_IF_READY_ENABLED_NOT_SUPPORTED, | |
5460 READ_IF_READY_DISABLED)); | |
5461 | |
5462 // Tests basic functionality of ReadIfReady() when it is enabled or disabled. | |
5463 TEST_P(SpdySessionReadIfReadyTest, ReadIfReady) { | |
5464 SpdySerializedFrame req( | |
5465 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST, true)); | |
5466 MockWrite writes[] = { | |
5467 CreateMockWrite(req, 0), | |
5468 }; | |
5469 | |
5470 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
5471 SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); | |
5472 MockRead reads[] = { | |
5473 CreateMockRead(resp, 1), CreateMockRead(body, 2), | |
5474 MockRead(ASYNC, 0, 3) // EOF | |
5475 }; | |
5476 | |
5477 session_deps_.host_resolver->set_synchronous_mode(true); | |
5478 | |
5479 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
5480 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5481 | |
5482 AddSSLSocketData(); | |
5483 | |
5484 CreateNetworkSession(); | |
5485 CreateSecureSpdySession(); | |
5486 | |
5487 base::WeakPtr<SpdyStream> spdy_stream = | |
5488 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, | |
5489 test_url_, HIGHEST, NetLogWithSource()); | |
5490 ASSERT_TRUE(spdy_stream); | |
5491 EXPECT_EQ(0u, spdy_stream->stream_id()); | |
5492 test::StreamDelegateDoNothing delegate(spdy_stream); | |
5493 spdy_stream->SetDelegate(&delegate); | |
5494 | |
5495 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
5496 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
5497 | |
5498 base::RunLoop().RunUntilIdle(); | |
5499 | |
5500 EXPECT_FALSE(spdy_stream); | |
5501 EXPECT_EQ(1u, delegate.stream_id()); | |
5502 } | |
5503 | |
5504 class SendInitialSettingsOnNewSpdySessionTest : public SpdySessionTest { | |
5505 protected: | |
5506 void RunInitialSettingsTest(const SettingsMap expected_settings) { | |
5507 session_deps_.host_resolver->set_synchronous_mode(true); | |
5508 | |
5509 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; | |
5510 | |
5511 SpdySerializedFrame settings_frame( | |
5512 spdy_util_.ConstructSpdySettings(expected_settings)); | |
5513 MockWrite writes[] = {MockWrite(ASYNC, kHttp2ConnectionHeaderPrefix, | |
5514 kHttp2ConnectionHeaderPrefixSize), | |
5515 CreateMockWrite(settings_frame)}; | |
5516 | |
5517 StaticSocketDataProvider data(reads, arraysize(reads), writes, | |
5518 arraysize(writes)); | |
5519 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5520 AddSSLSocketData(); | |
5521 | |
5522 CreateNetworkSession(); | |
5523 | |
5524 SpdySessionPoolPeer pool_peer(spdy_session_pool_); | |
5525 pool_peer.SetEnableSendingInitialData(true); | |
5526 | |
5527 CreateSecureSpdySession(); | |
5528 | |
5529 base::RunLoop().RunUntilIdle(); | |
5530 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
5531 } | |
5532 }; | |
5533 | |
5534 // Setting values when Params::http2_settings is empty. Note that | |
5535 // SETTINGS_INITIAL_WINDOW_SIZE is sent in production, because it is set to a | |
5536 // non-default value, but it is not sent in tests, because the protocol default | |
5537 // value is used in tests. | |
5538 TEST_F(SendInitialSettingsOnNewSpdySessionTest, Empty) { | |
5539 SettingsMap expected_settings; | |
5540 expected_settings[SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize; | |
5541 expected_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
5542 kSpdyMaxConcurrentPushedStreams; | |
5543 RunInitialSettingsTest(expected_settings); | |
5544 } | |
5545 | |
5546 // When a setting is set to the protocol default value, | |
5547 // no corresponding value is sent on the wire. | |
5548 TEST_F(SendInitialSettingsOnNewSpdySessionTest, ProtocolDefault) { | |
5549 // Explicitly set protocol default values for the following settings. | |
5550 session_deps_.http2_settings[SETTINGS_HEADER_TABLE_SIZE] = 4096; | |
5551 session_deps_.http2_settings[SETTINGS_ENABLE_PUSH] = 1; | |
5552 session_deps_.http2_settings[SETTINGS_INITIAL_WINDOW_SIZE] = 64 * 1024 - 1; | |
5553 | |
5554 SettingsMap expected_settings; | |
5555 expected_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
5556 kSpdyMaxConcurrentPushedStreams; | |
5557 RunInitialSettingsTest(expected_settings); | |
5558 } | |
5559 | |
5560 // Values set in Params::http2_settings overwrite Chromium's default values. | |
5561 TEST_F(SendInitialSettingsOnNewSpdySessionTest, OverwriteValues) { | |
5562 session_deps_.http2_settings[SETTINGS_HEADER_TABLE_SIZE] = 16 * 1024; | |
5563 session_deps_.http2_settings[SETTINGS_ENABLE_PUSH] = 0; | |
5564 session_deps_.http2_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = 42; | |
5565 session_deps_.http2_settings[SETTINGS_INITIAL_WINDOW_SIZE] = 32 * 1024; | |
5566 | |
5567 SettingsMap expected_settings; | |
5568 expected_settings[SETTINGS_HEADER_TABLE_SIZE] = 16 * 1024; | |
5569 expected_settings[SETTINGS_ENABLE_PUSH] = 0; | |
5570 expected_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = 42; | |
5571 expected_settings[SETTINGS_INITIAL_WINDOW_SIZE] = 32 * 1024; | |
5572 RunInitialSettingsTest(expected_settings); | |
5573 } | |
5574 | |
5575 // Unknown parameters should still be sent to the server. | |
5576 TEST_F(SendInitialSettingsOnNewSpdySessionTest, UnknownSettings) { | |
5577 // The following parameters are not defined in the HTTP/2 specification. | |
5578 session_deps_.http2_settings[static_cast<SpdySettingsIds>(7)] = 1234; | |
5579 session_deps_.http2_settings[static_cast<SpdySettingsIds>(25)] = 5678; | |
5580 | |
5581 SettingsMap expected_settings; | |
5582 expected_settings[SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize; | |
5583 expected_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
5584 kSpdyMaxConcurrentPushedStreams; | |
5585 expected_settings[static_cast<SpdySettingsIds>(7)] = 1234; | |
5586 expected_settings[static_cast<SpdySettingsIds>(25)] = 5678; | |
5587 RunInitialSettingsTest(expected_settings); | |
5588 } | |
5589 | |
5590 class AltSvcFrameTest : public SpdySessionTest { | |
5591 public: | |
5592 AltSvcFrameTest() | |
5593 : alternative_service_("quic", | |
5594 "alternative.example.org", | |
5595 443, | |
5596 86400, | |
5597 SpdyAltSvcWireFormat::VersionVector()) {} | |
5598 | |
5599 void AddSocketData(const SpdyAltSvcIR& altsvc_ir) { | |
5600 altsvc_frame_ = spdy_util_.SerializeFrame(altsvc_ir); | |
5601 reads_.push_back(CreateMockRead(altsvc_frame_, 0)); | |
5602 reads_.push_back(MockRead(ASYNC, 0, 1)); | |
5603 | |
5604 data_.reset( | |
5605 new SequencedSocketData(reads_.data(), reads_.size(), nullptr, 0)); | |
5606 session_deps_.socket_factory->AddSocketDataProvider(data_.get()); | |
5607 } | |
5608 | |
5609 void CreateSecureSpdySession() { | |
5610 session_ = ::net::CreateSecureSpdySession(http_session_.get(), key_, | |
5611 NetLogWithSource()); | |
5612 } | |
5613 | |
5614 SpdyAltSvcWireFormat::AlternativeService alternative_service_; | |
5615 | |
5616 private: | |
5617 SpdySerializedFrame altsvc_frame_; | |
5618 std::vector<MockRead> reads_; | |
5619 std::unique_ptr<SequencedSocketData> data_; | |
5620 }; | |
5621 | |
5622 TEST_F(AltSvcFrameTest, ProcessAltSvcFrame) { | |
5623 const char origin[] = "https://mail.example.org"; | |
5624 SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0); | |
5625 altsvc_ir.add_altsvc(alternative_service_); | |
5626 altsvc_ir.set_origin(origin); | |
5627 AddSocketData(altsvc_ir); | |
5628 AddSSLSocketData(); | |
5629 | |
5630 CreateNetworkSession(); | |
5631 CreateSecureSpdySession(); | |
5632 | |
5633 base::RunLoop().RunUntilIdle(); | |
5634 | |
5635 const url::SchemeHostPort session_origin("https", test_url_.host(), | |
5636 test_url_.EffectiveIntPort()); | |
5637 AlternativeServiceVector altsvc_vector = | |
5638 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5639 session_origin); | |
5640 ASSERT_TRUE(altsvc_vector.empty()); | |
5641 | |
5642 altsvc_vector = | |
5643 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5644 url::SchemeHostPort(GURL(origin))); | |
5645 ASSERT_EQ(1u, altsvc_vector.size()); | |
5646 EXPECT_EQ(kProtoQUIC, altsvc_vector[0].protocol); | |
5647 EXPECT_EQ("alternative.example.org", altsvc_vector[0].host); | |
5648 EXPECT_EQ(443u, altsvc_vector[0].port); | |
5649 } | |
5650 | |
5651 TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameOnInsecureSession) { | |
5652 const char origin[] = "https://mail.example.org"; | |
5653 SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0); | |
5654 altsvc_ir.add_altsvc(alternative_service_); | |
5655 altsvc_ir.set_origin(origin); | |
5656 AddSocketData(altsvc_ir); | |
5657 AddSSLSocketData(); | |
5658 | |
5659 CreateNetworkSession(); | |
5660 CreateInsecureSpdySession(); | |
5661 | |
5662 base::RunLoop().RunUntilIdle(); | |
5663 | |
5664 const url::SchemeHostPort session_origin("https", test_url_.host(), | |
5665 test_url_.EffectiveIntPort()); | |
5666 AlternativeServiceVector altsvc_vector = | |
5667 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5668 session_origin); | |
5669 ASSERT_TRUE(altsvc_vector.empty()); | |
5670 | |
5671 altsvc_vector = | |
5672 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5673 url::SchemeHostPort(GURL(origin))); | |
5674 ASSERT_TRUE(altsvc_vector.empty()); | |
5675 } | |
5676 | |
5677 TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameForOriginNotCoveredByCert) { | |
5678 const char origin[] = "https://invalid.example.org"; | |
5679 SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0); | |
5680 altsvc_ir.add_altsvc(alternative_service_); | |
5681 altsvc_ir.set_origin(origin); | |
5682 AddSocketData(altsvc_ir); | |
5683 AddSSLSocketData(); | |
5684 | |
5685 CreateNetworkSession(); | |
5686 CreateSecureSpdySession(); | |
5687 | |
5688 base::RunLoop().RunUntilIdle(); | |
5689 | |
5690 const url::SchemeHostPort session_origin("https", test_url_.host(), | |
5691 test_url_.EffectiveIntPort()); | |
5692 AlternativeServiceVector altsvc_vector = | |
5693 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5694 session_origin); | |
5695 ASSERT_TRUE(altsvc_vector.empty()); | |
5696 | |
5697 altsvc_vector = | |
5698 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5699 url::SchemeHostPort(GURL(origin))); | |
5700 ASSERT_TRUE(altsvc_vector.empty()); | |
5701 } | |
5702 | |
5703 // An ALTSVC frame on stream 0 with empty origin MUST be ignored. | |
5704 // (RFC 7838 Section 4) | |
5705 TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameWithEmptyOriginOnStreamZero) { | |
5706 SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0); | |
5707 altsvc_ir.add_altsvc(alternative_service_); | |
5708 AddSocketData(altsvc_ir); | |
5709 AddSSLSocketData(); | |
5710 | |
5711 CreateNetworkSession(); | |
5712 CreateSecureSpdySession(); | |
5713 | |
5714 base::RunLoop().RunUntilIdle(); | |
5715 | |
5716 const url::SchemeHostPort session_origin("https", test_url_.host(), | |
5717 test_url_.EffectiveIntPort()); | |
5718 AlternativeServiceVector altsvc_vector = | |
5719 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5720 session_origin); | |
5721 ASSERT_TRUE(altsvc_vector.empty()); | |
5722 } | |
5723 | |
5724 // An ALTSVC frame on a stream other than stream 0 with non-empty origin MUST be | |
5725 // ignored. (RFC 7838 Section 4) | |
5726 TEST_F(AltSvcFrameTest, | |
5727 DoNotProcessAltSvcFrameWithNonEmptyOriginOnNonZeroStream) { | |
5728 SpdyAltSvcIR altsvc_ir(/* stream_id = */ 1); | |
5729 altsvc_ir.add_altsvc(alternative_service_); | |
5730 altsvc_ir.set_origin("https://mail.example.org"); | |
5731 AddSocketData(altsvc_ir); | |
5732 AddSSLSocketData(); | |
5733 | |
5734 CreateNetworkSession(); | |
5735 CreateSecureSpdySession(); | |
5736 | |
5737 base::RunLoop().RunUntilIdle(); | |
5738 | |
5739 const url::SchemeHostPort session_origin("https", test_url_.host(), | |
5740 test_url_.EffectiveIntPort()); | |
5741 AlternativeServiceVector altsvc_vector = | |
5742 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5743 session_origin); | |
5744 ASSERT_TRUE(altsvc_vector.empty()); | |
5745 } | |
5746 | |
5747 TEST_F(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) { | |
5748 SpdyAltSvcIR altsvc_ir(/* stream_id = */ 1); | |
5749 altsvc_ir.add_altsvc(alternative_service_); | |
5750 | |
5751 SpdySerializedFrame altsvc_frame(spdy_util_.SerializeFrame(altsvc_ir)); | |
5752 SpdySerializedFrame rst( | |
5753 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_REFUSED_STREAM)); | |
5754 MockRead reads[] = { | |
5755 CreateMockRead(altsvc_frame, 1), CreateMockRead(rst, 2), | |
5756 MockRead(ASYNC, 0, 3) // EOF | |
5757 }; | |
5758 | |
5759 const char request_origin[] = "https://mail.example.org"; | |
5760 SpdySerializedFrame req( | |
5761 spdy_util_.ConstructSpdyGet(request_origin, 1, MEDIUM)); | |
5762 MockWrite writes[] = { | |
5763 CreateMockWrite(req, 0), | |
5764 }; | |
5765 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
5766 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5767 | |
5768 AddSSLSocketData(); | |
5769 | |
5770 CreateNetworkSession(); | |
5771 CreateSecureSpdySession(); | |
5772 | |
5773 base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously( | |
5774 SPDY_REQUEST_RESPONSE_STREAM, session_, GURL(request_origin), MEDIUM, | |
5775 NetLogWithSource()); | |
5776 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
5777 spdy_stream1->SetDelegate(&delegate1); | |
5778 | |
5779 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(request_origin)); | |
5780 | |
5781 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
5782 | |
5783 base::RunLoop().RunUntilIdle(); | |
5784 | |
5785 const url::SchemeHostPort session_origin("https", test_url_.host(), | |
5786 test_url_.EffectiveIntPort()); | |
5787 AlternativeServiceVector altsvc_vector = | |
5788 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5789 session_origin); | |
5790 ASSERT_TRUE(altsvc_vector.empty()); | |
5791 | |
5792 altsvc_vector = | |
5793 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5794 url::SchemeHostPort(GURL(request_origin))); | |
5795 ASSERT_EQ(1u, altsvc_vector.size()); | |
5796 EXPECT_EQ(kProtoQUIC, altsvc_vector[0].protocol); | |
5797 EXPECT_EQ("alternative.example.org", altsvc_vector[0].host); | |
5798 EXPECT_EQ(443u, altsvc_vector[0].port); | |
5799 } | |
5800 | |
5801 TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameOnStreamWithInsecureOrigin) { | |
5802 SpdyAltSvcIR altsvc_ir(/* stream_id = */ 1); | |
5803 altsvc_ir.add_altsvc(alternative_service_); | |
5804 | |
5805 SpdySerializedFrame altsvc_frame(spdy_util_.SerializeFrame(altsvc_ir)); | |
5806 SpdySerializedFrame rst( | |
5807 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_REFUSED_STREAM)); | |
5808 MockRead reads[] = { | |
5809 CreateMockRead(altsvc_frame, 1), CreateMockRead(rst, 2), | |
5810 MockRead(ASYNC, 0, 3) // EOF | |
5811 }; | |
5812 | |
5813 const char request_origin[] = "http://mail.example.org"; | |
5814 SpdySerializedFrame req( | |
5815 spdy_util_.ConstructSpdyGet(request_origin, 1, MEDIUM)); | |
5816 MockWrite writes[] = { | |
5817 CreateMockWrite(req, 0), | |
5818 }; | |
5819 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); | |
5820 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
5821 | |
5822 AddSSLSocketData(); | |
5823 | |
5824 CreateNetworkSession(); | |
5825 CreateSecureSpdySession(); | |
5826 | |
5827 base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously( | |
5828 SPDY_REQUEST_RESPONSE_STREAM, session_, GURL(request_origin), MEDIUM, | |
5829 NetLogWithSource()); | |
5830 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
5831 spdy_stream1->SetDelegate(&delegate1); | |
5832 | |
5833 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(request_origin)); | |
5834 | |
5835 spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); | |
5836 | |
5837 base::RunLoop().RunUntilIdle(); | |
5838 | |
5839 const url::SchemeHostPort session_origin("https", test_url_.host(), | |
5840 test_url_.EffectiveIntPort()); | |
5841 AlternativeServiceVector altsvc_vector = | |
5842 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5843 session_origin); | |
5844 ASSERT_TRUE(altsvc_vector.empty()); | |
5845 | |
5846 altsvc_vector = | |
5847 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5848 url::SchemeHostPort(GURL(request_origin))); | |
5849 ASSERT_TRUE(altsvc_vector.empty()); | |
5850 } | |
5851 | |
5852 TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameOnNonExistentStream) { | |
5853 SpdyAltSvcIR altsvc_ir(/* stream_id = */ 1); | |
5854 altsvc_ir.add_altsvc(alternative_service_); | |
5855 AddSocketData(altsvc_ir); | |
5856 AddSSLSocketData(); | |
5857 | |
5858 CreateNetworkSession(); | |
5859 CreateSecureSpdySession(); | |
5860 | |
5861 base::RunLoop().RunUntilIdle(); | |
5862 | |
5863 const url::SchemeHostPort session_origin("https", test_url_.host(), | |
5864 test_url_.EffectiveIntPort()); | |
5865 AlternativeServiceVector altsvc_vector = | |
5866 spdy_session_pool_->http_server_properties()->GetAlternativeServices( | |
5867 session_origin); | |
5868 ASSERT_TRUE(altsvc_vector.empty()); | |
5869 } | |
5870 | |
5871 TEST(MapFramerErrorToProtocolError, MapsValues) { | |
5872 CHECK_EQ( | |
5873 SPDY_ERROR_INVALID_CONTROL_FRAME, | |
5874 MapFramerErrorToProtocolError(SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); | |
5875 CHECK_EQ( | |
5876 SPDY_ERROR_INVALID_DATA_FRAME_FLAGS, | |
5877 MapFramerErrorToProtocolError(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS)); | |
5878 CHECK_EQ( | |
5879 SPDY_ERROR_GOAWAY_FRAME_CORRUPT, | |
5880 MapFramerErrorToProtocolError(SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT)); | |
5881 CHECK_EQ(SPDY_ERROR_UNEXPECTED_FRAME, | |
5882 MapFramerErrorToProtocolError(SpdyFramer::SPDY_UNEXPECTED_FRAME)); | |
5883 } | |
5884 | |
5885 TEST(MapFramerErrorToNetError, MapsValue) { | |
5886 CHECK_EQ(ERR_SPDY_PROTOCOL_ERROR, | |
5887 MapFramerErrorToNetError(SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); | |
5888 CHECK_EQ(ERR_SPDY_COMPRESSION_ERROR, | |
5889 MapFramerErrorToNetError(SpdyFramer::SPDY_COMPRESS_FAILURE)); | |
5890 CHECK_EQ(ERR_SPDY_COMPRESSION_ERROR, | |
5891 MapFramerErrorToNetError(SpdyFramer::SPDY_DECOMPRESS_FAILURE)); | |
5892 CHECK_EQ( | |
5893 ERR_SPDY_FRAME_SIZE_ERROR, | |
5894 MapFramerErrorToNetError(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); | |
5895 CHECK_EQ(ERR_SPDY_FRAME_SIZE_ERROR, | |
5896 MapFramerErrorToNetError(SpdyFramer::SPDY_OVERSIZED_PAYLOAD)); | |
5897 } | |
5898 | |
5899 TEST(MapRstStreamStatusToProtocolError, MapsValues) { | |
5900 CHECK_EQ(STATUS_CODE_PROTOCOL_ERROR, | |
5901 MapRstStreamStatusToProtocolError(ERROR_CODE_PROTOCOL_ERROR)); | |
5902 CHECK_EQ(STATUS_CODE_FRAME_SIZE_ERROR, | |
5903 MapRstStreamStatusToProtocolError(ERROR_CODE_FRAME_SIZE_ERROR)); | |
5904 CHECK_EQ(STATUS_CODE_ENHANCE_YOUR_CALM, | |
5905 MapRstStreamStatusToProtocolError(ERROR_CODE_ENHANCE_YOUR_CALM)); | |
5906 CHECK_EQ(STATUS_CODE_INADEQUATE_SECURITY, | |
5907 MapRstStreamStatusToProtocolError(ERROR_CODE_INADEQUATE_SECURITY)); | |
5908 CHECK_EQ(STATUS_CODE_HTTP_1_1_REQUIRED, | |
5909 MapRstStreamStatusToProtocolError(ERROR_CODE_HTTP_1_1_REQUIRED)); | |
5910 } | |
5911 | |
5912 TEST(MapNetErrorToGoAwayStatus, MapsValue) { | |
5913 CHECK_EQ(ERROR_CODE_INADEQUATE_SECURITY, | |
5914 MapNetErrorToGoAwayStatus(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY)); | |
5915 CHECK_EQ(ERROR_CODE_FLOW_CONTROL_ERROR, | |
5916 MapNetErrorToGoAwayStatus(ERR_SPDY_FLOW_CONTROL_ERROR)); | |
5917 CHECK_EQ(ERROR_CODE_PROTOCOL_ERROR, | |
5918 MapNetErrorToGoAwayStatus(ERR_SPDY_PROTOCOL_ERROR)); | |
5919 CHECK_EQ(ERROR_CODE_COMPRESSION_ERROR, | |
5920 MapNetErrorToGoAwayStatus(ERR_SPDY_COMPRESSION_ERROR)); | |
5921 CHECK_EQ(ERROR_CODE_FRAME_SIZE_ERROR, | |
5922 MapNetErrorToGoAwayStatus(ERR_SPDY_FRAME_SIZE_ERROR)); | |
5923 CHECK_EQ(ERROR_CODE_PROTOCOL_ERROR, | |
5924 MapNetErrorToGoAwayStatus(ERR_UNEXPECTED)); | |
5925 } | |
5926 | |
5927 TEST(CanPoolTest, CanPool) { | |
5928 // Load a cert that is valid for: | |
5929 // www.example.org | |
5930 // mail.example.org | |
5931 // mail.example.com | |
5932 | |
5933 TransportSecurityState tss; | |
5934 SSLInfo ssl_info; | |
5935 ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), | |
5936 "spdy_pooling.pem"); | |
5937 | |
5938 EXPECT_TRUE(SpdySession::CanPool( | |
5939 &tss, ssl_info, "www.example.org", "www.example.org")); | |
5940 EXPECT_TRUE(SpdySession::CanPool( | |
5941 &tss, ssl_info, "www.example.org", "mail.example.org")); | |
5942 EXPECT_TRUE(SpdySession::CanPool( | |
5943 &tss, ssl_info, "www.example.org", "mail.example.com")); | |
5944 EXPECT_FALSE(SpdySession::CanPool( | |
5945 &tss, ssl_info, "www.example.org", "mail.google.com")); | |
5946 } | |
5947 | |
5948 TEST(CanPoolTest, CanNotPoolWithCertErrors) { | |
5949 // Load a cert that is valid for: | |
5950 // www.example.org | |
5951 // mail.example.org | |
5952 // mail.example.com | |
5953 | |
5954 TransportSecurityState tss; | |
5955 SSLInfo ssl_info; | |
5956 ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), | |
5957 "spdy_pooling.pem"); | |
5958 ssl_info.cert_status = CERT_STATUS_REVOKED; | |
5959 | |
5960 EXPECT_FALSE(SpdySession::CanPool( | |
5961 &tss, ssl_info, "www.example.org", "mail.example.org")); | |
5962 } | |
5963 | |
5964 TEST(CanPoolTest, CanNotPoolWithClientCerts) { | |
5965 // Load a cert that is valid for: | |
5966 // www.example.org | |
5967 // mail.example.org | |
5968 // mail.example.com | |
5969 | |
5970 TransportSecurityState tss; | |
5971 SSLInfo ssl_info; | |
5972 ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), | |
5973 "spdy_pooling.pem"); | |
5974 ssl_info.client_cert_sent = true; | |
5975 | |
5976 EXPECT_FALSE(SpdySession::CanPool( | |
5977 &tss, ssl_info, "www.example.org", "mail.example.org")); | |
5978 } | |
5979 | |
5980 TEST(CanPoolTest, CanNotPoolAcrossETLDsWithChannelID) { | |
5981 // Load a cert that is valid for: | |
5982 // www.example.org | |
5983 // mail.example.org | |
5984 // mail.example.com | |
5985 | |
5986 TransportSecurityState tss; | |
5987 SSLInfo ssl_info; | |
5988 ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), | |
5989 "spdy_pooling.pem"); | |
5990 ssl_info.channel_id_sent = true; | |
5991 | |
5992 EXPECT_TRUE(SpdySession::CanPool( | |
5993 &tss, ssl_info, "www.example.org", "mail.example.org")); | |
5994 EXPECT_FALSE(SpdySession::CanPool( | |
5995 &tss, ssl_info, "www.example.org", "www.example.com")); | |
5996 } | |
5997 | |
5998 TEST(CanPoolTest, CanNotPoolWithBadPins) { | |
5999 uint8_t primary_pin = 1; | |
6000 uint8_t backup_pin = 2; | |
6001 uint8_t bad_pin = 3; | |
6002 TransportSecurityState tss; | |
6003 test::AddPin(&tss, "mail.example.org", primary_pin, backup_pin); | |
6004 | |
6005 SSLInfo ssl_info; | |
6006 ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), | |
6007 "spdy_pooling.pem"); | |
6008 ssl_info.is_issued_by_known_root = true; | |
6009 ssl_info.public_key_hashes.push_back(test::GetTestHashValue(bad_pin)); | |
6010 | |
6011 EXPECT_FALSE(SpdySession::CanPool( | |
6012 &tss, ssl_info, "www.example.org", "mail.example.org")); | |
6013 } | |
6014 | |
6015 TEST(CanPoolTest, CanNotPoolWithBadCTWhenCTRequired) { | |
6016 using testing::Return; | |
6017 using CTRequirementLevel = | |
6018 TransportSecurityState::RequireCTDelegate::CTRequirementLevel; | |
6019 | |
6020 SSLInfo ssl_info; | |
6021 ssl_info.cert = | |
6022 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); | |
6023 ssl_info.is_issued_by_known_root = true; | |
6024 ssl_info.public_key_hashes.push_back(test::GetTestHashValue(1)); | |
6025 ssl_info.ct_cert_policy_compliance = | |
6026 ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS; | |
6027 | |
6028 MockRequireCTDelegate require_ct_delegate; | |
6029 EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost("www.example.org")) | |
6030 .WillRepeatedly(Return(CTRequirementLevel::NOT_REQUIRED)); | |
6031 EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost("mail.example.org")) | |
6032 .WillRepeatedly(Return(CTRequirementLevel::REQUIRED)); | |
6033 | |
6034 TransportSecurityState tss; | |
6035 tss.SetRequireCTDelegate(&require_ct_delegate); | |
6036 | |
6037 EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, "www.example.org", | |
6038 "mail.example.org")); | |
6039 } | |
6040 | |
6041 TEST(CanPoolTest, CanPoolWithBadCTWhenCTNotRequired) { | |
6042 using testing::Return; | |
6043 using CTRequirementLevel = | |
6044 TransportSecurityState::RequireCTDelegate::CTRequirementLevel; | |
6045 | |
6046 SSLInfo ssl_info; | |
6047 ssl_info.cert = | |
6048 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); | |
6049 ssl_info.is_issued_by_known_root = true; | |
6050 ssl_info.public_key_hashes.push_back(test::GetTestHashValue(1)); | |
6051 ssl_info.ct_cert_policy_compliance = | |
6052 ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS; | |
6053 | |
6054 MockRequireCTDelegate require_ct_delegate; | |
6055 EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost("www.example.org")) | |
6056 .WillRepeatedly(Return(CTRequirementLevel::NOT_REQUIRED)); | |
6057 EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost("mail.example.org")) | |
6058 .WillRepeatedly(Return(CTRequirementLevel::NOT_REQUIRED)); | |
6059 | |
6060 TransportSecurityState tss; | |
6061 tss.SetRequireCTDelegate(&require_ct_delegate); | |
6062 | |
6063 EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, "www.example.org", | |
6064 "mail.example.org")); | |
6065 } | |
6066 | |
6067 TEST(CanPoolTest, CanPoolWithGoodCTWhenCTRequired) { | |
6068 using testing::Return; | |
6069 using CTRequirementLevel = | |
6070 TransportSecurityState::RequireCTDelegate::CTRequirementLevel; | |
6071 | |
6072 SSLInfo ssl_info; | |
6073 ssl_info.cert = | |
6074 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); | |
6075 ssl_info.is_issued_by_known_root = true; | |
6076 ssl_info.public_key_hashes.push_back(test::GetTestHashValue(1)); | |
6077 ssl_info.ct_cert_policy_compliance = | |
6078 ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS; | |
6079 | |
6080 MockRequireCTDelegate require_ct_delegate; | |
6081 EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost("www.example.org")) | |
6082 .WillRepeatedly(Return(CTRequirementLevel::NOT_REQUIRED)); | |
6083 EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost("mail.example.org")) | |
6084 .WillRepeatedly(Return(CTRequirementLevel::REQUIRED)); | |
6085 | |
6086 TransportSecurityState tss; | |
6087 tss.SetRequireCTDelegate(&require_ct_delegate); | |
6088 | |
6089 EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, "www.example.org", | |
6090 "mail.example.org")); | |
6091 } | |
6092 | |
6093 TEST(CanPoolTest, CanPoolWithAcceptablePins) { | |
6094 uint8_t primary_pin = 1; | |
6095 uint8_t backup_pin = 2; | |
6096 TransportSecurityState tss; | |
6097 test::AddPin(&tss, "mail.example.org", primary_pin, backup_pin); | |
6098 | |
6099 SSLInfo ssl_info; | |
6100 ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), | |
6101 "spdy_pooling.pem"); | |
6102 ssl_info.is_issued_by_known_root = true; | |
6103 ssl_info.public_key_hashes.push_back(test::GetTestHashValue(primary_pin)); | |
6104 | |
6105 EXPECT_TRUE(SpdySession::CanPool( | |
6106 &tss, ssl_info, "www.example.org", "mail.example.org")); | |
6107 } | |
6108 | |
6109 } // namespace net | |
OLD | NEW |