Home | History | Annotate | Download | only in spdy
      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