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
,
56 // A delegate that opens a new session when it is closed.
57 class SessionOpeningDelegate
: public SpdyStream::Delegate
{
59 SessionOpeningDelegate(SpdySessionPool
* spdy_session_pool
,
60 const SpdySessionKey
& key
)
61 : spdy_session_pool_(spdy_session_pool
),
64 ~SessionOpeningDelegate() override
{}
66 void OnRequestHeadersSent() override
{}
68 SpdyResponseHeadersStatus
OnResponseHeadersUpdated(
69 const SpdyHeaderBlock
& response_headers
) override
{
70 return RESPONSE_HEADERS_ARE_COMPLETE
;
73 void OnDataReceived(scoped_ptr
<SpdyBuffer
> buffer
) override
{}
75 void OnDataSent() override
{}
77 void OnTrailers(const SpdyHeaderBlock
& trailers
) override
{}
79 void OnClose(int status
) override
{
80 ignore_result(CreateFakeSpdySession(spdy_session_pool_
, key_
));
84 SpdySessionPool
* const spdy_session_pool_
;
85 const SpdySessionKey key_
;
88 // Set up a SpdyStream to create a new session when it is closed.
89 // CloseCurrentSessions should not close the newly-created session.
90 TEST_P(SpdySessionPoolTest
, CloseCurrentSessions
) {
91 const char kTestHost
[] = "www.foo.com";
92 const int kTestPort
= 80;
94 session_deps_
.host_resolver
->set_synchronous_mode(true);
96 HostPortPair
test_host_port_pair(kTestHost
, kTestPort
);
97 SpdySessionKey test_key
=
99 test_host_port_pair
, ProxyServer::Direct(),
100 PRIVACY_MODE_DISABLED
);
102 MockConnect
connect_data(SYNCHRONOUS
, OK
);
104 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
107 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
108 data
.set_connect_data(connect_data
);
109 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
111 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
112 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
114 CreateNetworkSession();
116 // Setup the first session to the first host.
117 base::WeakPtr
<SpdySession
> session
=
118 CreateInsecureSpdySession(http_session_
, test_key
, BoundNetLog());
120 // Flush the SpdySession::OnReadComplete() task.
121 base::MessageLoop::current()->RunUntilIdle();
123 // Verify that we have sessions for everything.
124 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
126 // Set the stream to create a new session when it is closed.
127 base::WeakPtr
<SpdyStream
> spdy_stream
=
128 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
129 session
, GURL("http://www.foo.com"),
130 MEDIUM
, BoundNetLog());
131 SessionOpeningDelegate
delegate(spdy_session_pool_
, test_key
);
132 spdy_stream
->SetDelegate(&delegate
);
134 // Close the current session.
135 spdy_session_pool_
->CloseCurrentSessions(ERR_ABORTED
);
137 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
140 TEST_P(SpdySessionPoolTest
, CloseCurrentIdleSessions
) {
141 MockConnect
connect_data(SYNCHRONOUS
, OK
);
143 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
146 session_deps_
.host_resolver
->set_synchronous_mode(true);
148 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
149 data
.set_connect_data(connect_data
);
150 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
152 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
153 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
155 CreateNetworkSession();
158 const std::string
kTestHost1("http://www.a.com");
159 HostPortPair
test_host_port_pair1(kTestHost1
, 80);
160 SpdySessionKey
key1(test_host_port_pair1
, ProxyServer::Direct(),
161 PRIVACY_MODE_DISABLED
);
162 base::WeakPtr
<SpdySession
> session1
=
163 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
164 GURL
url1(kTestHost1
);
165 base::WeakPtr
<SpdyStream
> spdy_stream1
=
166 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
167 session1
, url1
, MEDIUM
, BoundNetLog());
168 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
171 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
172 const std::string
kTestHost2("http://www.b.com");
173 HostPortPair
test_host_port_pair2(kTestHost2
, 80);
174 SpdySessionKey
key2(test_host_port_pair2
, ProxyServer::Direct(),
175 PRIVACY_MODE_DISABLED
);
176 base::WeakPtr
<SpdySession
> session2
=
177 CreateInsecureSpdySession(http_session_
, key2
, BoundNetLog());
178 GURL
url2(kTestHost2
);
179 base::WeakPtr
<SpdyStream
> spdy_stream2
=
180 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
181 session2
, url2
, MEDIUM
, BoundNetLog());
182 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
185 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
186 const std::string
kTestHost3("http://www.c.com");
187 HostPortPair
test_host_port_pair3(kTestHost3
, 80);
188 SpdySessionKey
key3(test_host_port_pair3
, ProxyServer::Direct(),
189 PRIVACY_MODE_DISABLED
);
190 base::WeakPtr
<SpdySession
> session3
=
191 CreateInsecureSpdySession(http_session_
, key3
, BoundNetLog());
192 GURL
url3(kTestHost3
);
193 base::WeakPtr
<SpdyStream
> spdy_stream3
=
194 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
195 session3
, url3
, MEDIUM
, BoundNetLog());
196 ASSERT_TRUE(spdy_stream3
.get() != NULL
);
198 // All sessions are active and not closed
199 EXPECT_TRUE(session1
->is_active());
200 EXPECT_TRUE(session1
->IsAvailable());
201 EXPECT_TRUE(session2
->is_active());
202 EXPECT_TRUE(session2
->IsAvailable());
203 EXPECT_TRUE(session3
->is_active());
204 EXPECT_TRUE(session3
->IsAvailable());
206 // Should not do anything, all are active
207 spdy_session_pool_
->CloseCurrentIdleSessions();
208 EXPECT_TRUE(session1
->is_active());
209 EXPECT_TRUE(session1
->IsAvailable());
210 EXPECT_TRUE(session2
->is_active());
211 EXPECT_TRUE(session2
->IsAvailable());
212 EXPECT_TRUE(session3
->is_active());
213 EXPECT_TRUE(session3
->IsAvailable());
215 // Make sessions 1 and 3 inactive, but keep them open.
216 // Session 2 still open and active
217 session1
->CloseCreatedStream(spdy_stream1
, OK
);
218 EXPECT_EQ(NULL
, spdy_stream1
.get());
219 session3
->CloseCreatedStream(spdy_stream3
, OK
);
220 EXPECT_EQ(NULL
, spdy_stream3
.get());
221 EXPECT_FALSE(session1
->is_active());
222 EXPECT_TRUE(session1
->IsAvailable());
223 EXPECT_TRUE(session2
->is_active());
224 EXPECT_TRUE(session2
->IsAvailable());
225 EXPECT_FALSE(session3
->is_active());
226 EXPECT_TRUE(session3
->IsAvailable());
228 // Should close session 1 and 3, 2 should be left open
229 spdy_session_pool_
->CloseCurrentIdleSessions();
230 base::MessageLoop::current()->RunUntilIdle();
232 EXPECT_TRUE(session1
== NULL
);
233 EXPECT_TRUE(session2
->is_active());
234 EXPECT_TRUE(session2
->IsAvailable());
235 EXPECT_TRUE(session3
== NULL
);
237 // Should not do anything
238 spdy_session_pool_
->CloseCurrentIdleSessions();
239 base::MessageLoop::current()->RunUntilIdle();
241 EXPECT_TRUE(session2
->is_active());
242 EXPECT_TRUE(session2
->IsAvailable());
245 session2
->CloseCreatedStream(spdy_stream2
, OK
);
246 base::MessageLoop::current()->RunUntilIdle();
248 EXPECT_EQ(NULL
, spdy_stream2
.get());
249 EXPECT_FALSE(session2
->is_active());
250 EXPECT_TRUE(session2
->IsAvailable());
252 // This should close session 2
253 spdy_session_pool_
->CloseCurrentIdleSessions();
254 base::MessageLoop::current()->RunUntilIdle();
256 EXPECT_TRUE(session2
== NULL
);
259 // Set up a SpdyStream to create a new session when it is closed.
260 // CloseAllSessions should close the newly-created session.
261 TEST_P(SpdySessionPoolTest
, CloseAllSessions
) {
262 const char kTestHost
[] = "www.foo.com";
263 const int kTestPort
= 80;
265 session_deps_
.host_resolver
->set_synchronous_mode(true);
267 HostPortPair
test_host_port_pair(kTestHost
, kTestPort
);
268 SpdySessionKey test_key
=
270 test_host_port_pair
, ProxyServer::Direct(),
271 PRIVACY_MODE_DISABLED
);
273 MockConnect
connect_data(SYNCHRONOUS
, OK
);
275 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
278 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
279 data
.set_connect_data(connect_data
);
280 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
282 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
283 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
285 CreateNetworkSession();
287 // Setup the first session to the first host.
288 base::WeakPtr
<SpdySession
> session
=
289 CreateInsecureSpdySession(http_session_
, test_key
, BoundNetLog());
291 // Flush the SpdySession::OnReadComplete() task.
292 base::MessageLoop::current()->RunUntilIdle();
294 // Verify that we have sessions for everything.
295 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_key
));
297 // Set the stream to create a new session when it is closed.
298 base::WeakPtr
<SpdyStream
> spdy_stream
=
299 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
300 session
, GURL("http://www.foo.com"),
301 MEDIUM
, BoundNetLog());
302 SessionOpeningDelegate
delegate(spdy_session_pool_
, test_key
);
303 spdy_stream
->SetDelegate(&delegate
);
305 // Close the current session.
306 spdy_session_pool_
->CloseAllSessions();
308 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_key
));
311 // This test has three variants, one for each style of closing the connection.
312 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
313 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
314 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
315 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
316 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
317 // sessions are closed with SpdySessionPool::CloseIdleSessions().
318 void SpdySessionPoolTest::RunIPPoolingTest(
319 SpdyPoolCloseSessionsType close_sessions_type
) {
320 const int kTestPort
= 80;
326 AddressList addresses
;
328 { "http:://www.foo.com",
330 "192.0.2.33,192.168.0.1,192.168.0.5"
332 { "http://js.foo.com",
334 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
336 { "http://images.foo.com",
338 "192.168.0.4,192.168.0.3"
342 session_deps_
.host_resolver
->set_synchronous_mode(true);
343 for (size_t i
= 0; i
< arraysize(test_hosts
); i
++) {
344 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
345 test_hosts
[i
].name
, test_hosts
[i
].iplist
, std::string());
347 // This test requires that the HostResolver cache be populated. Normal
348 // code would have done this already, but we do it manually.
349 HostResolver::RequestInfo
info(HostPortPair(test_hosts
[i
].name
, kTestPort
));
350 session_deps_
.host_resolver
->Resolve(info
,
352 &test_hosts
[i
].addresses
,
353 CompletionCallback(),
357 // Setup a SpdySessionKey
358 test_hosts
[i
].key
= SpdySessionKey(
359 HostPortPair(test_hosts
[i
].name
, kTestPort
), ProxyServer::Direct(),
360 PRIVACY_MODE_DISABLED
);
363 MockConnect
connect_data(SYNCHRONOUS
, OK
);
365 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
368 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
369 data
.set_connect_data(connect_data
);
370 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
372 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
373 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
375 CreateNetworkSession();
377 // Setup the first session to the first host.
378 base::WeakPtr
<SpdySession
> session
=
379 CreateInsecureSpdySession(
380 http_session_
, test_hosts
[0].key
, BoundNetLog());
382 // Flush the SpdySession::OnReadComplete() task.
383 base::MessageLoop::current()->RunUntilIdle();
385 // The third host has no overlap with the first, so it can't pool IPs.
386 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
388 // The second host overlaps with the first, and should IP pool.
389 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
391 // Verify that the second host, through a proxy, won't share the IP.
392 SpdySessionKey
proxy_key(test_hosts
[1].key
.host_port_pair(),
393 ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
394 PRIVACY_MODE_DISABLED
);
395 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, proxy_key
));
397 // Overlap between 2 and 3 does is not transitive to 1.
398 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
400 // Create a new session to host 2.
401 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
402 base::WeakPtr
<SpdySession
> session2
=
403 CreateInsecureSpdySession(
404 http_session_
, test_hosts
[2].key
, BoundNetLog());
406 // Verify that we have sessions for everything.
407 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[0].key
));
408 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
409 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
411 // Grab the session to host 1 and verify that it is the same session
412 // we got with host 0, and that is a different from host 2's session.
413 base::WeakPtr
<SpdySession
> session1
=
414 spdy_session_pool_
->FindAvailableSession(
415 test_hosts
[1].key
, BoundNetLog());
416 EXPECT_EQ(session
.get(), session1
.get());
417 EXPECT_NE(session2
.get(), session1
.get());
419 // Remove the aliases and observe that we still have a session for host1.
420 SpdySessionPoolPeer
pool_peer(spdy_session_pool_
);
421 pool_peer
.RemoveAliases(test_hosts
[0].key
);
422 pool_peer
.RemoveAliases(test_hosts
[1].key
);
423 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
425 // Expire the host cache
426 session_deps_
.host_resolver
->GetHostCache()->clear();
427 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
429 // Cleanup the sessions.
430 switch (close_sessions_type
) {
431 case SPDY_POOL_CLOSE_SESSIONS_MANUALLY
:
432 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
433 session2
->CloseSessionOnError(ERR_ABORTED
, std::string());
434 base::MessageLoop::current()->RunUntilIdle();
435 EXPECT_TRUE(session
== NULL
);
436 EXPECT_TRUE(session2
== NULL
);
438 case SPDY_POOL_CLOSE_CURRENT_SESSIONS
:
439 spdy_session_pool_
->CloseCurrentSessions(ERR_ABORTED
);
441 case SPDY_POOL_CLOSE_IDLE_SESSIONS
:
442 GURL
url(test_hosts
[0].url
);
443 base::WeakPtr
<SpdyStream
> spdy_stream
=
444 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
445 session
, url
, MEDIUM
, BoundNetLog());
446 GURL
url1(test_hosts
[1].url
);
447 base::WeakPtr
<SpdyStream
> spdy_stream1
=
448 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
449 session1
, url1
, MEDIUM
, BoundNetLog());
450 GURL
url2(test_hosts
[2].url
);
451 base::WeakPtr
<SpdyStream
> spdy_stream2
=
452 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
453 session2
, url2
, MEDIUM
, BoundNetLog());
455 // Close streams to make spdy_session and spdy_session1 inactive.
456 session
->CloseCreatedStream(spdy_stream
, OK
);
457 EXPECT_EQ(NULL
, spdy_stream
.get());
458 session1
->CloseCreatedStream(spdy_stream1
, OK
);
459 EXPECT_EQ(NULL
, spdy_stream1
.get());
461 // Check spdy_session and spdy_session1 are not closed.
462 EXPECT_FALSE(session
->is_active());
463 EXPECT_TRUE(session
->IsAvailable());
464 EXPECT_FALSE(session1
->is_active());
465 EXPECT_TRUE(session1
->IsAvailable());
466 EXPECT_TRUE(session2
->is_active());
467 EXPECT_TRUE(session2
->IsAvailable());
469 // Test that calling CloseIdleSessions, does not cause a crash.
470 // http://crbug.com/181400
471 spdy_session_pool_
->CloseCurrentIdleSessions();
472 base::MessageLoop::current()->RunUntilIdle();
474 // Verify spdy_session and spdy_session1 are closed.
475 EXPECT_TRUE(session
== NULL
);
476 EXPECT_TRUE(session1
== NULL
);
477 EXPECT_TRUE(session2
->is_active());
478 EXPECT_TRUE(session2
->IsAvailable());
480 spdy_stream2
->Cancel();
481 EXPECT_EQ(NULL
, spdy_stream
.get());
482 EXPECT_EQ(NULL
, spdy_stream1
.get());
483 EXPECT_EQ(NULL
, spdy_stream2
.get());
485 session2
->CloseSessionOnError(ERR_ABORTED
, std::string());
486 base::MessageLoop::current()->RunUntilIdle();
487 EXPECT_TRUE(session2
== NULL
);
491 // Verify that the map is all cleaned up.
492 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[0].key
));
493 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[1].key
));
494 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, test_hosts
[2].key
));
497 TEST_P(SpdySessionPoolTest
, IPPooling
) {
498 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY
);
501 TEST_P(SpdySessionPoolTest
, IPPoolingCloseCurrentSessions
) {
502 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS
);
505 TEST_P(SpdySessionPoolTest
, IPPoolingCloseIdleSessions
) {
506 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS
);
509 // Construct a Pool with SpdySessions in various availability states. Simulate
510 // an IP address change. Ensure sessions gracefully shut down. Regression test
511 // for crbug.com/379469.
512 TEST_P(SpdySessionPoolTest
, IPAddressChanged
) {
513 MockConnect
connect_data(SYNCHRONOUS
, OK
);
514 session_deps_
.host_resolver
->set_synchronous_mode(true);
515 SpdyTestUtil
spdy_util(GetParam());
518 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
520 scoped_ptr
<SpdyFrame
> req(
521 spdy_util
.ConstructSpdyGet("http://www.a.com", false, 1, MEDIUM
));
522 MockWrite writes
[] = {CreateMockWrite(*req
, 1)};
524 StaticSocketDataProvider
data(reads
, arraysize(reads
), writes
,
526 data
.set_connect_data(connect_data
);
527 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
529 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
530 session_deps_
.socket_factory
->AddSSLSocketDataProvider(&ssl
);
532 CreateNetworkSession();
534 // Set up session A: Going away, but with an active stream.
535 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
536 const std::string
kTestHostA("http://www.a.com");
537 HostPortPair
test_host_port_pairA(kTestHostA
, 80);
539 test_host_port_pairA
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
540 base::WeakPtr
<SpdySession
> sessionA
=
541 CreateInsecureSpdySession(http_session_
, keyA
, BoundNetLog());
543 GURL
urlA(kTestHostA
);
544 base::WeakPtr
<SpdyStream
> spdy_streamA
= CreateStreamSynchronously(
545 SPDY_BIDIRECTIONAL_STREAM
, sessionA
, urlA
, MEDIUM
, BoundNetLog());
546 test::StreamDelegateDoNothing
delegateA(spdy_streamA
);
547 spdy_streamA
->SetDelegate(&delegateA
);
549 scoped_ptr
<SpdyHeaderBlock
> headers(
550 spdy_util
.ConstructGetHeaderBlock(urlA
.spec()));
551 spdy_streamA
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
552 EXPECT_TRUE(spdy_streamA
->HasUrlFromHeaders());
554 base::MessageLoop::current()->RunUntilIdle(); // Allow headers to write.
555 EXPECT_TRUE(delegateA
.send_headers_completed());
557 sessionA
->MakeUnavailable();
558 EXPECT_TRUE(sessionA
->IsGoingAway());
559 EXPECT_FALSE(delegateA
.StreamIsClosed());
561 // Set up session B: Available, with a created stream.
562 const std::string
kTestHostB("http://www.b.com");
563 HostPortPair
test_host_port_pairB(kTestHostB
, 80);
565 test_host_port_pairB
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
566 base::WeakPtr
<SpdySession
> sessionB
=
567 CreateInsecureSpdySession(http_session_
, keyB
, BoundNetLog());
568 EXPECT_TRUE(sessionB
->IsAvailable());
570 GURL
urlB(kTestHostB
);
571 base::WeakPtr
<SpdyStream
> spdy_streamB
= CreateStreamSynchronously(
572 SPDY_BIDIRECTIONAL_STREAM
, sessionB
, urlB
, MEDIUM
, BoundNetLog());
573 test::StreamDelegateDoNothing
delegateB(spdy_streamB
);
574 spdy_streamB
->SetDelegate(&delegateB
);
576 // Set up session C: Draining.
577 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
578 const std::string
kTestHostC("http://www.c.com");
579 HostPortPair
test_host_port_pairC(kTestHostC
, 80);
581 test_host_port_pairC
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
582 base::WeakPtr
<SpdySession
> sessionC
=
583 CreateInsecureSpdySession(http_session_
, keyC
, BoundNetLog());
585 sessionC
->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR
, "Error!");
586 EXPECT_TRUE(sessionC
->IsDraining());
588 spdy_session_pool_
->OnIPAddressChanged();
590 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
591 EXPECT_TRUE(sessionA
->IsGoingAway());
592 EXPECT_TRUE(sessionB
->IsDraining());
593 EXPECT_TRUE(sessionC
->IsDraining());
596 sessionA
->num_active_streams()); // Active stream is still active.
597 EXPECT_FALSE(delegateA
.StreamIsClosed());
599 EXPECT_TRUE(delegateB
.StreamIsClosed()); // Created stream was closed.
600 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateB
.WaitForClose());
602 sessionA
->CloseSessionOnError(ERR_ABORTED
, "Closing");
603 sessionB
->CloseSessionOnError(ERR_ABORTED
, "Closing");
605 EXPECT_TRUE(delegateA
.StreamIsClosed());
606 EXPECT_EQ(ERR_ABORTED
, delegateA
.WaitForClose());
608 EXPECT_TRUE(sessionA
->IsDraining());
609 EXPECT_TRUE(sessionB
->IsDraining());
610 EXPECT_TRUE(sessionC
->IsDraining());
612 // Both streams were closed with an error.
613 EXPECT_TRUE(delegateA
.StreamIsClosed());
614 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateA
.WaitForClose());
615 EXPECT_TRUE(delegateB
.StreamIsClosed());
616 EXPECT_EQ(ERR_NETWORK_CHANGED
, delegateB
.WaitForClose());
617 #endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)