preconnect.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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/histogram.h"
8#include "base/logging.h"
9#include "base/string_util.h"
10#include "chrome/browser/profile.h"
11#include "chrome/browser/chrome_thread.h"
12#include "chrome/common/net/url_request_context_getter.h"
13#include "net/base/host_port_pair.h"
14#include "net/http/http_network_session.h"
15#include "net/http/http_request_info.h"
16#include "net/http/http_stream.h"
17#include "net/http/http_transaction_factory.h"
18#include "net/proxy/proxy_service.h"
19#include "net/url_request/url_request_context.h"
20
21namespace chrome_browser_net {
22
23// static
24void Preconnect::PreconnectOnUIThread(const GURL& url,
25    UrlInfo::ResolutionMotivation motivation) {
26  // Prewarm connection to Search URL.
27  ChromeThread::PostTask(
28      ChromeThread::IO,
29      FROM_HERE,
30      NewRunnableFunction(Preconnect::PreconnectOnIOThread, url, motivation));
31  return;
32}
33
34// static
35void Preconnect::PreconnectOnIOThread(const GURL& url,
36    UrlInfo::ResolutionMotivation motivation) {
37  Preconnect* preconnect = new Preconnect(motivation);
38  // TODO(jar): Should I use PostTask for LearnedSubresources to delay the
39  // preconnection a tad?
40  preconnect->Connect(url);
41}
42
43void Preconnect::Connect(const GURL& url) {
44  URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
45  if (!getter)
46    return;
47  if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
48    LOG(DFATAL) << "This must be run only on the IO thread.";
49    return;
50  }
51
52  // We are now commited to doing the async preconnection call.
53  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation_,
54                            UrlInfo::MAX_MOTIVATED);
55
56  URLRequestContext* context = getter->GetURLRequestContext();
57  net::HttpTransactionFactory* factory = context->http_transaction_factory();
58  net::HttpNetworkSession* session = factory->GetSession();
59
60  request_info_.reset(new net::HttpRequestInfo());
61  request_info_->url = url;
62  request_info_->method = "GET";
63  // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST
64  // priority here, as we won't make a request, and will surrender the created
65  // socket to the pool as soon as we can.  However, we would like to mark the
66  // speculative socket as such, and IF we use a net::LOWEST priority, and if
67  // a navigation asked for a socket (after us) then it would get our socket,
68  // and we'd get its later-arriving socket, which might make us record that
69  // the speculation didn't help :-/.  By using net::HIGHEST, we ensure that
70  // a socket is given to us if "we asked first" and this allows us to mark it
71  // as speculative, and better detect stats (if it gets used).
72  // TODO(jar): histogram to see how often we accidentally use a previously-
73  // unused socket, when a previously used socket was available.
74  request_info_->priority = net::HIGHEST;
75
76  // Translate the motivation from UrlRequest motivations to HttpRequest
77  // motivations.
78  switch (motivation_) {
79    case UrlInfo::OMNIBOX_MOTIVATED:
80      request_info_->motivation = net::HttpRequestInfo::OMNIBOX_MOTIVATED;
81      break;
82    case UrlInfo::LEARNED_REFERAL_MOTIVATED:
83      request_info_->motivation = net::HttpRequestInfo::PRECONNECT_MOTIVATED;
84      break;
85    case UrlInfo::EARLY_LOAD_MOTIVATED:
86      break;
87    default:
88      // Other motivations should never happen here.
89      NOTREACHED();
90      break;
91  }
92
93  // Setup the SSL Configuration.
94  ssl_config_.reset(new net::SSLConfig());
95  session->ssl_config_service()->GetSSLConfig(ssl_config_.get());
96  if (session->http_stream_factory()->next_protos())
97    ssl_config_->next_protos = *session->http_stream_factory()->next_protos();
98
99  // All preconnects should be for main pages.
100  ssl_config_->verify_ev_cert = true;
101
102  proxy_info_.reset(new net::ProxyInfo());
103  net::StreamFactory* stream_factory = session->http_stream_factory();
104  stream_factory->RequestStream(request_info_.get(), ssl_config_.get(),
105                                proxy_info_.get(), this, net_log_, session,
106                                &stream_request_job_);
107}
108
109void Preconnect::OnStreamReady(net::HttpStream* stream) {
110  delete stream;
111  delete this;
112}
113
114void Preconnect::OnStreamFailed(int status) {
115  delete this;
116}
117
118void Preconnect::OnCertificateError(int status, const net::SSLInfo& ssl_info) {
119  delete this;
120}
121
122void Preconnect::OnNeedsProxyAuth(const net::HttpResponseInfo& proxy_response,
123                                  net::HttpAuthController* auth_controller) {
124  delete this;
125}
126
127void Preconnect::OnNeedsClientAuth(net::SSLCertRequestInfo* cert_info) {
128  delete this;
129}
130
131}  // chrome_browser_net
132