1 // Copyright (c) 2011 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 "net/spdy/spdy_io_buffer.h" 8 #include "net/spdy/spdy_session_pool.h" 9 #include "net/spdy/spdy_stream.h" 10 #include "net/spdy/spdy_test_util.h" 11 #include "testing/platform_test.h" 12 13 namespace net { 14 15 // TODO(cbentzel): Expose compression setter/getter in public SpdySession 16 // interface rather than going through all these contortions. 17 class SpdySessionTest : public PlatformTest { 18 public: 19 static void TurnOffCompression() { 20 spdy::SpdyFramer::set_enable_compression_default(false); 21 } 22 protected: 23 virtual void TearDown() { 24 // Wanted to be 100% sure PING is disabled. 25 SpdySession::set_enable_ping_based_connection_checking(false); 26 } 27 }; 28 29 class TestSpdyStreamDelegate : public net::SpdyStream::Delegate { 30 public: 31 explicit TestSpdyStreamDelegate(OldCompletionCallback* callback) 32 : callback_(callback) {} 33 virtual ~TestSpdyStreamDelegate() {} 34 35 virtual bool OnSendHeadersComplete(int status) { return true; } 36 37 virtual int OnSendBody() { 38 return ERR_UNEXPECTED; 39 } 40 41 virtual int OnSendBodyComplete(int /*status*/, bool* /*eof*/) { 42 return ERR_UNEXPECTED; 43 } 44 45 virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response, 46 base::Time response_time, 47 int status) { 48 return status; 49 } 50 51 virtual void OnDataReceived(const char* buffer, int bytes) { 52 } 53 54 virtual void OnDataSent(int length) { 55 } 56 57 virtual void OnClose(int status) { 58 OldCompletionCallback* callback = callback_; 59 callback_ = NULL; 60 callback->Run(OK); 61 } 62 63 virtual void set_chunk_callback(net::ChunkCallback *) {} 64 65 private: 66 OldCompletionCallback* callback_; 67 }; 68 69 70 // Test the SpdyIOBuffer class. 71 TEST_F(SpdySessionTest, SpdyIOBuffer) { 72 std::priority_queue<SpdyIOBuffer> queue_; 73 const size_t kQueueSize = 100; 74 75 // Insert 100 items; pri 100 to 1. 76 for (size_t index = 0; index < kQueueSize; ++index) { 77 SpdyIOBuffer buffer(new IOBuffer(), 0, kQueueSize - index, NULL); 78 queue_.push(buffer); 79 } 80 81 // Insert several priority 0 items last. 82 const size_t kNumDuplicates = 12; 83 IOBufferWithSize* buffers[kNumDuplicates]; 84 for (size_t index = 0; index < kNumDuplicates; ++index) { 85 buffers[index] = new IOBufferWithSize(index+1); 86 queue_.push(SpdyIOBuffer(buffers[index], buffers[index]->size(), 0, NULL)); 87 } 88 89 EXPECT_EQ(kQueueSize + kNumDuplicates, queue_.size()); 90 91 // Verify the P0 items come out in FIFO order. 92 for (size_t index = 0; index < kNumDuplicates; ++index) { 93 SpdyIOBuffer buffer = queue_.top(); 94 EXPECT_EQ(0, buffer.priority()); 95 EXPECT_EQ(index + 1, buffer.size()); 96 queue_.pop(); 97 } 98 99 int priority = 1; 100 while (queue_.size()) { 101 SpdyIOBuffer buffer = queue_.top(); 102 EXPECT_EQ(priority++, buffer.priority()); 103 queue_.pop(); 104 } 105 } 106 107 TEST_F(SpdySessionTest, GoAway) { 108 SpdySessionDependencies session_deps; 109 session_deps.host_resolver->set_synchronous_mode(true); 110 111 MockConnect connect_data(false, OK); 112 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyGoAway()); 113 MockRead reads[] = { 114 CreateMockRead(*goaway), 115 MockRead(false, 0, 0) // EOF 116 }; 117 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); 118 data.set_connect_data(connect_data); 119 session_deps.socket_factory->AddSocketDataProvider(&data); 120 121 SSLSocketDataProvider ssl(false, OK); 122 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); 123 124 scoped_refptr<HttpNetworkSession> http_session( 125 SpdySessionDependencies::SpdyCreateSession(&session_deps)); 126 127 const std::string kTestHost("www.foo.com"); 128 const int kTestPort = 80; 129 HostPortPair test_host_port_pair(kTestHost, kTestPort); 130 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); 131 132 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); 133 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); 134 scoped_refptr<SpdySession> session = 135 spdy_session_pool->Get(pair, BoundNetLog()); 136 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); 137 138 scoped_refptr<TransportSocketParams> transport_params( 139 new TransportSocketParams(test_host_port_pair, 140 MEDIUM, 141 GURL(), 142 false, 143 false)); 144 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); 145 EXPECT_EQ(OK, 146 connection->Init(test_host_port_pair.ToString(), 147 transport_params, MEDIUM, 148 NULL, http_session->transport_socket_pool(), 149 BoundNetLog())); 150 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); 151 152 // Flush the SpdySession::OnReadComplete() task. 153 MessageLoop::current()->RunAllPending(); 154 155 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); 156 157 scoped_refptr<SpdySession> session2 = 158 spdy_session_pool->Get(pair, BoundNetLog()); 159 160 // Delete the first session. 161 session = NULL; 162 163 // Delete the second session. 164 spdy_session_pool->Remove(session2); 165 session2 = NULL; 166 } 167 168 TEST_F(SpdySessionTest, Ping) { 169 SpdySessionDependencies session_deps; 170 session_deps.host_resolver->set_synchronous_mode(true); 171 172 MockConnect connect_data(false, OK); 173 scoped_ptr<spdy::SpdyFrame> read_ping(ConstructSpdyPing()); 174 MockRead reads[] = { 175 CreateMockRead(*read_ping), 176 CreateMockRead(*read_ping), 177 MockRead(false, 0, 0) // EOF 178 }; 179 scoped_ptr<spdy::SpdyFrame> write_ping(ConstructSpdyPing()); 180 MockRead writes[] = { 181 CreateMockRead(*write_ping), 182 CreateMockRead(*write_ping), 183 }; 184 StaticSocketDataProvider data( 185 reads, arraysize(reads), writes, arraysize(writes)); 186 data.set_connect_data(connect_data); 187 session_deps.socket_factory->AddSocketDataProvider(&data); 188 189 SSLSocketDataProvider ssl(false, OK); 190 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); 191 192 scoped_refptr<HttpNetworkSession> http_session( 193 SpdySessionDependencies::SpdyCreateSession(&session_deps)); 194 195 static const char kStreamUrl[] = "http://www.google.com/"; 196 GURL url(kStreamUrl); 197 198 const std::string kTestHost("www.google.com"); 199 const int kTestPort = 80; 200 HostPortPair test_host_port_pair(kTestHost, kTestPort); 201 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); 202 203 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); 204 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); 205 scoped_refptr<SpdySession> session = 206 spdy_session_pool->Get(pair, BoundNetLog()); 207 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); 208 209 210 scoped_refptr<TransportSocketParams> transport_params( 211 new TransportSocketParams(test_host_port_pair, 212 MEDIUM, 213 GURL(), 214 false, 215 false)); 216 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); 217 EXPECT_EQ(OK, 218 connection->Init(test_host_port_pair.ToString(), 219 transport_params, 220 MEDIUM, 221 NULL, 222 http_session->transport_socket_pool(), 223 BoundNetLog())); 224 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); 225 226 scoped_refptr<SpdyStream> spdy_stream1; 227 TestOldCompletionCallback callback1; 228 EXPECT_EQ(OK, session->CreateStream(url, 229 MEDIUM, 230 &spdy_stream1, 231 BoundNetLog(), 232 &callback1)); 233 scoped_ptr<TestSpdyStreamDelegate> delegate( 234 new TestSpdyStreamDelegate(&callback1)); 235 spdy_stream1->SetDelegate(delegate.get()); 236 237 base::TimeTicks before_ping_time = base::TimeTicks::Now(); 238 239 // Enable sending of PING. 240 SpdySession::set_enable_ping_based_connection_checking(true); 241 SpdySession::set_connection_at_risk_of_loss_ms(0); 242 SpdySession::set_trailing_ping_delay_time_ms(0); 243 SpdySession::set_hung_interval_ms(50); 244 245 session->SendPrefacePingIfNoneInFlight(); 246 247 EXPECT_EQ(OK, callback1.WaitForResult()); 248 249 EXPECT_EQ(0, session->pings_in_flight()); 250 EXPECT_GT(session->next_ping_id(), static_cast<uint32>(1)); 251 EXPECT_FALSE(session->trailing_ping_pending()); 252 // TODO(rtenneti): check_ping_status_pending works in debug mode with 253 // breakpoints, but fails if run in stand alone mode. 254 // EXPECT_FALSE(session->check_ping_status_pending()); 255 EXPECT_GE(session->received_data_time(), before_ping_time); 256 257 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); 258 259 // Delete the first session. 260 session = NULL; 261 } 262 263 class StreamReleaserCallback : public CallbackRunner<Tuple1<int> > { 264 public: 265 StreamReleaserCallback(SpdySession* session, 266 SpdyStream* first_stream) 267 : session_(session), first_stream_(first_stream) {} 268 ~StreamReleaserCallback() {} 269 270 int WaitForResult() { return callback_.WaitForResult(); } 271 272 virtual void RunWithParams(const Tuple1<int>& params) { 273 session_->CloseSessionOnError(ERR_FAILED, false); 274 session_ = NULL; 275 first_stream_->Cancel(); 276 first_stream_ = NULL; 277 stream_->Cancel(); 278 stream_ = NULL; 279 callback_.RunWithParams(params); 280 } 281 282 scoped_refptr<SpdyStream>* stream() { return &stream_; } 283 284 private: 285 scoped_refptr<SpdySession> session_; 286 scoped_refptr<SpdyStream> first_stream_; 287 scoped_refptr<SpdyStream> stream_; 288 TestCompletionCallback callback_; 289 }; 290 291 // Start with max concurrent streams set to 1. Request two streams. Receive a 292 // settings frame setting max concurrent streams to 2. Have the callback 293 // release the stream, which releases its reference (the last) to the session. 294 // Make sure nothing blows up. 295 // http://crbug.com/57331 296 TEST_F(SpdySessionTest, OnSettings) { 297 SpdySessionDependencies session_deps; 298 session_deps.host_resolver->set_synchronous_mode(true); 299 300 spdy::SpdySettings new_settings; 301 spdy::SettingsFlagsAndId id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); 302 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); 303 const size_t max_concurrent_streams = 2; 304 new_settings.push_back(spdy::SpdySetting(id, max_concurrent_streams)); 305 306 // Set up the socket so we read a SETTINGS frame that raises max concurrent 307 // streams to 2. 308 MockConnect connect_data(false, OK); 309 scoped_ptr<spdy::SpdyFrame> settings_frame( 310 ConstructSpdySettings(new_settings)); 311 MockRead reads[] = { 312 CreateMockRead(*settings_frame), 313 MockRead(false, 0, 0) // EOF 314 }; 315 316 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); 317 data.set_connect_data(connect_data); 318 session_deps.socket_factory->AddSocketDataProvider(&data); 319 320 SSLSocketDataProvider ssl(false, OK); 321 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); 322 323 scoped_refptr<HttpNetworkSession> http_session( 324 SpdySessionDependencies::SpdyCreateSession(&session_deps)); 325 326 const std::string kTestHost("www.foo.com"); 327 const int kTestPort = 80; 328 HostPortPair test_host_port_pair(kTestHost, kTestPort); 329 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); 330 331 // Initialize the SpdySettingsStorage with 1 max concurrent streams. 332 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); 333 spdy::SpdySettings old_settings; 334 id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); 335 old_settings.push_back(spdy::SpdySetting(id, 1)); 336 spdy_session_pool->mutable_spdy_settings()->Set( 337 test_host_port_pair, old_settings); 338 339 // Create a session. 340 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); 341 scoped_refptr<SpdySession> session = 342 spdy_session_pool->Get(pair, BoundNetLog()); 343 ASSERT_TRUE(spdy_session_pool->HasSession(pair)); 344 345 scoped_refptr<TransportSocketParams> transport_params( 346 new TransportSocketParams(test_host_port_pair, 347 MEDIUM, 348 GURL(), 349 false, 350 false)); 351 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); 352 EXPECT_EQ(OK, 353 connection->Init(test_host_port_pair.ToString(), 354 transport_params, MEDIUM, 355 NULL, http_session->transport_socket_pool(), 356 BoundNetLog())); 357 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); 358 359 // Create 2 streams. First will succeed. Second will be pending. 360 scoped_refptr<SpdyStream> spdy_stream1; 361 TestCompletionCallback callback1; 362 GURL url("http://www.google.com"); 363 EXPECT_EQ(OK, 364 session->CreateStream(url, 365 MEDIUM, /* priority, not important */ 366 &spdy_stream1, 367 BoundNetLog(), 368 &callback1)); 369 370 StreamReleaserCallback stream_releaser(session, spdy_stream1); 371 372 ASSERT_EQ(ERR_IO_PENDING, 373 session->CreateStream(url, 374 MEDIUM, /* priority, not important */ 375 stream_releaser.stream(), 376 BoundNetLog(), 377 &stream_releaser)); 378 379 // Make sure |stream_releaser| holds the last refs. 380 session = NULL; 381 spdy_stream1 = NULL; 382 383 EXPECT_EQ(OK, stream_releaser.WaitForResult()); 384 } 385 386 // Start with max concurrent streams set to 1. Request two streams. When the 387 // first completes, have the callback close itself, which should trigger the 388 // second stream creation. Then cancel that one immediately. Don't crash. 389 // http://crbug.com/63532 390 TEST_F(SpdySessionTest, CancelPendingCreateStream) { 391 SpdySessionDependencies session_deps; 392 session_deps.host_resolver->set_synchronous_mode(true); 393 394 MockRead reads[] = { 395 MockRead(false, ERR_IO_PENDING) // Stall forever. 396 }; 397 398 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); 399 MockConnect connect_data(false, OK); 400 401 data.set_connect_data(connect_data); 402 session_deps.socket_factory->AddSocketDataProvider(&data); 403 404 SSLSocketDataProvider ssl(false, OK); 405 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); 406 407 scoped_refptr<HttpNetworkSession> http_session( 408 SpdySessionDependencies::SpdyCreateSession(&session_deps)); 409 410 const std::string kTestHost("www.foo.com"); 411 const int kTestPort = 80; 412 HostPortPair test_host_port_pair(kTestHost, kTestPort); 413 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); 414 415 // Initialize the SpdySettingsStorage with 1 max concurrent streams. 416 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); 417 spdy::SpdySettings settings; 418 spdy::SettingsFlagsAndId id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); 419 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); 420 id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); 421 settings.push_back(spdy::SpdySetting(id, 1)); 422 spdy_session_pool->mutable_spdy_settings()->Set( 423 test_host_port_pair, settings); 424 425 // Create a session. 426 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); 427 scoped_refptr<SpdySession> session = 428 spdy_session_pool->Get(pair, BoundNetLog()); 429 ASSERT_TRUE(spdy_session_pool->HasSession(pair)); 430 431 scoped_refptr<TransportSocketParams> transport_params( 432 new TransportSocketParams(test_host_port_pair, 433 MEDIUM, 434 GURL(), 435 false, 436 false)); 437 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); 438 EXPECT_EQ(OK, 439 connection->Init(test_host_port_pair.ToString(), 440 transport_params, MEDIUM, 441 NULL, http_session->transport_socket_pool(), 442 BoundNetLog())); 443 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); 444 445 // Use scoped_ptr to let us invalidate the memory when we want to, to trigger 446 // a valgrind error if the callback is invoked when it's not supposed to be. 447 scoped_ptr<TestCompletionCallback> callback(new TestCompletionCallback); 448 449 // Create 2 streams. First will succeed. Second will be pending. 450 scoped_refptr<SpdyStream> spdy_stream1; 451 GURL url("http://www.google.com"); 452 ASSERT_EQ(OK, 453 session->CreateStream(url, 454 MEDIUM, /* priority, not important */ 455 &spdy_stream1, 456 BoundNetLog(), 457 callback.get())); 458 459 scoped_refptr<SpdyStream> spdy_stream2; 460 ASSERT_EQ(ERR_IO_PENDING, 461 session->CreateStream(url, 462 MEDIUM, /* priority, not important */ 463 &spdy_stream2, 464 BoundNetLog(), 465 callback.get())); 466 467 // Release the first one, this will allow the second to be created. 468 spdy_stream1->Cancel(); 469 spdy_stream1 = NULL; 470 471 session->CancelPendingCreateStreams(&spdy_stream2); 472 callback.reset(); 473 474 // Should not crash when running the pending callback. 475 MessageLoop::current()->RunAllPending(); 476 } 477 478 TEST_F(SpdySessionTest, SendSettingsOnNewSession) { 479 SpdySessionDependencies session_deps; 480 session_deps.host_resolver->set_synchronous_mode(true); 481 482 MockRead reads[] = { 483 MockRead(false, ERR_IO_PENDING) // Stall forever. 484 }; 485 486 // Create the bogus setting that we want to verify is sent out. 487 // Note that it will be marked as SETTINGS_FLAG_PERSISTED when sent out. But 488 // to set it into the SpdySettingsStorage, we need to mark as 489 // SETTINGS_FLAG_PLEASE_PERSIST. 490 spdy::SpdySettings settings; 491 const uint32 kBogusSettingId = 0xABAB; 492 const uint32 kBogusSettingValue = 0xCDCD; 493 spdy::SettingsFlagsAndId id(kBogusSettingId); 494 id.set_id(kBogusSettingId); 495 id.set_flags(spdy::SETTINGS_FLAG_PERSISTED); 496 settings.push_back(spdy::SpdySetting(id, kBogusSettingValue)); 497 MockConnect connect_data(false, OK); 498 scoped_ptr<spdy::SpdyFrame> settings_frame( 499 ConstructSpdySettings(settings)); 500 MockWrite writes[] = { 501 CreateMockWrite(*settings_frame), 502 }; 503 504 StaticSocketDataProvider data( 505 reads, arraysize(reads), writes, arraysize(writes)); 506 data.set_connect_data(connect_data); 507 session_deps.socket_factory->AddSocketDataProvider(&data); 508 509 SSLSocketDataProvider ssl(false, OK); 510 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); 511 512 scoped_refptr<HttpNetworkSession> http_session( 513 SpdySessionDependencies::SpdyCreateSession(&session_deps)); 514 515 const std::string kTestHost("www.foo.com"); 516 const int kTestPort = 80; 517 HostPortPair test_host_port_pair(kTestHost, kTestPort); 518 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); 519 520 id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); 521 settings.clear(); 522 settings.push_back(spdy::SpdySetting(id, kBogusSettingValue)); 523 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); 524 spdy_session_pool->mutable_spdy_settings()->Set( 525 test_host_port_pair, settings); 526 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); 527 scoped_refptr<SpdySession> session = 528 spdy_session_pool->Get(pair, BoundNetLog()); 529 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); 530 531 scoped_refptr<TransportSocketParams> transport_params( 532 new TransportSocketParams(test_host_port_pair, 533 MEDIUM, 534 GURL(), 535 false, 536 false)); 537 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); 538 EXPECT_EQ(OK, 539 connection->Init(test_host_port_pair.ToString(), 540 transport_params, MEDIUM, 541 NULL, http_session->transport_socket_pool(), 542 BoundNetLog())); 543 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); 544 MessageLoop::current()->RunAllPending(); 545 EXPECT_TRUE(data.at_write_eof()); 546 } 547 548 // This test has two variants, one for each style of closing the connection. 549 // If |clean_via_close_current_sessions| is false, the sessions are closed 550 // manually, calling SpdySessionPool::Remove() directly. If it is true, 551 // sessions are closed with SpdySessionPool::CloseCurrentSessions(). 552 void IPPoolingTest(bool clean_via_close_current_sessions) { 553 const int kTestPort = 80; 554 struct TestHosts { 555 std::string name; 556 std::string iplist; 557 HostPortProxyPair pair; 558 } test_hosts[] = { 559 { "www.foo.com", "192.168.0.1,192.168.0.5" }, 560 { "images.foo.com", "192.168.0.2,192.168.0.3,192.168.0.5" }, 561 { "js.foo.com", "192.168.0.4,192.168.0.3" }, 562 }; 563 564 SpdySessionDependencies session_deps; 565 session_deps.host_resolver->set_synchronous_mode(true); 566 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_hosts); i++) { 567 session_deps.host_resolver->rules()->AddIPLiteralRule(test_hosts[i].name, 568 test_hosts[i].iplist, ""); 569 570 // This test requires that the HostResolver cache be populated. Normal 571 // code would have done this already, but we do it manually. 572 HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort)); 573 AddressList result; 574 session_deps.host_resolver->Resolve( 575 info, &result, NULL, NULL, BoundNetLog()); 576 577 // Setup a HostPortProxyPair 578 test_hosts[i].pair = HostPortProxyPair( 579 HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct()); 580 } 581 582 MockConnect connect_data(false, OK); 583 MockRead reads[] = { 584 MockRead(false, ERR_IO_PENDING) // Stall forever. 585 }; 586 587 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); 588 data.set_connect_data(connect_data); 589 session_deps.socket_factory->AddSocketDataProvider(&data); 590 591 SSLSocketDataProvider ssl(false, OK); 592 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); 593 594 scoped_refptr<HttpNetworkSession> http_session( 595 SpdySessionDependencies::SpdyCreateSession(&session_deps)); 596 597 // Setup the first session to the first host. 598 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); 599 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[0].pair)); 600 scoped_refptr<SpdySession> session = 601 spdy_session_pool->Get(test_hosts[0].pair, BoundNetLog()); 602 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[0].pair)); 603 604 HostPortPair test_host_port_pair(test_hosts[0].name, kTestPort); 605 scoped_refptr<TransportSocketParams> transport_params( 606 new TransportSocketParams(test_host_port_pair, 607 MEDIUM, 608 GURL(), 609 false, 610 false)); 611 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); 612 EXPECT_EQ(OK, 613 connection->Init(test_host_port_pair.ToString(), 614 transport_params, MEDIUM, 615 NULL, http_session->transport_socket_pool(), 616 BoundNetLog())); 617 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); 618 619 // Flush the SpdySession::OnReadComplete() task. 620 MessageLoop::current()->RunAllPending(); 621 622 // The third host has no overlap with the first, so it can't pool IPs. 623 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[2].pair)); 624 625 // The second host overlaps with the first, and should IP pool. 626 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[1].pair)); 627 628 // Verify that the second host, through a proxy, won't share the IP. 629 HostPortProxyPair proxy_pair(test_hosts[1].pair.first, 630 ProxyServer::FromPacString("HTTP http://proxy.foo.com/")); 631 EXPECT_FALSE(spdy_session_pool->HasSession(proxy_pair)); 632 633 // Overlap between 2 and 3 does is not transitive to 1. 634 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[2].pair)); 635 636 // Create a new session to host 2. 637 scoped_refptr<SpdySession> session2 = 638 spdy_session_pool->Get(test_hosts[2].pair, BoundNetLog()); 639 640 // Verify that we have sessions for everything. 641 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[0].pair)); 642 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[1].pair)); 643 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[2].pair)); 644 645 // Cleanup the sessions. 646 if (!clean_via_close_current_sessions) { 647 spdy_session_pool->Remove(session); 648 session = NULL; 649 spdy_session_pool->Remove(session2); 650 session2 = NULL; 651 } else { 652 spdy_session_pool->CloseCurrentSessions(); 653 } 654 655 // Verify that the map is all cleaned up. 656 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[0].pair)); 657 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[1].pair)); 658 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[2].pair)); 659 } 660 661 TEST_F(SpdySessionTest, IPPooling) { 662 IPPoolingTest(false); 663 } 664 665 TEST_F(SpdySessionTest, IPPoolingCloseCurrentSessions) { 666 IPPoolingTest(true); 667 } 668 669 } // namespace net 670