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. 4 5 #include "net/spdy/spdy_session_pool.h" 6 7 #include <cstddef> 8 #include <string> 9 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" 20 21 namespace net { 22 23 namespace { 24 25 class SpdySessionPoolTest : public ::testing::Test, 26 public ::testing::WithParamInterface<NextProto> { 27 protected: 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, 33 }; 34 35 SpdySessionPoolTest() 36 : session_deps_(GetParam()), 37 spdy_session_pool_(NULL) {} 38 39 void CreateNetworkSession() { 40 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); 41 spdy_session_pool_ = http_session_->spdy_session_pool(); 42 } 43 44 void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type); 45 46 SpdySessionDependencies session_deps_; 47 scoped_refptr<HttpNetworkSession> http_session_; 48 SpdySessionPool* spdy_session_pool_; 49 }; 50 51 INSTANTIATE_TEST_CASE_P( 52 NextProto, 53 SpdySessionPoolTest, 54 testing::Values(kProtoDeprecatedSPDY2, 55 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4)); 56 57 // A delegate that opens a new session when it is closed. 58 class SessionOpeningDelegate : public SpdyStream::Delegate { 59 public: 60 SessionOpeningDelegate(SpdySessionPool* spdy_session_pool, 61 const SpdySessionKey& key) 62 : spdy_session_pool_(spdy_session_pool), 63 key_(key) {} 64 65 virtual ~SessionOpeningDelegate() {} 66 67 virtual void OnRequestHeadersSent() OVERRIDE {} 68 69 virtual SpdyResponseHeadersStatus OnResponseHeadersUpdated( 70 const SpdyHeaderBlock& response_headers) OVERRIDE { 71 return RESPONSE_HEADERS_ARE_COMPLETE; 72 } 73 74 virtual void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {} 75 76 virtual void OnDataSent() OVERRIDE {} 77 78 virtual void OnClose(int status) OVERRIDE { 79 ignore_result(CreateFakeSpdySession(spdy_session_pool_, key_)); 80 } 81 82 private: 83 SpdySessionPool* const spdy_session_pool_; 84 const SpdySessionKey key_; 85 }; 86 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; 92 93 session_deps_.host_resolver->set_synchronous_mode(true); 94 95 HostPortPair test_host_port_pair(kTestHost, kTestPort); 96 SpdySessionKey test_key = 97 SpdySessionKey( 98 test_host_port_pair, ProxyServer::Direct(), 99 PRIVACY_MODE_DISABLED); 100 101 MockConnect connect_data(SYNCHRONOUS, OK); 102 MockRead reads[] = { 103 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. 104 }; 105 106 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); 107 data.set_connect_data(connect_data); 108 session_deps_.socket_factory->AddSocketDataProvider(&data); 109 110 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); 111 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); 112 113 CreateNetworkSession(); 114 115 // Setup the first session to the first host. 116 base::WeakPtr<SpdySession> session = 117 CreateInsecureSpdySession(http_session_, test_key, BoundNetLog()); 118 119 // Flush the SpdySession::OnReadComplete() task. 120 base::MessageLoop::current()->RunUntilIdle(); 121 122 // Verify that we have sessions for everything. 123 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key)); 124 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); 132 133 // Close the current session. 134 spdy_session_pool_->CloseCurrentSessions(net::ERR_ABORTED); 135 136 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key)); 137 } 138 139 TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) { 140 MockConnect connect_data(SYNCHRONOUS, OK); 141 MockRead reads[] = { 142 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. 143 }; 144 145 session_deps_.host_resolver->set_synchronous_mode(true); 146 147 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); 148 data.set_connect_data(connect_data); 149 session_deps_.socket_factory->AddSocketDataProvider(&data); 150 151 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); 152 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); 153 154 CreateNetworkSession(); 155 156 // Set up session 1 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); 168 169 // Set up session 2 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); 182 183 // Set up session 3 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); 196 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()); 204 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()); 213 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()); 226 227 // Should close session 1 and 3, 2 should be left open 228 spdy_session_pool_->CloseCurrentIdleSessions(); 229 base::MessageLoop::current()->RunUntilIdle(); 230 231 EXPECT_TRUE(session1 == NULL); 232 EXPECT_TRUE(session2->is_active()); 233 EXPECT_TRUE(session2->IsAvailable()); 234 EXPECT_TRUE(session3 == NULL); 235 236 // Should not do anything 237 spdy_session_pool_->CloseCurrentIdleSessions(); 238 base::MessageLoop::current()->RunUntilIdle(); 239 240 EXPECT_TRUE(session2->is_active()); 241 EXPECT_TRUE(session2->IsAvailable()); 242 243 // Make 2 not active 244 session2->CloseCreatedStream(spdy_stream2, OK); 245 base::MessageLoop::current()->RunUntilIdle(); 246 247 EXPECT_EQ(NULL, spdy_stream2.get()); 248 EXPECT_FALSE(session2->is_active()); 249 EXPECT_TRUE(session2->IsAvailable()); 250 251 // This should close session 2 252 spdy_session_pool_->CloseCurrentIdleSessions(); 253 base::MessageLoop::current()->RunUntilIdle(); 254 255 EXPECT_TRUE(session2 == NULL); 256 } 257 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; 263 264 session_deps_.host_resolver->set_synchronous_mode(true); 265 266 HostPortPair test_host_port_pair(kTestHost, kTestPort); 267 SpdySessionKey test_key = 268 SpdySessionKey( 269 test_host_port_pair, ProxyServer::Direct(), 270 PRIVACY_MODE_DISABLED); 271 272 MockConnect connect_data(SYNCHRONOUS, OK); 273 MockRead reads[] = { 274 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. 275 }; 276 277 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); 278 data.set_connect_data(connect_data); 279 session_deps_.socket_factory->AddSocketDataProvider(&data); 280 281 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); 282 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); 283 284 CreateNetworkSession(); 285 286 // Setup the first session to the first host. 287 base::WeakPtr<SpdySession> session = 288 CreateInsecureSpdySession(http_session_, test_key, BoundNetLog()); 289 290 // Flush the SpdySession::OnReadComplete() task. 291 base::MessageLoop::current()->RunUntilIdle(); 292 293 // Verify that we have sessions for everything. 294 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key)); 295 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); 303 304 // Close the current session. 305 spdy_session_pool_->CloseAllSessions(); 306 307 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key)); 308 } 309 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; 320 struct TestHosts { 321 std::string url; 322 std::string name; 323 std::string iplist; 324 SpdySessionKey key; 325 AddressList addresses; 326 } test_hosts[] = { 327 { "http:://www.foo.com", 328 "www.foo.com", 329 "192.0.2.33,192.168.0.1,192.168.0.5" 330 }, 331 { "http://js.foo.com", 332 "js.foo.com", 333 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33" 334 }, 335 { "http://images.foo.com", 336 "images.foo.com", 337 "192.168.0.4,192.168.0.3" 338 }, 339 }; 340 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()); 345 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, 350 DEFAULT_PRIORITY, 351 &test_hosts[i].addresses, 352 CompletionCallback(), 353 NULL, 354 BoundNetLog()); 355 356 // Setup a SpdySessionKey 357 test_hosts[i].key = SpdySessionKey( 358 HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(), 359 PRIVACY_MODE_DISABLED); 360 } 361 362 MockConnect connect_data(SYNCHRONOUS, OK); 363 MockRead reads[] = { 364 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. 365 }; 366 367 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); 368 data.set_connect_data(connect_data); 369 session_deps_.socket_factory->AddSocketDataProvider(&data); 370 371 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); 372 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); 373 374 CreateNetworkSession(); 375 376 // Setup the first session to the first host. 377 base::WeakPtr<SpdySession> session = 378 CreateInsecureSpdySession( 379 http_session_, test_hosts[0].key, BoundNetLog()); 380 381 // Flush the SpdySession::OnReadComplete() task. 382 base::MessageLoop::current()->RunUntilIdle(); 383 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)); 386 387 // The second host overlaps with the first, and should IP pool. 388 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key)); 389 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)); 395 396 // Overlap between 2 and 3 does is not transitive to 1. 397 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key)); 398 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()); 404 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)); 409 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()); 417 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)); 423 424 // Expire the host cache 425 session_deps_.host_resolver->GetHostCache()->clear(); 426 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key)); 427 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); 436 break; 437 case SPDY_POOL_CLOSE_CURRENT_SESSIONS: 438 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED); 439 break; 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()); 453 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()); 459 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()); 467 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(); 472 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()); 478 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()); 483 484 session2->CloseSessionOnError(ERR_ABORTED, std::string()); 485 base::MessageLoop::current()->RunUntilIdle(); 486 EXPECT_TRUE(session2 == NULL); 487 break; 488 } 489 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)); 494 } 495 496 TEST_P(SpdySessionPoolTest, IPPooling) { 497 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY); 498 } 499 500 TEST_P(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) { 501 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS); 502 } 503 504 TEST_P(SpdySessionPoolTest, IPPoolingCloseIdleSessions) { 505 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS); 506 } 507 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()); 515 516 MockRead reads[] = { 517 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. 518 }; 519 scoped_ptr<SpdyFrame> req( 520 spdy_util.ConstructSpdyGet("http://www.a.com", false, 1, MEDIUM)); 521 MockWrite writes[] = {CreateMockWrite(*req, 1)}; 522 523 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); 524 data.set_connect_data(connect_data); 525 session_deps_.socket_factory->AddSocketDataProvider(&data); 526 527 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); 528 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); 529 530 CreateNetworkSession(); 531 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); 536 SpdySessionKey keyA( 537 test_host_port_pairA, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); 538 base::WeakPtr<SpdySession> sessionA = 539 CreateInsecureSpdySession(http_session_, keyA, BoundNetLog()); 540 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); 546 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()); 551 552 base::MessageLoop::current()->RunUntilIdle(); // Allow headers to write. 553 EXPECT_TRUE(delegateA.send_headers_completed()); 554 555 sessionA->MakeUnavailable(); 556 EXPECT_TRUE(sessionA->IsGoingAway()); 557 EXPECT_FALSE(delegateA.StreamIsClosed()); 558 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); 562 SpdySessionKey keyB( 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()); 567 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); 573 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); 578 SpdySessionKey keyC( 579 test_host_port_pairC, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); 580 base::WeakPtr<SpdySession> sessionC = 581 CreateInsecureSpdySession(http_session_, keyC, BoundNetLog()); 582 583 sessionC->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error!"); 584 EXPECT_TRUE(sessionC->IsDraining()); 585 586 spdy_session_pool_->OnIPAddressChanged(); 587 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()); 592 593 EXPECT_EQ(1u, 594 sessionA->num_active_streams()); // Active stream is still active. 595 EXPECT_FALSE(delegateA.StreamIsClosed()); 596 597 EXPECT_TRUE(delegateB.StreamIsClosed()); // Created stream was closed. 598 EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose()); 599 600 sessionA->CloseSessionOnError(ERR_ABORTED, "Closing"); 601 sessionB->CloseSessionOnError(ERR_ABORTED, "Closing"); 602 603 EXPECT_TRUE(delegateA.StreamIsClosed()); 604 EXPECT_EQ(ERR_ABORTED, delegateA.WaitForClose()); 605 #else 606 EXPECT_TRUE(sessionA->IsDraining()); 607 EXPECT_TRUE(sessionB->IsDraining()); 608 EXPECT_TRUE(sessionC->IsDraining()); 609 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) 616 } 617 618 } // namespace 619 620 } // namespace net 621