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