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(
54 testing::Values(kProtoDeprecatedSPDY2
,
55 kProtoSPDY3
, kProtoSPDY31
, kProtoSPDY4
));
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 virtual ~SessionOpeningDelegate() {}
67 virtual void OnRequestHeadersSent() OVERRIDE
{}
69 virtual SpdyResponseHeadersStatus
OnResponseHeadersUpdated(
70 const SpdyHeaderBlock
& response_headers
) OVERRIDE
{
71 return RESPONSE_HEADERS_ARE_COMPLETE
;
74 virtual void OnDataReceived(scoped_ptr
<SpdyBuffer
> buffer
) OVERRIDE
{}
76 virtual void OnDataSent() OVERRIDE
{}
78 virtual void OnClose(int status
) OVERRIDE
{
79 ignore_result(CreateFakeSpdySession(spdy_session_pool_
, key_
));
83 SpdySessionPool
* const spdy_session_pool_
;
84 const SpdySessionKey key_
;
87 // Set up a SpdyStream to create a new session when it is closed.
88 // CloseCurrentSessions should not close the newly-created session.
89 TEST_P(SpdySessionPoolTest
, CloseCurrentSessions
) {
90 const char kTestHost
[] = "www.foo.com";
91 const int kTestPort
= 80;
93 session_deps_
.host_resolver
->set_synchronous_mode(true);
95 HostPortPair
test_host_port_pair(kTestHost
, kTestPort
);
96 SpdySessionKey test_key
=
98 test_host_port_pair
, ProxyServer::Direct(),
99 PRIVACY_MODE_DISABLED
);
101 MockConnect
connect_data(SYNCHRONOUS
, OK
);
103 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
106 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
107 data
.set_connect_data(connect_data
);
108 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
110 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
111 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
113 CreateNetworkSession();
115 // Setup the first session to the first host.
116 base::WeakPtr
<SpdySession
> session
=
117 CreateInsecureSpdySession(http_session_
, test_key
, BoundNetLog());
119 // Flush the SpdySession::OnReadComplete() task.
120 base::MessageLoop::current()->RunUntilIdle();
122 // Verify that we have sessions for everything.
123 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
125 // Set the stream to create a new session when it is closed.
126 base::WeakPtr
<SpdyStream
> spdy_stream
=
127 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
128 session
, GURL("http://www.foo.com"),
129 MEDIUM
, BoundNetLog());
130 SessionOpeningDelegate
delegate(spdy_session_pool_
, test_key
);
131 spdy_stream
->SetDelegate(&delegate
);
133 // Close the current session.
134 spdy_session_pool_
->CloseCurrentSessions(net::ERR_ABORTED
);
136 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
139 TEST_P(SpdySessionPoolTest
, CloseCurrentIdleSessions
) {
140 MockConnect
connect_data(SYNCHRONOUS
, OK
);
142 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
145 session_deps_
.host_resolver
->set_synchronous_mode(true);
147 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
148 data
.set_connect_data(connect_data
);
149 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
151 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
152 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
154 CreateNetworkSession();
157 const std::string
kTestHost1("http://www.a.com");
158 HostPortPair
test_host_port_pair1(kTestHost1
, 80);
159 SpdySessionKey
key1(test_host_port_pair1
, ProxyServer::Direct(),
160 PRIVACY_MODE_DISABLED
);
161 base::WeakPtr
<SpdySession
> session1
=
162 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
163 GURL
url1(kTestHost1
);
164 base::WeakPtr
<SpdyStream
> spdy_stream1
=
165 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
166 session1
, url1
, MEDIUM
, BoundNetLog());
167 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
170 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
171 const std::string
kTestHost2("http://www.b.com");
172 HostPortPair
test_host_port_pair2(kTestHost2
, 80);
173 SpdySessionKey
key2(test_host_port_pair2
, ProxyServer::Direct(),
174 PRIVACY_MODE_DISABLED
);
175 base::WeakPtr
<SpdySession
> session2
=
176 CreateInsecureSpdySession(http_session_
, key2
, BoundNetLog());
177 GURL
url2(kTestHost2
);
178 base::WeakPtr
<SpdyStream
> spdy_stream2
=
179 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
180 session2
, url2
, MEDIUM
, BoundNetLog());
181 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
184 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
185 const std::string
kTestHost3("http://www.c.com");
186 HostPortPair
test_host_port_pair3(kTestHost3
, 80);
187 SpdySessionKey
key3(test_host_port_pair3
, ProxyServer::Direct(),
188 PRIVACY_MODE_DISABLED
);
189 base::WeakPtr
<SpdySession
> session3
=
190 CreateInsecureSpdySession(http_session_
, key3
, BoundNetLog());
191 GURL
url3(kTestHost3
);
192 base::WeakPtr
<SpdyStream
> spdy_stream3
=
193 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
194 session3
, url3
, MEDIUM
, BoundNetLog());
195 ASSERT_TRUE(spdy_stream3
.get() != NULL
);
197 // All sessions are active and not closed
198 EXPECT_TRUE(session1
->is_active());
199 EXPECT_TRUE(session1
->IsAvailable());
200 EXPECT_TRUE(session2
->is_active());
201 EXPECT_TRUE(session2
->IsAvailable());
202 EXPECT_TRUE(session3
->is_active());
203 EXPECT_TRUE(session3
->IsAvailable());
205 // Should not do anything, all are active
206 spdy_session_pool_
->CloseCurrentIdleSessions();
207 EXPECT_TRUE(session1
->is_active());
208 EXPECT_TRUE(session1
->IsAvailable());
209 EXPECT_TRUE(session2
->is_active());
210 EXPECT_TRUE(session2
->IsAvailable());
211 EXPECT_TRUE(session3
->is_active());
212 EXPECT_TRUE(session3
->IsAvailable());
214 // Make sessions 1 and 3 inactive, but keep them open.
215 // Session 2 still open and active
216 session1
->CloseCreatedStream(spdy_stream1
, OK
);
217 EXPECT_EQ(NULL
, spdy_stream1
.get());
218 session3
->CloseCreatedStream(spdy_stream3
, OK
);
219 EXPECT_EQ(NULL
, spdy_stream3
.get());
220 EXPECT_FALSE(session1
->is_active());
221 EXPECT_TRUE(session1
->IsAvailable());
222 EXPECT_TRUE(session2
->is_active());
223 EXPECT_TRUE(session2
->IsAvailable());
224 EXPECT_FALSE(session3
->is_active());
225 EXPECT_TRUE(session3
->IsAvailable());
227 // Should close session 1 and 3, 2 should be left open
228 spdy_session_pool_
->CloseCurrentIdleSessions();
229 base::MessageLoop::current()->RunUntilIdle();
231 EXPECT_TRUE(session1
== NULL
);
232 EXPECT_TRUE(session2
->is_active());
233 EXPECT_TRUE(session2
->IsAvailable());
234 EXPECT_TRUE(session3
== NULL
);
236 // Should not do anything
237 spdy_session_pool_
->CloseCurrentIdleSessions();
238 base::MessageLoop::current()->RunUntilIdle();
240 EXPECT_TRUE(session2
->is_active());
241 EXPECT_TRUE(session2
->IsAvailable());
244 session2
->CloseCreatedStream(spdy_stream2
, OK
);
245 base::MessageLoop::current()->RunUntilIdle();
247 EXPECT_EQ(NULL
, spdy_stream2
.get());
248 EXPECT_FALSE(session2
->is_active());
249 EXPECT_TRUE(session2
->IsAvailable());
251 // This should close session 2
252 spdy_session_pool_
->CloseCurrentIdleSessions();
253 base::MessageLoop::current()->RunUntilIdle();
255 EXPECT_TRUE(session2
== NULL
);
258 // Set up a SpdyStream to create a new session when it is closed.
259 // CloseAllSessions should close the newly-created session.
260 TEST_P(SpdySessionPoolTest
, CloseAllSessions
) {
261 const char kTestHost
[] = "www.foo.com";
262 const int kTestPort
= 80;
264 session_deps_
.host_resolver
->set_synchronous_mode(true);
266 HostPortPair
test_host_port_pair(kTestHost
, kTestPort
);
267 SpdySessionKey test_key
=
269 test_host_port_pair
, ProxyServer::Direct(),
270 PRIVACY_MODE_DISABLED
);
272 MockConnect
connect_data(SYNCHRONOUS
, OK
);
274 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
277 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
278 data
.set_connect_data(connect_data
);
279 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
281 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
282 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
284 CreateNetworkSession();
286 // Setup the first session to the first host.
287 base::WeakPtr
<SpdySession
> session
=
288 CreateInsecureSpdySession(http_session_
, test_key
, BoundNetLog());
290 // Flush the SpdySession::OnReadComplete() task.
291 base::MessageLoop::current()->RunUntilIdle();
293 // Verify that we have sessions for everything.
294 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
296 // Set the stream to create a new session when it is closed.
297 base::WeakPtr
<SpdyStream
> spdy_stream
=
298 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
299 session
, GURL("http://www.foo.com"),
300 MEDIUM
, BoundNetLog());
301 SessionOpeningDelegate
delegate(spdy_session_pool_
, test_key
);
302 spdy_stream
->SetDelegate(&delegate
);
304 // Close the current session.
305 spdy_session_pool_
->CloseAllSessions();
307 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_key
));
310 // This test has three variants, one for each style of closing the connection.
311 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
312 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
313 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
314 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
315 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
316 // sessions are closed with SpdySessionPool::CloseIdleSessions().
317 void SpdySessionPoolTest::RunIPPoolingTest(
318 SpdyPoolCloseSessionsType close_sessions_type
) {
319 const int kTestPort
= 80;
325 AddressList addresses
;
327 { "http:://www.foo.com",
329 "192.0.2.33,192.168.0.1,192.168.0.5"
331 { "http://js.foo.com",
333 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
335 { "http://images.foo.com",
337 "192.168.0.4,192.168.0.3"
341 session_deps_
.host_resolver
->set_synchronous_mode(true);
342 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_hosts
); i
++) {
343 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
344 test_hosts
[i
].name
, test_hosts
[i
].iplist
, std::string());
346 // This test requires that the HostResolver cache be populated. Normal
347 // code would have done this already, but we do it manually.
348 HostResolver::RequestInfo
info(HostPortPair(test_hosts
[i
].name
, kTestPort
));
349 session_deps_
.host_resolver
->Resolve(info
,
351 &test_hosts
[i
].addresses
,
352 CompletionCallback(),
356 // Setup a SpdySessionKey
357 test_hosts
[i
].key
= SpdySessionKey(
358 HostPortPair(test_hosts
[i
].name
, kTestPort
), ProxyServer::Direct(),
359 PRIVACY_MODE_DISABLED
);
362 MockConnect
connect_data(SYNCHRONOUS
, OK
);
364 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
367 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
368 data
.set_connect_data(connect_data
);
369 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
371 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
372 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
374 CreateNetworkSession();
376 // Setup the first session to the first host.
377 base::WeakPtr
<SpdySession
> session
=
378 CreateInsecureSpdySession(
379 http_session_
, test_hosts
[0].key
, BoundNetLog());
381 // Flush the SpdySession::OnReadComplete() task.
382 base::MessageLoop::current()->RunUntilIdle();
384 // The third host has no overlap with the first, so it can't pool IPs.
385 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
387 // The second host overlaps with the first, and should IP pool.
388 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
390 // Verify that the second host, through a proxy, won't share the IP.
391 SpdySessionKey
proxy_key(test_hosts
[1].key
.host_port_pair(),
392 ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
393 PRIVACY_MODE_DISABLED
);
394 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, proxy_key
));
396 // Overlap between 2 and 3 does is not transitive to 1.
397 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
399 // Create a new session to host 2.
400 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
401 base::WeakPtr
<SpdySession
> session2
=
402 CreateInsecureSpdySession(
403 http_session_
, test_hosts
[2].key
, BoundNetLog());
405 // Verify that we have sessions for everything.
406 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[0].key
));
407 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
408 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
410 // Grab the session to host 1 and verify that it is the same session
411 // we got with host 0, and that is a different from host 2's session.
412 base::WeakPtr
<SpdySession
> session1
=
413 spdy_session_pool_
->FindAvailableSession(
414 test_hosts
[1].key
, BoundNetLog());
415 EXPECT_EQ(session
.get(), session1
.get());
416 EXPECT_NE(session2
.get(), session1
.get());
418 // Remove the aliases and observe that we still have a session for host1.
419 SpdySessionPoolPeer
pool_peer(spdy_session_pool_
);
420 pool_peer
.RemoveAliases(test_hosts
[0].key
);
421 pool_peer
.RemoveAliases(test_hosts
[1].key
);
422 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
424 // Expire the host cache
425 session_deps_
.host_resolver
->GetHostCache()->clear();
426 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
428 // Cleanup the sessions.
429 switch (close_sessions_type
) {
430 case SPDY_POOL_CLOSE_SESSIONS_MANUALLY
:
431 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
432 session2
->CloseSessionOnError(ERR_ABORTED
, std::string());
433 base::MessageLoop::current()->RunUntilIdle();
434 EXPECT_TRUE(session
== NULL
);
435 EXPECT_TRUE(session2
== NULL
);
437 case SPDY_POOL_CLOSE_CURRENT_SESSIONS
:
438 spdy_session_pool_
->CloseCurrentSessions(ERR_ABORTED
);
440 case SPDY_POOL_CLOSE_IDLE_SESSIONS
:
441 GURL
url(test_hosts
[0].url
);
442 base::WeakPtr
<SpdyStream
> spdy_stream
=
443 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
444 session
, url
, MEDIUM
, BoundNetLog());
445 GURL
url1(test_hosts
[1].url
);
446 base::WeakPtr
<SpdyStream
> spdy_stream1
=
447 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
448 session1
, url1
, MEDIUM
, BoundNetLog());
449 GURL
url2(test_hosts
[2].url
);
450 base::WeakPtr
<SpdyStream
> spdy_stream2
=
451 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
452 session2
, url2
, MEDIUM
, BoundNetLog());
454 // Close streams to make spdy_session and spdy_session1 inactive.
455 session
->CloseCreatedStream(spdy_stream
, OK
);
456 EXPECT_EQ(NULL
, spdy_stream
.get());
457 session1
->CloseCreatedStream(spdy_stream1
, OK
);
458 EXPECT_EQ(NULL
, spdy_stream1
.get());
460 // Check spdy_session and spdy_session1 are not closed.
461 EXPECT_FALSE(session
->is_active());
462 EXPECT_TRUE(session
->IsAvailable());
463 EXPECT_FALSE(session1
->is_active());
464 EXPECT_TRUE(session1
->IsAvailable());
465 EXPECT_TRUE(session2
->is_active());
466 EXPECT_TRUE(session2
->IsAvailable());
468 // Test that calling CloseIdleSessions, does not cause a crash.
469 // http://crbug.com/181400
470 spdy_session_pool_
->CloseCurrentIdleSessions();
471 base::MessageLoop::current()->RunUntilIdle();
473 // Verify spdy_session and spdy_session1 are closed.
474 EXPECT_TRUE(session
== NULL
);
475 EXPECT_TRUE(session1
== NULL
);
476 EXPECT_TRUE(session2
->is_active());
477 EXPECT_TRUE(session2
->IsAvailable());
479 spdy_stream2
->Cancel();
480 EXPECT_EQ(NULL
, spdy_stream
.get());
481 EXPECT_EQ(NULL
, spdy_stream1
.get());
482 EXPECT_EQ(NULL
, spdy_stream2
.get());
484 session2
->CloseSessionOnError(ERR_ABORTED
, std::string());
485 base::MessageLoop::current()->RunUntilIdle();
486 EXPECT_TRUE(session2
== NULL
);
490 // Verify that the map is all cleaned up.
491 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[0].key
));
492 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
493 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
496 TEST_P(SpdySessionPoolTest
, IPPooling
) {
497 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY
);
500 TEST_P(SpdySessionPoolTest
, IPPoolingCloseCurrentSessions
) {
501 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS
);
504 TEST_P(SpdySessionPoolTest
, IPPoolingCloseIdleSessions
) {
505 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS
);
508 // Construct a Pool with SpdySessions in various availability states. Simulate
509 // an IP address change. Ensure sessions gracefully shut down. Regression test
510 // for crbug.com/379469.
511 TEST_P(SpdySessionPoolTest
, IPAddressChanged
) {
512 MockConnect
connect_data(SYNCHRONOUS
, OK
);
513 session_deps_
.host_resolver
->set_synchronous_mode(true);
514 SpdyTestUtil
spdy_util(GetParam());
517 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
519 scoped_ptr
<SpdyFrame
> req(
520 spdy_util
.ConstructSpdyGet("http://www.a.com", false, 1, MEDIUM
));
521 MockWrite writes
[] = {CreateMockWrite(*req
, 1)};
523 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
524 data
.set_connect_data(connect_data
);
525 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
527 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
528 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
530 CreateNetworkSession();
532 // Set up session A: Going away, but with an active stream.
533 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
534 const std::string
kTestHostA("http://www.a.com");
535 HostPortPair
test_host_port_pairA(kTestHostA
, 80);
537 test_host_port_pairA
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
538 base::WeakPtr
<SpdySession
> sessionA
=
539 CreateInsecureSpdySession(http_session_
, keyA
, BoundNetLog());
541 GURL
urlA(kTestHostA
);
542 base::WeakPtr
<SpdyStream
> spdy_streamA
= CreateStreamSynchronously(
543 SPDY_BIDIRECTIONAL_STREAM
, sessionA
, urlA
, MEDIUM
, BoundNetLog());
544 test::StreamDelegateDoNothing
delegateA(spdy_streamA
);
545 spdy_streamA
->SetDelegate(&delegateA
);
547 scoped_ptr
<SpdyHeaderBlock
> headers(
548 spdy_util
.ConstructGetHeaderBlock(urlA
.spec()));
549 spdy_streamA
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
550 EXPECT_TRUE(spdy_streamA
->HasUrlFromHeaders());
552 base::MessageLoop::current()->RunUntilIdle(); // Allow headers to write.
553 EXPECT_TRUE(delegateA
.send_headers_completed());
555 sessionA
->MakeUnavailable();
556 EXPECT_TRUE(sessionA
->IsGoingAway());
557 EXPECT_FALSE(delegateA
.StreamIsClosed());
559 // Set up session B: Available, with a created stream.
560 const std::string
kTestHostB("http://www.b.com");
561 HostPortPair
test_host_port_pairB(kTestHostB
, 80);
563 test_host_port_pairB
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
564 base::WeakPtr
<SpdySession
> sessionB
=
565 CreateInsecureSpdySession(http_session_
, keyB
, BoundNetLog());
566 EXPECT_TRUE(sessionB
->IsAvailable());
568 GURL
urlB(kTestHostB
);
569 base::WeakPtr
<SpdyStream
> spdy_streamB
= CreateStreamSynchronously(
570 SPDY_BIDIRECTIONAL_STREAM
, sessionB
, urlB
, MEDIUM
, BoundNetLog());
571 test::StreamDelegateDoNothing
delegateB(spdy_streamB
);
572 spdy_streamB
->SetDelegate(&delegateB
);
574 // Set up session C: Draining.
575 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
576 const std::string
kTestHostC("http://www.c.com");
577 HostPortPair
test_host_port_pairC(kTestHostC
, 80);
579 test_host_port_pairC
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
580 base::WeakPtr
<SpdySession
> sessionC
=
581 CreateInsecureSpdySession(http_session_
, keyC
, BoundNetLog());
583 sessionC
->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR
, "Error!");
584 EXPECT_TRUE(sessionC
->IsDraining());
586 spdy_session_pool_
->OnIPAddressChanged();
588 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
589 EXPECT_TRUE(sessionA
->IsGoingAway());
590 EXPECT_TRUE(sessionB
->IsDraining());
591 EXPECT_TRUE(sessionC
->IsDraining());
594 sessionA
->num_active_streams()); // Active stream is still active.
595 EXPECT_FALSE(delegateA
.StreamIsClosed());
597 EXPECT_TRUE(delegateB
.StreamIsClosed()); // Created stream was closed.
598 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateB
.WaitForClose());
600 sessionA
->CloseSessionOnError(ERR_ABORTED
, "Closing");
601 sessionB
->CloseSessionOnError(ERR_ABORTED
, "Closing");
603 EXPECT_TRUE(delegateA
.StreamIsClosed());
604 EXPECT_EQ(ERR_ABORTED
, delegateA
.WaitForClose());
606 EXPECT_TRUE(sessionA
->IsDraining());
607 EXPECT_TRUE(sessionB
->IsDraining());
608 EXPECT_TRUE(sessionC
->IsDraining());
610 // Both streams were closed with an error.
611 EXPECT_TRUE(delegateA
.StreamIsClosed());
612 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateA
.WaitForClose());
613 EXPECT_TRUE(delegateB
.StreamIsClosed());
614 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateB
.WaitForClose());
615 #endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)