preconnect.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// found in the LICENSE file.
4bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
5bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/net/preconnect.h"
6bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
7bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/histogram.h"
8bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/logging.h"
9bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/string_util.h"
10bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/profile.h"
11bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/chrome_thread.h"
12bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/common/net/url_request_context_getter.h"
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "net/base/host_port_pair.h"
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "net/http/http_network_session.h"
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "net/http/http_request_info.h"
16bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "net/http/http_stream.h"
17bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "net/http/http_transaction_factory.h"
18bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "net/proxy/proxy_service.h"
19bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "net/url_request/url_request_context.h"
20bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
21bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsennamespace chrome_browser_net {
22bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// static
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Preconnect::PreconnectOnUIThread(const GURL& url,
25731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    UrlInfo::ResolutionMotivation motivation) {
26bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Prewarm connection to Search URL.
27bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  ChromeThread::PostTask(
284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      ChromeThread::IO,
293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      FROM_HERE,
303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      NewRunnableFunction(Preconnect::PreconnectOnIOThread, url, motivation));
314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return;
324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
33bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// static
35bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid Preconnect::PreconnectOnIOThread(const GURL& url,
36731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    UrlInfo::ResolutionMotivation motivation) {
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Preconnect* preconnect = new Preconnect(motivation);
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // TODO(jar): Should I use PostTask for LearnedSubresources to delay the
39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // preconnection a tad?
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  preconnect->Connect(url);
41bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
42bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
43bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid Preconnect::Connect(const GURL& url) {
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
45bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (!getter)
46bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return;
47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    LOG(DFATAL) << "This must be run only on the IO thread.";
49731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  }
513f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
52731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // We are now commited to doing the async preconnection call.
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation_,
54dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                            UrlInfo::MAX_MOTIVATED);
55731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
56731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  URLRequestContext* context = getter->GetURLRequestContext();
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  net::HttpTransactionFactory* factory = context->http_transaction_factory();
58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  net::HttpNetworkSession* session = factory->GetSession();
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  request_info_.reset(new net::HttpRequestInfo());
61bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  request_info_->url = url;
62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  request_info_->method = "GET";
63bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST
64bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // priority here, as we won't make a request, and will surrender the created
65bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // socket to the pool as soon as we can.  However, we would like to mark the
66513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // speculative socket as such, and IF we use a net::LOWEST priority, and if
67bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // a navigation asked for a socket (after us) then it would get our socket,
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // and we'd get its later-arriving socket, which might make us record that
69bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // the speculation didn't help :-/.  By using net::HIGHEST, we ensure that
70bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // a socket is given to us if "we asked first" and this allows us to mark it
71bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // as speculative, and better detect stats (if it gets used).
72bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // TODO(jar): histogram to see how often we accidentally use a previously-
73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // unused socket, when a previously used socket was available.
74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  request_info_->priority = net::HIGHEST;
75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
76bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Translate the motivation from UrlRequest motivations to HttpRequest
77bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // motivations.
78513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  switch (motivation_) {
79513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case UrlInfo::OMNIBOX_MOTIVATED:
80513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      request_info_->motivation = net::HttpRequestInfo::OMNIBOX_MOTIVATED;
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
82513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case UrlInfo::LEARNED_REFERAL_MOTIVATED:
83513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      request_info_->motivation = net::HttpRequestInfo::PRECONNECT_MOTIVATED;
843f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      break;
853f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    case UrlInfo::EARLY_LOAD_MOTIVATED:
8621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      break;
8721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    default:
8821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      // Other motivations should never happen here.
89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NOTREACHED();
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
9121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
9221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Setup the SSL Configuration.
94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ssl_config_.reset(new net::SSLConfig());
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  session->ssl_config_service()->GetSSLConfig(ssl_config_.get());
96513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (session->http_stream_factory()->next_protos())
9721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    ssl_config_->next_protos = *session->http_stream_factory()->next_protos();
98513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // All preconnects should be for main pages.
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  ssl_config_->verify_ev_cert = true;
101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  proxy_info_.reset(new net::ProxyInfo());
103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  net::StreamFactory* stream_factory = session->http_stream_factory();
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  stream_factory->RequestStream(request_info_.get(), ssl_config_.get(),
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                proxy_info_.get(), this, net_log_, session,
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                &stream_request_job_);
107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
109bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid Preconnect::OnStreamReady(net::HttpStream* stream) {
110bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  delete stream;
111bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  delete this;
112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
113bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
1143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid Preconnect::OnStreamFailed(int status) {
1153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  delete this;
116bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
117bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
118731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid Preconnect::OnCertificateError(int status, const net::SSLInfo& ssl_info) {
119bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  delete this;
1203f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}
1213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
122bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid Preconnect::OnNeedsProxyAuth(const net::HttpResponseInfo& proxy_response,
123bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                  net::HttpAuthController* auth_controller) {
124bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  delete this;
125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
126bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
127bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid Preconnect::OnNeedsClientAuth(net::SSLCertRequestInfo* cert_info) {
128bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  delete this;
129}
130
131}  // chrome_browser_net
132