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