Home | History | Annotate | Download | only in net
      1 // Copyright (c) 2012 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 "chrome/browser/net/preconnect.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/metrics/histogram.h"
     10 #include "content/public/browser/browser_thread.h"
     11 #include "net/base/net_log.h"
     12 #include "net/http/http_network_session.h"
     13 #include "net/http/http_request_info.h"
     14 #include "net/http/http_stream_factory.h"
     15 #include "net/http/http_transaction_factory.h"
     16 #include "net/ssl/ssl_config_service.h"
     17 #include "net/url_request/http_user_agent_settings.h"
     18 #include "net/url_request/url_request_context.h"
     19 #include "net/url_request/url_request_context_getter.h"
     20 
     21 using content::BrowserThread;
     22 
     23 namespace chrome_browser_net {
     24 
     25 void PreconnectOnUIThread(
     26     const GURL& url,
     27     const GURL& first_party_for_cookies,
     28     UrlInfo::ResolutionMotivation motivation,
     29     int count,
     30     net::URLRequestContextGetter* getter) {
     31   // Prewarm connection to Search URL.
     32   BrowserThread::PostTask(
     33       BrowserThread::IO,
     34       FROM_HERE,
     35       base::Bind(&PreconnectOnIOThread, url, first_party_for_cookies,
     36                  motivation, count, make_scoped_refptr(getter)));
     37   return;
     38 }
     39 
     40 
     41 void PreconnectOnIOThread(
     42     const GURL& url,
     43     const GURL& first_party_for_cookies,
     44     UrlInfo::ResolutionMotivation motivation,
     45     int count,
     46     net::URLRequestContextGetter* getter) {
     47   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
     48     LOG(DFATAL) << "This must be run only on the IO thread.";
     49     return;
     50   }
     51   if (!getter)
     52     return;
     53   // We are now commited to doing the async preconnection call.
     54   UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation,
     55                             UrlInfo::MAX_MOTIVATED);
     56 
     57   net::URLRequestContext* context = getter->GetURLRequestContext();
     58   net::HttpTransactionFactory* factory = context->http_transaction_factory();
     59   net::HttpNetworkSession* session = factory->GetSession();
     60 
     61   std::string user_agent;
     62   if (context->http_user_agent_settings())
     63     user_agent = context->http_user_agent_settings()->GetUserAgent();
     64   net::HttpRequestInfo request_info;
     65   request_info.url = url;
     66   request_info.method = "GET";
     67   request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kUserAgent,
     68                                        user_agent);
     69 
     70   net::NetworkDelegate* delegate = context->network_delegate();
     71   if (delegate->CanEnablePrivacyMode(url, first_party_for_cookies))
     72     request_info.privacy_mode = net::PRIVACY_MODE_ENABLED;
     73 
     74   // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST
     75   // priority here, as we won't make a request, and will surrender the created
     76   // socket to the pool as soon as we can.  However, we would like to mark the
     77   // speculative socket as such, and IF we use a net::LOWEST priority, and if
     78   // a navigation asked for a socket (after us) then it would get our socket,
     79   // and we'd get its later-arriving socket, which might make us record that
     80   // the speculation didn't help :-/.  By using net::HIGHEST, we ensure that
     81   // a socket is given to us if "we asked first" and this allows us to mark it
     82   // as speculative, and better detect stats (if it gets used).
     83   // TODO(jar): histogram to see how often we accidentally use a previously-
     84   // unused socket, when a previously used socket was available.
     85   net::RequestPriority priority = net::HIGHEST;
     86 
     87   // Translate the motivation from UrlRequest motivations to HttpRequest
     88   // motivations.
     89   switch (motivation) {
     90     case UrlInfo::OMNIBOX_MOTIVATED:
     91       request_info.motivation = net::HttpRequestInfo::OMNIBOX_MOTIVATED;
     92       break;
     93     case UrlInfo::LEARNED_REFERAL_MOTIVATED:
     94       request_info.motivation = net::HttpRequestInfo::PRECONNECT_MOTIVATED;
     95       break;
     96     case UrlInfo::MOUSE_OVER_MOTIVATED:
     97     case UrlInfo::SELF_REFERAL_MOTIVATED:
     98     case UrlInfo::EARLY_LOAD_MOTIVATED:
     99       request_info.motivation = net::HttpRequestInfo::EARLY_LOAD_MOTIVATED;
    100       break;
    101     default:
    102       // Other motivations should never happen here.
    103       NOTREACHED();
    104       break;
    105   }
    106 
    107   // Setup the SSL Configuration.
    108   net::SSLConfig ssl_config;
    109   session->ssl_config_service()->GetSSLConfig(&ssl_config);
    110   session->GetNextProtos(&ssl_config.next_protos);
    111 
    112   // All preconnects should perform EV certificate verification.
    113   ssl_config.verify_ev_cert = true;
    114 
    115   net::HttpStreamFactory* http_stream_factory = session->http_stream_factory();
    116   http_stream_factory->PreconnectStreams(count, request_info, priority,
    117                                          ssl_config, ssl_config);
    118 }
    119 
    120 }  // namespace chrome_browser_net
    121