Home | History | Annotate | Download | only in http
      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/http/http_stream_factory_impl.h"
      6 
      7 #include <string>
      8 
      9 #include "base/basictypes.h"
     10 #include "net/base/cert_verifier.h"
     11 #include "net/base/mock_host_resolver.h"
     12 #include "net/base/net_log.h"
     13 #include "net/base/ssl_config_service_defaults.h"
     14 #include "net/base/test_completion_callback.h"
     15 #include "net/http/http_auth_handler_factory.h"
     16 #include "net/http/http_network_session.h"
     17 #include "net/http/http_network_session_peer.h"
     18 #include "net/http/http_request_info.h"
     19 #include "net/proxy/proxy_info.h"
     20 #include "net/proxy/proxy_service.h"
     21 #include "net/socket/socket_test_util.h"
     22 #include "net/spdy/spdy_session.h"
     23 #include "net/spdy/spdy_session_pool.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 namespace net {
     27 
     28 namespace {
     29 
     30 class MockHttpStreamFactoryImpl : public HttpStreamFactoryImpl {
     31  public:
     32   MockHttpStreamFactoryImpl(HttpNetworkSession* session)
     33       : HttpStreamFactoryImpl(session),
     34         preconnect_done_(false),
     35         waiting_for_preconnect_(false) {}
     36 
     37 
     38   void WaitForPreconnects() {
     39     while (!preconnect_done_) {
     40       waiting_for_preconnect_ = true;
     41       MessageLoop::current()->Run();
     42       waiting_for_preconnect_ = false;
     43     }
     44   }
     45 
     46  private:
     47   // HttpStreamFactoryImpl methods.
     48   virtual void OnPreconnectsCompleteInternal() {
     49     preconnect_done_ = true;
     50     if (waiting_for_preconnect_)
     51       MessageLoop::current()->Quit();
     52   }
     53 
     54   bool preconnect_done_;
     55   bool waiting_for_preconnect_;
     56 };
     57 
     58 struct SessionDependencies {
     59   // Custom proxy service dependency.
     60   explicit SessionDependencies(ProxyService* proxy_service)
     61       : host_resolver(new MockHostResolver),
     62         cert_verifier(new CertVerifier),
     63         proxy_service(proxy_service),
     64         ssl_config_service(new SSLConfigServiceDefaults),
     65         http_auth_handler_factory(
     66             HttpAuthHandlerFactory::CreateDefault(host_resolver.get())),
     67         net_log(NULL) {}
     68 
     69   scoped_ptr<MockHostResolverBase> host_resolver;
     70   scoped_ptr<CertVerifier> cert_verifier;
     71   scoped_refptr<ProxyService> proxy_service;
     72   scoped_refptr<SSLConfigService> ssl_config_service;
     73   MockClientSocketFactory socket_factory;
     74   scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory;
     75   NetLog* net_log;
     76 };
     77 
     78 HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
     79   HttpNetworkSession::Params params;
     80   params.host_resolver = session_deps->host_resolver.get();
     81   params.cert_verifier = session_deps->cert_verifier.get();
     82   params.proxy_service = session_deps->proxy_service;
     83   params.ssl_config_service = session_deps->ssl_config_service;
     84   params.client_socket_factory = &session_deps->socket_factory;
     85   params.http_auth_handler_factory =
     86       session_deps->http_auth_handler_factory.get();
     87   params.net_log = session_deps->net_log;
     88   return new HttpNetworkSession(params);
     89 }
     90 
     91 struct TestCase {
     92   int num_streams;
     93   bool ssl;
     94 };
     95 
     96 TestCase kTests[] = {
     97   { 1, false },
     98   { 2, false },
     99   { 1, true},
    100   { 2, true},
    101 };
    102 
    103 void PreconnectHelper(const TestCase& test,
    104                       HttpNetworkSession* session) {
    105   HttpNetworkSessionPeer peer(session);
    106   MockHttpStreamFactoryImpl* mock_factory =
    107       new MockHttpStreamFactoryImpl(session);
    108   peer.SetHttpStreamFactory(mock_factory);
    109   SSLConfig ssl_config;
    110   session->ssl_config_service()->GetSSLConfig(&ssl_config);
    111 
    112   HttpRequestInfo request;
    113   request.method = "GET";
    114   request.url = test.ssl ?  GURL("https://www.google.com") :
    115       GURL("http://www.google.com");
    116   request.load_flags = 0;
    117 
    118   ProxyInfo proxy_info;
    119   TestCompletionCallback callback;
    120 
    121   session->http_stream_factory()->PreconnectStreams(
    122       test.num_streams, request, ssl_config, BoundNetLog());
    123   mock_factory->WaitForPreconnects();
    124 };
    125 
    126 template<typename ParentPool>
    127 class CapturePreconnectsSocketPool : public ParentPool {
    128  public:
    129   CapturePreconnectsSocketPool(HostResolver* host_resolver,
    130                                CertVerifier* cert_verifier);
    131 
    132   int last_num_streams() const {
    133     return last_num_streams_;
    134   }
    135 
    136   virtual int RequestSocket(const std::string& group_name,
    137                             const void* socket_params,
    138                             RequestPriority priority,
    139                             ClientSocketHandle* handle,
    140                             CompletionCallback* callback,
    141                             const BoundNetLog& net_log) {
    142     ADD_FAILURE();
    143     return ERR_UNEXPECTED;
    144   }
    145 
    146   virtual void RequestSockets(const std::string& group_name,
    147                               const void* socket_params,
    148                               int num_sockets,
    149                               const BoundNetLog& net_log) {
    150     last_num_streams_ = num_sockets;
    151   }
    152 
    153   virtual void CancelRequest(const std::string& group_name,
    154                              ClientSocketHandle* handle) {
    155     ADD_FAILURE();
    156   }
    157   virtual void ReleaseSocket(const std::string& group_name,
    158                              ClientSocket* socket,
    159                              int id) {
    160     ADD_FAILURE();
    161   }
    162   virtual void CloseIdleSockets() {
    163     ADD_FAILURE();
    164   }
    165   virtual int IdleSocketCount() const {
    166     ADD_FAILURE();
    167     return 0;
    168   }
    169   virtual int IdleSocketCountInGroup(const std::string& group_name) const {
    170     ADD_FAILURE();
    171     return 0;
    172   }
    173   virtual LoadState GetLoadState(const std::string& group_name,
    174                                  const ClientSocketHandle* handle) const {
    175     ADD_FAILURE();
    176     return LOAD_STATE_IDLE;
    177   }
    178   virtual base::TimeDelta ConnectionTimeout() const {
    179     return base::TimeDelta();
    180   }
    181 
    182  private:
    183   int last_num_streams_;
    184 };
    185 
    186 typedef CapturePreconnectsSocketPool<TransportClientSocketPool>
    187 CapturePreconnectsTransportSocketPool;
    188 typedef CapturePreconnectsSocketPool<HttpProxyClientSocketPool>
    189 CapturePreconnectsHttpProxySocketPool;
    190 typedef CapturePreconnectsSocketPool<SOCKSClientSocketPool>
    191 CapturePreconnectsSOCKSSocketPool;
    192 typedef CapturePreconnectsSocketPool<SSLClientSocketPool>
    193 CapturePreconnectsSSLSocketPool;
    194 
    195 template<typename ParentPool>
    196 CapturePreconnectsSocketPool<ParentPool>::CapturePreconnectsSocketPool(
    197     HostResolver* host_resolver, CertVerifier* /* cert_verifier */)
    198     : ParentPool(0, 0, NULL, host_resolver, NULL, NULL),
    199       last_num_streams_(-1) {}
    200 
    201 template<>
    202 CapturePreconnectsHttpProxySocketPool::CapturePreconnectsSocketPool(
    203     HostResolver* host_resolver, CertVerifier* /* cert_verifier */)
    204     : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL),
    205       last_num_streams_(-1) {}
    206 
    207 template<>
    208 CapturePreconnectsSSLSocketPool::CapturePreconnectsSocketPool(
    209     HostResolver* host_resolver, CertVerifier* cert_verifier)
    210     : SSLClientSocketPool(0, 0, NULL, host_resolver, cert_verifier, NULL, NULL,
    211                           NULL, NULL, NULL, NULL, NULL, NULL, NULL),
    212       last_num_streams_(-1) {}
    213 
    214 TEST(HttpStreamFactoryTest, PreconnectDirect) {
    215   for (size_t i = 0; i < arraysize(kTests); ++i) {
    216     SessionDependencies session_deps(ProxyService::CreateDirect());
    217     scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
    218     HttpNetworkSessionPeer peer(session);
    219     CapturePreconnectsTransportSocketPool* transport_conn_pool =
    220         new CapturePreconnectsTransportSocketPool(
    221             session_deps.host_resolver.get(),
    222             session_deps.cert_verifier.get());
    223     peer.SetTransportSocketPool(transport_conn_pool);
    224     CapturePreconnectsSSLSocketPool* ssl_conn_pool =
    225         new CapturePreconnectsSSLSocketPool(
    226             session_deps.host_resolver.get(),
    227             session_deps.cert_verifier.get());
    228     peer.SetSSLSocketPool(ssl_conn_pool);
    229     PreconnectHelper(kTests[i], session);
    230     if (kTests[i].ssl)
    231       EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams());
    232     else
    233       EXPECT_EQ(kTests[i].num_streams, transport_conn_pool->last_num_streams());
    234   }
    235 }
    236 
    237 TEST(HttpStreamFactoryTest, PreconnectHttpProxy) {
    238   for (size_t i = 0; i < arraysize(kTests); ++i) {
    239     SessionDependencies session_deps(ProxyService::CreateFixed("http_proxy"));
    240     scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
    241     HttpNetworkSessionPeer peer(session);
    242     HostPortPair proxy_host("http_proxy", 80);
    243     CapturePreconnectsHttpProxySocketPool* http_proxy_pool =
    244         new CapturePreconnectsHttpProxySocketPool(
    245             session_deps.host_resolver.get(),
    246             session_deps.cert_verifier.get());
    247     peer.SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool);
    248     CapturePreconnectsSSLSocketPool* ssl_conn_pool =
    249         new CapturePreconnectsSSLSocketPool(
    250             session_deps.host_resolver.get(),
    251             session_deps.cert_verifier.get());
    252     peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
    253     PreconnectHelper(kTests[i], session);
    254     if (kTests[i].ssl)
    255       EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams());
    256     else
    257       EXPECT_EQ(kTests[i].num_streams, http_proxy_pool->last_num_streams());
    258   }
    259 }
    260 
    261 TEST(HttpStreamFactoryTest, PreconnectSocksProxy) {
    262   for (size_t i = 0; i < arraysize(kTests); ++i) {
    263     SessionDependencies session_deps(
    264         ProxyService::CreateFixed("socks4://socks_proxy:1080"));
    265     scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
    266     HttpNetworkSessionPeer peer(session);
    267     HostPortPair proxy_host("socks_proxy", 1080);
    268     CapturePreconnectsSOCKSSocketPool* socks_proxy_pool =
    269         new CapturePreconnectsSOCKSSocketPool(
    270             session_deps.host_resolver.get(),
    271             session_deps.cert_verifier.get());
    272     peer.SetSocketPoolForSOCKSProxy(proxy_host, socks_proxy_pool);
    273     CapturePreconnectsSSLSocketPool* ssl_conn_pool =
    274         new CapturePreconnectsSSLSocketPool(
    275             session_deps.host_resolver.get(),
    276             session_deps.cert_verifier.get());
    277     peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
    278     PreconnectHelper(kTests[i], session);
    279     if (kTests[i].ssl)
    280       EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams());
    281     else
    282       EXPECT_EQ(kTests[i].num_streams, socks_proxy_pool->last_num_streams());
    283   }
    284 }
    285 
    286 TEST(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) {
    287   for (size_t i = 0; i < arraysize(kTests); ++i) {
    288     SessionDependencies session_deps(ProxyService::CreateDirect());
    289     scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
    290     HttpNetworkSessionPeer peer(session);
    291 
    292     // Set an existing SpdySession in the pool.
    293     HostPortPair host_port_pair("www.google.com", 443);
    294     HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
    295     scoped_refptr<SpdySession> spdy_session =
    296         session->spdy_session_pool()->Get(pair, BoundNetLog());
    297 
    298     CapturePreconnectsTransportSocketPool* transport_conn_pool =
    299         new CapturePreconnectsTransportSocketPool(
    300             session_deps.host_resolver.get(),
    301             session_deps.cert_verifier.get());
    302     peer.SetTransportSocketPool(transport_conn_pool);
    303     CapturePreconnectsSSLSocketPool* ssl_conn_pool =
    304         new CapturePreconnectsSSLSocketPool(
    305             session_deps.host_resolver.get(),
    306             session_deps.cert_verifier.get());
    307     peer.SetSSLSocketPool(ssl_conn_pool);
    308     PreconnectHelper(kTests[i], session);
    309     // We shouldn't be preconnecting if we have an existing session, which is
    310     // the case for https://www.google.com.
    311     if (kTests[i].ssl)
    312       EXPECT_EQ(-1, ssl_conn_pool->last_num_streams());
    313     else
    314       EXPECT_EQ(kTests[i].num_streams, transport_conn_pool->last_num_streams());
    315   }
    316 }
    317 
    318 }  // namespace
    319 
    320 }  // namespace net
    321