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