1// Copyright 2014 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/chromeos/login/auth/auth_prewarmer.h"
6
7#include "chrome/browser/chrome_notification_types.h"
8#include "chrome/browser/chromeos/profiles/profile_helper.h"
9#include "chrome/browser/net/chrome_url_request_context.h"
10#include "chrome/browser/net/preconnect.h"
11#include "chromeos/network/network_handler.h"
12#include "chromeos/network/network_state.h"
13#include "chromeos/network/network_state_handler.h"
14#include "content/public/browser/browser_thread.h"
15#include "google_apis/gaia/gaia_urls.h"
16#include "url/gurl.h"
17
18namespace chromeos {
19
20AuthPrewarmer::AuthPrewarmer()
21    : doing_prewarm_(false) {
22}
23
24AuthPrewarmer::~AuthPrewarmer() {
25  if (registrar_.IsRegistered(
26          this,
27          chrome::NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED,
28          content::Source<Profile>(ProfileHelper::GetSigninProfile()))) {
29    registrar_.Remove(
30        this,
31        chrome::NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED,
32        content::Source<Profile>(ProfileHelper::GetSigninProfile()));
33  }
34  NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
35                                                                 FROM_HERE);
36}
37
38void AuthPrewarmer::PrewarmAuthentication(
39    const base::Closure& completion_callback) {
40  if (doing_prewarm_) {
41    LOG(ERROR) << "PrewarmAuthentication called twice.";
42    return;
43  }
44  doing_prewarm_ = true;
45  completion_callback_ = completion_callback;
46  if (GetRequestContext() && IsNetworkConnected()) {
47    DoPrewarm();
48    return;
49  }
50  if (!IsNetworkConnected()) {
51    // DefaultNetworkChanged will get called when a network becomes connected.
52    NetworkHandler::Get()->network_state_handler()
53        ->AddObserver(this, FROM_HERE);
54  }
55  if (!GetRequestContext()) {
56    registrar_.Add(
57        this,
58        chrome::NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED,
59        content::Source<Profile>(ProfileHelper::GetSigninProfile()));
60  }
61}
62
63void AuthPrewarmer::DefaultNetworkChanged(const NetworkState* network) {
64  if (!network)
65    return;  // Still no default (connected) network.
66
67  NetworkHandler::Get()->network_state_handler()
68      ->RemoveObserver(this, FROM_HERE);
69  if (GetRequestContext())
70    DoPrewarm();
71}
72
73void AuthPrewarmer::Observe(int type,
74                            const content::NotificationSource& source,
75                            const content::NotificationDetails& details) {
76  switch (type) {
77    case chrome::NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED:
78      registrar_.Remove(
79          this,
80          chrome::NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED,
81          content::Source<Profile>(ProfileHelper::GetSigninProfile()));
82      if (IsNetworkConnected())
83        DoPrewarm();
84      break;
85    default:
86      NOTREACHED();
87  }
88}
89
90void AuthPrewarmer::DoPrewarm() {
91  const int kConnectionsNeeded = 1;
92
93  std::vector<GURL> urls;
94  urls.push_back(GaiaUrls::GetInstance()->client_login_url());
95  urls.push_back(GaiaUrls::GetInstance()->service_login_url());
96
97  for (size_t i = 0; i < urls.size(); ++i) {
98    chrome_browser_net::PreconnectOnUIThread(
99        urls[i],
100        urls[i],
101        chrome_browser_net::UrlInfo::EARLY_LOAD_MOTIVATED,
102        kConnectionsNeeded,
103        GetRequestContext());
104  }
105  if (!completion_callback_.is_null()) {
106    content::BrowserThread::PostTask(content::BrowserThread::UI,
107                                     FROM_HERE,
108                                     completion_callback_);
109  }
110}
111
112bool AuthPrewarmer::IsNetworkConnected() const {
113  NetworkStateHandler* nsh = NetworkHandler::Get()->network_state_handler();
114  return (nsh->ConnectedNetworkByType(NetworkTypePattern::Default()) != NULL);
115}
116
117net::URLRequestContextGetter* AuthPrewarmer::GetRequestContext() const {
118  return ProfileHelper::GetSigninProfile()->GetRequestContext();
119}
120
121}  // namespace chromeos
122