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 21using content::BrowserThread; 22 23namespace chrome_browser_net { 24 25void 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 41void 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