1 // Copyright (c) 2013 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.
5 #include "net/spdy/spdy_session_pool.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "net/dns/host_cache.h"
13 #include "net/http/http_network_session.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/transport_client_socket_pool.h"
16 #include "net/spdy/spdy_session.h"
17 #include "net/spdy/spdy_stream_test_util.h"
18 #include "net/spdy/spdy_test_util_common.h"
19 #include "testing/gtest/include/gtest/gtest.h"
25 class SpdySessionPoolTest
: public ::testing::Test
,
26 public ::testing::WithParamInterface
<NextProto
> {
28 // Used by RunIPPoolingTest().
29 enum SpdyPoolCloseSessionsType
{
30 SPDY_POOL_CLOSE_SESSIONS_MANUALLY
,
31 SPDY_POOL_CLOSE_CURRENT_SESSIONS
,
32 SPDY_POOL_CLOSE_IDLE_SESSIONS
,
36 : session_deps_(GetParam()),
37 spdy_session_pool_(NULL
) {}
39 void CreateNetworkSession() {
40 http_session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
41 spdy_session_pool_
= http_session_
->spdy_session_pool();
44 void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type
);
46 SpdySessionDependencies session_deps_
;
47 scoped_refptr
<HttpNetworkSession
> http_session_
;
48 SpdySessionPool
* spdy_session_pool_
;
51 INSTANTIATE_TEST_CASE_P(NextProto
,
53 testing::Values(kProtoSPDY31
,
57 // A delegate that opens a new session when it is closed.
58 class SessionOpeningDelegate
: public SpdyStream::Delegate
{
60 SessionOpeningDelegate(SpdySessionPool
* spdy_session_pool
,
61 const SpdySessionKey
& key
)
62 : spdy_session_pool_(spdy_session_pool
),
65 ~SessionOpeningDelegate() override
{}
67 void OnRequestHeadersSent() override
{}
69 SpdyResponseHeadersStatus
OnResponseHeadersUpdated(
70 const SpdyHeaderBlock
& response_headers
) override
{
71 return RESPONSE_HEADERS_ARE_COMPLETE
;
74 void OnDataReceived(scoped_ptr
<SpdyBuffer
> buffer
) override
{}
76 void OnDataSent() override
{}
78 void OnTrailers(const SpdyHeaderBlock
& trailers
) override
{}
80 void OnClose(int status
) override
{
81 ignore_result(CreateFakeSpdySession(spdy_session_pool_
, key_
));
85 SpdySessionPool
* const spdy_session_pool_
;
86 const SpdySessionKey key_
;
89 // Set up a SpdyStream to create a new session when it is closed.
90 // CloseCurrentSessions should not close the newly-created session.
91 TEST_P(SpdySessionPoolTest
, CloseCurrentSessions
) {
92 const char kTestHost
[] = "www.foo.com";
93 const int kTestPort
= 80;
95 session_deps_
.host_resolver
->set_synchronous_mode(true);
97 HostPortPair
test_host_port_pair(kTestHost
, kTestPort
);
98 SpdySessionKey test_key
=
100 test_host_port_pair
, ProxyServer::Direct(),
101 PRIVACY_MODE_DISABLED
);
103 MockConnect
connect_data(SYNCHRONOUS
, OK
);
105 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
108 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
109 data
.set_connect_data(connect_data
);
110 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
112 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
113 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
115 CreateNetworkSession();
117 // Setup the first session to the first host.
118 base::WeakPtr
<SpdySession
> session
=
119 CreateInsecureSpdySession(http_session_
, test_key
, BoundNetLog());
121 // Flush the SpdySession::OnReadComplete() task.
122 base::MessageLoop::current()->RunUntilIdle();
124 // Verify that we have sessions for everything.
125 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
127 // Set the stream to create a new session when it is closed.
128 base::WeakPtr
<SpdyStream
> spdy_stream
=
129 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
130 session
, GURL("http://www.foo.com"),
131 MEDIUM
, BoundNetLog());
132 SessionOpeningDelegate
delegate(spdy_session_pool_
, test_key
);
133 spdy_stream
->SetDelegate(&delegate
);
135 // Close the current session.
136 spdy_session_pool_
->CloseCurrentSessions(ERR_ABORTED
);
138 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
141 TEST_P(SpdySessionPoolTest
, CloseCurrentIdleSessions
) {
142 MockConnect
connect_data(SYNCHRONOUS
, OK
);
144 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
147 session_deps_
.host_resolver
->set_synchronous_mode(true);
149 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
150 data
.set_connect_data(connect_data
);
151 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
153 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
154 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
156 CreateNetworkSession();
159 const std::string
kTestHost1("http://www.a.com");
160 HostPortPair
test_host_port_pair1(kTestHost1
, 80);
161 SpdySessionKey
key1(test_host_port_pair1
, ProxyServer::Direct(),
162 PRIVACY_MODE_DISABLED
);
163 base::WeakPtr
<SpdySession
> session1
=
164 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
165 GURL
url1(kTestHost1
);
166 base::WeakPtr
<SpdyStream
> spdy_stream1
=
167 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
168 session1
, url1
, MEDIUM
, BoundNetLog());
169 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
172 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
173 const std::string
kTestHost2("http://www.b.com");
174 HostPortPair
test_host_port_pair2(kTestHost2
, 80);
175 SpdySessionKey
key2(test_host_port_pair2
, ProxyServer::Direct(),
176 PRIVACY_MODE_DISABLED
);
177 base::WeakPtr
<SpdySession
> session2
=
178 CreateInsecureSpdySession(http_session_
, key2
, BoundNetLog());
179 GURL
url2(kTestHost2
);
180 base::WeakPtr
<SpdyStream
> spdy_stream2
=
181 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
182 session2
, url2
, MEDIUM
, BoundNetLog());
183 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
186 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
187 const std::string
kTestHost3("http://www.c.com");
188 HostPortPair
test_host_port_pair3(kTestHost3
, 80);
189 SpdySessionKey
key3(test_host_port_pair3
, ProxyServer::Direct(),
190 PRIVACY_MODE_DISABLED
);
191 base::WeakPtr
<SpdySession
> session3
=
192 CreateInsecureSpdySession(http_session_
, key3
, BoundNetLog());
193 GURL
url3(kTestHost3
);
194 base::WeakPtr
<SpdyStream
> spdy_stream3
=
195 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
196 session3
, url3
, MEDIUM
, BoundNetLog());
197 ASSERT_TRUE(spdy_stream3
.get() != NULL
);
199 // All sessions are active and not closed
200 EXPECT_TRUE(session1
->is_active());
201 EXPECT_TRUE(session1
->IsAvailable());
202 EXPECT_TRUE(session2
->is_active());
203 EXPECT_TRUE(session2
->IsAvailable());
204 EXPECT_TRUE(session3
->is_active());
205 EXPECT_TRUE(session3
->IsAvailable());
207 // Should not do anything, all are active
208 spdy_session_pool_
->CloseCurrentIdleSessions();
209 EXPECT_TRUE(session1
->is_active());
210 EXPECT_TRUE(session1
->IsAvailable());
211 EXPECT_TRUE(session2
->is_active());
212 EXPECT_TRUE(session2
->IsAvailable());
213 EXPECT_TRUE(session3
->is_active());
214 EXPECT_TRUE(session3
->IsAvailable());
216 // Make sessions 1 and 3 inactive, but keep them open.
217 // Session 2 still open and active
218 session1
->CloseCreatedStream(spdy_stream1
, OK
);
219 EXPECT_EQ(NULL
, spdy_stream1
.get());
220 session3
->CloseCreatedStream(spdy_stream3
, OK
);
221 EXPECT_EQ(NULL
, spdy_stream3
.get());
222 EXPECT_FALSE(session1
->is_active());
223 EXPECT_TRUE(session1
->IsAvailable());
224 EXPECT_TRUE(session2
->is_active());
225 EXPECT_TRUE(session2
->IsAvailable());
226 EXPECT_FALSE(session3
->is_active());
227 EXPECT_TRUE(session3
->IsAvailable());
229 // Should close session 1 and 3, 2 should be left open
230 spdy_session_pool_
->CloseCurrentIdleSessions();
231 base::MessageLoop::current()->RunUntilIdle();
233 EXPECT_TRUE(session1
== NULL
);
234 EXPECT_TRUE(session2
->is_active());
235 EXPECT_TRUE(session2
->IsAvailable());
236 EXPECT_TRUE(session3
== NULL
);
238 // Should not do anything
239 spdy_session_pool_
->CloseCurrentIdleSessions();
240 base::MessageLoop::current()->RunUntilIdle();
242 EXPECT_TRUE(session2
->is_active());
243 EXPECT_TRUE(session2
->IsAvailable());
246 session2
->CloseCreatedStream(spdy_stream2
, OK
);
247 base::MessageLoop::current()->RunUntilIdle();
249 EXPECT_EQ(NULL
, spdy_stream2
.get());
250 EXPECT_FALSE(session2
->is_active());
251 EXPECT_TRUE(session2
->IsAvailable());
253 // This should close session 2
254 spdy_session_pool_
->CloseCurrentIdleSessions();
255 base::MessageLoop::current()->RunUntilIdle();
257 EXPECT_TRUE(session2
== NULL
);
260 // Set up a SpdyStream to create a new session when it is closed.
261 // CloseAllSessions should close the newly-created session.
262 TEST_P(SpdySessionPoolTest
, CloseAllSessions
) {
263 const char kTestHost
[] = "www.foo.com";
264 const int kTestPort
= 80;
266 session_deps_
.host_resolver
->set_synchronous_mode(true);
268 HostPortPair
test_host_port_pair(kTestHost
, kTestPort
);
269 SpdySessionKey test_key
=
271 test_host_port_pair
, ProxyServer::Direct(),
272 PRIVACY_MODE_DISABLED
);
274 MockConnect
connect_data(SYNCHRONOUS
, OK
);
276 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
279 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
280 data
.set_connect_data(connect_data
);
281 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
283 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
284 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
286 CreateNetworkSession();
288 // Setup the first session to the first host.
289 base::WeakPtr
<SpdySession
> session
=
290 CreateInsecureSpdySession(http_session_
, test_key
, BoundNetLog());
292 // Flush the SpdySession::OnReadComplete() task.
293 base::MessageLoop::current()->RunUntilIdle();
295 // Verify that we have sessions for everything.
296 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
298 // Set the stream to create a new session when it is closed.
299 base::WeakPtr
<SpdyStream
> spdy_stream
=
300 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
301 session
, GURL("http://www.foo.com"),
302 MEDIUM
, BoundNetLog());
303 SessionOpeningDelegate
delegate(spdy_session_pool_
, test_key
);
304 spdy_stream
->SetDelegate(&delegate
);
306 // Close the current session.
307 spdy_session_pool_
->CloseAllSessions();
309 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_key
));
312 // This test has three variants, one for each style of closing the connection.
313 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
314 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
315 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
316 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
317 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
318 // sessions are closed with SpdySessionPool::CloseIdleSessions().
319 void SpdySessionPoolTest::RunIPPoolingTest(
320 SpdyPoolCloseSessionsType close_sessions_type
) {
321 const int kTestPort
= 80;
327 AddressList addresses
;
329 { "http:://www.foo.com",
331 "192.0.2.33,192.168.0.1,192.168.0.5"
333 { "http://js.foo.com",
335 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
337 { "http://images.foo.com",
339 "192.168.0.4,192.168.0.3"
343 session_deps_
.host_resolver
->set_synchronous_mode(true);
344 for (size_t i
= 0; i
< arraysize(test_hosts
); i
++) {
345 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
346 test_hosts
[i
].name
, test_hosts
[i
].iplist
, std::string());
348 // This test requires that the HostResolver cache be populated. Normal
349 // code would have done this already, but we do it manually.
350 HostResolver::RequestInfo
info(HostPortPair(test_hosts
[i
].name
, kTestPort
));
351 session_deps_
.host_resolver
->Resolve(info
,
353 &test_hosts
[i
].addresses
,
354 CompletionCallback(),
358 // Setup a SpdySessionKey
359 test_hosts
[i
].key
= SpdySessionKey(
360 HostPortPair(test_hosts
[i
].name
, kTestPort
), ProxyServer::Direct(),
361 PRIVACY_MODE_DISABLED
);
364 MockConnect
connect_data(SYNCHRONOUS
, OK
);
366 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
369 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
370 data
.set_connect_data(connect_data
);
371 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
373 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
374 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
376 CreateNetworkSession();
378 // Setup the first session to the first host.
379 base::WeakPtr
<SpdySession
> session
=
380 CreateInsecureSpdySession(
381 http_session_
, test_hosts
[0].key
, BoundNetLog());
383 // Flush the SpdySession::OnReadComplete() task.
384 base::MessageLoop::current()->RunUntilIdle();
386 // The third host has no overlap with the first, so it can't pool IPs.
387 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
389 // The second host overlaps with the first, and should IP pool.
390 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
392 // Verify that the second host, through a proxy, won't share the IP.
393 SpdySessionKey
proxy_key(test_hosts
[1].key
.host_port_pair(),
394 ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
395 PRIVACY_MODE_DISABLED
);
396 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, proxy_key
));
398 // Overlap between 2 and 3 does is not transitive to 1.
399 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
401 // Create a new session to host 2.
402 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
403 base::WeakPtr
<SpdySession
> session2
=
404 CreateInsecureSpdySession(
405 http_session_
, test_hosts
[2].key
, BoundNetLog());
407 // Verify that we have sessions for everything.
408 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[0].key
));
409 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
410 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
412 // Grab the session to host 1 and verify that it is the same session
413 // we got with host 0, and that is a different from host 2's session.
414 base::WeakPtr
<SpdySession
> session1
=
415 spdy_session_pool_
->FindAvailableSession(
416 test_hosts
[1].key
, BoundNetLog());
417 EXPECT_EQ(session
.get(), session1
.get());
418 EXPECT_NE(session2
.get(), session1
.get());
420 // Remove the aliases and observe that we still have a session for host1.
421 SpdySessionPoolPeer
pool_peer(spdy_session_pool_
);
422 pool_peer
.RemoveAliases(test_hosts
[0].key
);
423 pool_peer
.RemoveAliases(test_hosts
[1].key
);
424 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
426 // Expire the host cache
427 session_deps_
.host_resolver
->GetHostCache()->clear();
428 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
430 // Cleanup the sessions.
431 switch (close_sessions_type
) {
432 case SPDY_POOL_CLOSE_SESSIONS_MANUALLY
:
433 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
434 session2
->CloseSessionOnError(ERR_ABORTED
, std::string());
435 base::MessageLoop::current()->RunUntilIdle();
436 EXPECT_TRUE(session
== NULL
);
437 EXPECT_TRUE(session2
== NULL
);
439 case SPDY_POOL_CLOSE_CURRENT_SESSIONS
:
440 spdy_session_pool_
->CloseCurrentSessions(ERR_ABORTED
);
442 case SPDY_POOL_CLOSE_IDLE_SESSIONS
:
443 GURL
url(test_hosts
[0].url
);
444 base::WeakPtr
<SpdyStream
> spdy_stream
=
445 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
446 session
, url
, MEDIUM
, BoundNetLog());
447 GURL
url1(test_hosts
[1].url
);
448 base::WeakPtr
<SpdyStream
> spdy_stream1
=
449 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
450 session1
, url1
, MEDIUM
, BoundNetLog());
451 GURL
url2(test_hosts
[2].url
);
452 base::WeakPtr
<SpdyStream
> spdy_stream2
=
453 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
454 session2
, url2
, MEDIUM
, BoundNetLog());
456 // Close streams to make spdy_session and spdy_session1 inactive.
457 session
->CloseCreatedStream(spdy_stream
, OK
);
458 EXPECT_EQ(NULL
, spdy_stream
.get());
459 session1
->CloseCreatedStream(spdy_stream1
, OK
);
460 EXPECT_EQ(NULL
, spdy_stream1
.get());
462 // Check spdy_session and spdy_session1 are not closed.
463 EXPECT_FALSE(session
->is_active());
464 EXPECT_TRUE(session
->IsAvailable());
465 EXPECT_FALSE(session1
->is_active());
466 EXPECT_TRUE(session1
->IsAvailable());
467 EXPECT_TRUE(session2
->is_active());
468 EXPECT_TRUE(session2
->IsAvailable());
470 // Test that calling CloseIdleSessions, does not cause a crash.
471 // http://crbug.com/181400
472 spdy_session_pool_
->CloseCurrentIdleSessions();
473 base::MessageLoop::current()->RunUntilIdle();
475 // Verify spdy_session and spdy_session1 are closed.
476 EXPECT_TRUE(session
== NULL
);
477 EXPECT_TRUE(session1
== NULL
);
478 EXPECT_TRUE(session2
->is_active());
479 EXPECT_TRUE(session2
->IsAvailable());
481 spdy_stream2
->Cancel();
482 EXPECT_EQ(NULL
, spdy_stream
.get());
483 EXPECT_EQ(NULL
, spdy_stream1
.get());
484 EXPECT_EQ(NULL
, spdy_stream2
.get());
486 session2
->CloseSessionOnError(ERR_ABORTED
, std::string());
487 base::MessageLoop::current()->RunUntilIdle();
488 EXPECT_TRUE(session2
== NULL
);
492 // Verify that the map is all cleaned up.
493 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[0].key
));
494 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
495 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
498 TEST_P(SpdySessionPoolTest
, IPPooling
) {
499 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY
);
502 TEST_P(SpdySessionPoolTest
, IPPoolingCloseCurrentSessions
) {
503 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS
);
506 TEST_P(SpdySessionPoolTest
, IPPoolingCloseIdleSessions
) {
507 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS
);
510 // Construct a Pool with SpdySessions in various availability states. Simulate
511 // an IP address change. Ensure sessions gracefully shut down. Regression test
512 // for crbug.com/379469.
513 TEST_P(SpdySessionPoolTest
, IPAddressChanged
) {
514 MockConnect
connect_data(SYNCHRONOUS
, OK
);
515 session_deps_
.host_resolver
->set_synchronous_mode(true);
516 SpdyTestUtil
spdy_util(GetParam());
519 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
521 scoped_ptr
<SpdyFrame
> req(
522 spdy_util
.ConstructSpdyGet("http://www.a.com", false, 1, MEDIUM
));
523 MockWrite writes
[] = {CreateMockWrite(*req
, 1)};
525 StaticSocketDataProvider
data(reads
, arraysize(reads
), writes
,
527 data
.set_connect_data(connect_data
);
528 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
530 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
531 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
533 CreateNetworkSession();
535 // Set up session A: Going away, but with an active stream.
536 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
537 const std::string
kTestHostA("http://www.a.com");
538 HostPortPair
test_host_port_pairA(kTestHostA
, 80);
540 test_host_port_pairA
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
541 base::WeakPtr
<SpdySession
> sessionA
=
542 CreateInsecureSpdySession(http_session_
, keyA
, BoundNetLog());
544 GURL
urlA(kTestHostA
);
545 base::WeakPtr
<SpdyStream
> spdy_streamA
= CreateStreamSynchronously(
546 SPDY_BIDIRECTIONAL_STREAM
, sessionA
, urlA
, MEDIUM
, BoundNetLog());
547 test::StreamDelegateDoNothing
delegateA(spdy_streamA
);
548 spdy_streamA
->SetDelegate(&delegateA
);
550 scoped_ptr
<SpdyHeaderBlock
> headers(
551 spdy_util
.ConstructGetHeaderBlock(urlA
.spec()));
552 spdy_streamA
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
553 EXPECT_TRUE(spdy_streamA
->HasUrlFromHeaders());
555 base::MessageLoop::current()->RunUntilIdle(); // Allow headers to write.
556 EXPECT_TRUE(delegateA
.send_headers_completed());
558 sessionA
->MakeUnavailable();
559 EXPECT_TRUE(sessionA
->IsGoingAway());
560 EXPECT_FALSE(delegateA
.StreamIsClosed());
562 // Set up session B: Available, with a created stream.
563 const std::string
kTestHostB("http://www.b.com");
564 HostPortPair
test_host_port_pairB(kTestHostB
, 80);
566 test_host_port_pairB
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
567 base::WeakPtr
<SpdySession
> sessionB
=
568 CreateInsecureSpdySession(http_session_
, keyB
, BoundNetLog());
569 EXPECT_TRUE(sessionB
->IsAvailable());
571 GURL
urlB(kTestHostB
);
572 base::WeakPtr
<SpdyStream
> spdy_streamB
= CreateStreamSynchronously(
573 SPDY_BIDIRECTIONAL_STREAM
, sessionB
, urlB
, MEDIUM
, BoundNetLog());
574 test::StreamDelegateDoNothing
delegateB(spdy_streamB
);
575 spdy_streamB
->SetDelegate(&delegateB
);
577 // Set up session C: Draining.
578 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
579 const std::string
kTestHostC("http://www.c.com");
580 HostPortPair
test_host_port_pairC(kTestHostC
, 80);
582 test_host_port_pairC
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
583 base::WeakPtr
<SpdySession
> sessionC
=
584 CreateInsecureSpdySession(http_session_
, keyC
, BoundNetLog());
586 sessionC
->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR
, "Error!");
587 EXPECT_TRUE(sessionC
->IsDraining());
589 spdy_session_pool_
->OnIPAddressChanged();
591 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
592 EXPECT_TRUE(sessionA
->IsGoingAway());
593 EXPECT_TRUE(sessionB
->IsDraining());
594 EXPECT_TRUE(sessionC
->IsDraining());
597 sessionA
->num_active_streams()); // Active stream is still active.
598 EXPECT_FALSE(delegateA
.StreamIsClosed());
600 EXPECT_TRUE(delegateB
.StreamIsClosed()); // Created stream was closed.
601 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateB
.WaitForClose());
603 sessionA
->CloseSessionOnError(ERR_ABORTED
, "Closing");
604 sessionB
->CloseSessionOnError(ERR_ABORTED
, "Closing");
606 EXPECT_TRUE(delegateA
.StreamIsClosed());
607 EXPECT_EQ(ERR_ABORTED
, delegateA
.WaitForClose());
609 EXPECT_TRUE(sessionA
->IsDraining());
610 EXPECT_TRUE(sessionB
->IsDraining());
611 EXPECT_TRUE(sessionC
->IsDraining());
613 // Both streams were closed with an error.
614 EXPECT_TRUE(delegateA
.StreamIsClosed());
615 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateA
.WaitForClose());
616 EXPECT_TRUE(delegateB
.StreamIsClosed());
617 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateB
.WaitForClose());
618 #endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)