summaryrefslogtreecommitdiffstats
path: root/chrome/browser/net/preconnect.cc
blob: ca22bd694e307fc9c83c1053d7c4b5dd38b6b5d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/net/preconnect.h"

#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/base/host_port_pair.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_info.h"
#include "net/http/http_stream.h"
#include "net/http/http_transaction_factory.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"

namespace chrome_browser_net {

// static
void Preconnect::PreconnectOnUIThread(const GURL& url,
    UrlInfo::ResolutionMotivation motivation) {
  // Prewarm connection to Search URL.
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      NewRunnableFunction(Preconnect::PreconnectOnIOThread, url, motivation));
  return;
}

// static
void Preconnect::PreconnectOnIOThread(const GURL& url,
    UrlInfo::ResolutionMotivation motivation) {
  Preconnect* preconnect = new Preconnect(motivation);
  // TODO(jar): Should I use PostTask for LearnedSubresources to delay the
  // preconnection a tad?
  preconnect->Connect(url);
}

void Preconnect::Connect(const GURL& url) {
  URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
  if (!getter)
    return;
  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
    LOG(DFATAL) << "This must be run only on the IO thread.";
    return;
  }

  // We are now commited to doing the async preconnection call.
  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation_,
                            UrlInfo::MAX_MOTIVATED);

  URLRequestContext* context = getter->GetURLRequestContext();
  net::HttpTransactionFactory* factory = context->http_transaction_factory();
  net::HttpNetworkSession* session = factory->GetSession();

  request_info_.reset(new net::HttpRequestInfo());
  request_info_->url = url;
  request_info_->method = "GET";
  // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST
  // priority here, as we won't make a request, and will surrender the created
  // socket to the pool as soon as we can.  However, we would like to mark the
  // speculative socket as such, and IF we use a net::LOWEST priority, and if
  // a navigation asked for a socket (after us) then it would get our socket,
  // and we'd get its later-arriving socket, which might make us record that
  // the speculation didn't help :-/.  By using net::HIGHEST, we ensure that
  // a socket is given to us if "we asked first" and this allows us to mark it
  // as speculative, and better detect stats (if it gets used).
  // TODO(jar): histogram to see how often we accidentally use a previously-
  // unused socket, when a previously used socket was available.
  request_info_->priority = net::HIGHEST;

  // Translate the motivation from UrlRequest motivations to HttpRequest
  // motivations.
  switch (motivation_) {
    case UrlInfo::OMNIBOX_MOTIVATED:
      request_info_->motivation = net::HttpRequestInfo::OMNIBOX_MOTIVATED;
      break;
    case UrlInfo::LEARNED_REFERAL_MOTIVATED:
      request_info_->motivation = net::HttpRequestInfo::PRECONNECT_MOTIVATED;
      break;
    case UrlInfo::EARLY_LOAD_MOTIVATED:
      break;
    default:
      // Other motivations should never happen here.
      NOTREACHED();
      break;
  }

  // Setup the SSL Configuration.
  ssl_config_.reset(new net::SSLConfig());
  session->ssl_config_service()->GetSSLConfig(ssl_config_.get());
  if (session->http_stream_factory()->next_protos())
    ssl_config_->next_protos = *session->http_stream_factory()->next_protos();

  // All preconnects should be for main pages.
  ssl_config_->verify_ev_cert = true;

  proxy_info_.reset(new net::ProxyInfo());
  net::StreamFactory* stream_factory = session->http_stream_factory();
  stream_factory->RequestStream(request_info_.get(), ssl_config_.get(),
                                proxy_info_.get(), this, net_log_, session,
                                &stream_request_job_);
}

void Preconnect::OnStreamReady(net::HttpStream* stream) {
  delete stream;
  delete this;
}

void Preconnect::OnStreamFailed(int status) {
  delete this;
}

void Preconnect::OnCertificateError(int status, const net::SSLInfo& ssl_info) {
  delete this;
}

void Preconnect::OnNeedsProxyAuth(const net::HttpResponseInfo& proxy_response,
                                  net::HttpAuthController* auth_controller) {
  delete this;
}

void Preconnect::OnNeedsClientAuth(net::SSLCertRequestInfo* cert_info) {
  delete this;
}

}  // chrome_browser_net