1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/preconnect.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
8731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
10dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/base/net_log.h"
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/base/ssl_config_service.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_network_session.h"
14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/http/http_request_info.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/http/http_stream_factory.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_transaction_factory.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_context.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/url_request/url_request_context_getter.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chrome_browser_net {
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid PreconnectOnUIThread(
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const GURL& url,
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    UrlInfo::ResolutionMotivation motivation,
25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int count) {
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Prewarm connection to Search URL.
27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
28731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO,
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FROM_HERE,
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NewRunnableFunction(PreconnectOnIOThread, url, motivation,
31201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          count));
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return;
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid PreconnectOnIOThread(
37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const GURL& url,
38dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    UrlInfo::ResolutionMotivation motivation,
39dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int count) {
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  net::URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!getter)
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
43731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(DFATAL) << "This must be run only on the IO thread.";
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We are now commited to doing the async preconnection call.
49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation,
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                            UrlInfo::MAX_MOTIVATED);
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  net::URLRequestContext* context = getter->GetURLRequestContext();
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::HttpTransactionFactory* factory = context->http_transaction_factory();
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::HttpNetworkSession* session = factory->GetSession();
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  net::HttpRequestInfo request_info;
57dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  request_info.url = url;
58dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  request_info.method = "GET";
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kUserAgent,
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       context->GetUserAgent(url));
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // priority here, as we won't make a request, and will surrender the created
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // socket to the pool as soon as we can.  However, we would like to mark the
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // speculative socket as such, and IF we use a net::LOWEST priority, and if
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // a navigation asked for a socket (after us) then it would get our socket,
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // and we'd get its later-arriving socket, which might make us record that
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // the speculation didn't help :-/.  By using net::HIGHEST, we ensure that
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // a socket is given to us if "we asked first" and this allows us to mark it
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // as speculative, and better detect stats (if it gets used).
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(jar): histogram to see how often we accidentally use a previously-
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // unused socket, when a previously used socket was available.
72dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  request_info.priority = net::HIGHEST;
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Translate the motivation from UrlRequest motivations to HttpRequest
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // motivations.
76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  switch (motivation) {
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case UrlInfo::OMNIBOX_MOTIVATED:
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      request_info.motivation = net::HttpRequestInfo::OMNIBOX_MOTIVATED;
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case UrlInfo::LEARNED_REFERAL_MOTIVATED:
81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      request_info.motivation = net::HttpRequestInfo::PRECONNECT_MOTIVATED;
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case UrlInfo::SELF_REFERAL_MOTIVATED:
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case UrlInfo::EARLY_LOAD_MOTIVATED:
85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      request_info.motivation = net::HttpRequestInfo::EARLY_LOAD_MOTIVATED;
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    default:
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Other motivations should never happen here.
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NOTREACHED();
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Setup the SSL Configuration.
94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  net::SSLConfig ssl_config;
95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  session->ssl_config_service()->GetSSLConfig(&ssl_config);
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (session->http_stream_factory()->next_protos())
97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ssl_config.next_protos = *session->http_stream_factory()->next_protos();
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // All preconnects should perform EV certificate verification.
100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ssl_config.verify_ev_cert = true;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  net::HttpStreamFactory* http_stream_factory = session->http_stream_factory();
103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  http_stream_factory->PreconnectStreams(
104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      count, request_info, ssl_config, net::BoundNetLog());
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
107201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}  // namespace chrome_browser_net
108