Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / signin / core / browser / device_activity_fetcher.cc
blob39b7433c8f5396e39bb90f9efcccb70310422d14
1 // Copyright 2015 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.
5 #include "components/signin/core/browser/device_activity_fetcher.h"
7 #include "base/strings/stringprintf.h"
8 #include "components/signin/core/browser/signin_client.h"
9 #include "google_apis/gaia/gaia_auth_fetcher.h"
10 #include "google_apis/gaia/gaia_constants.h"
11 #include "google_apis/gaia/gaia_urls.h"
12 #include "google_apis/gaia/google_service_auth_error.h"
13 #include "net/http/http_status_code.h"
14 #include "net/url_request/url_fetcher.h"
16 namespace {
18 // TODO(mlerman,anthonyvd): Replace the three parameters following with the
19 // necessary parameters for calling the ListDevices endpoint, once live.
20 // crbug.com/463611 for details!
21 const char kSyncListDevicesScope[] =
22 "https://www.googleapis.com/auth/chromesynclistdevices";
23 const char kChromeDomain[] = "http://www.chrome.com";
24 const char kListDevicesEndpoint[] = "http://127.0.0.1";
25 // Template for optional authorization header when using an OAuth access token.
26 const char kAuthorizationHeader[] = "Authorization: Bearer %s";
28 // In case of an error while fetching using the GaiaAuthFetcher, retry with
29 // exponential backoff. Try up to 9 times within 10 minutes.
30 const net::BackoffEntry::Policy kBackoffPolicy = {
31 // Number of initial errors (in sequence) to ignore before applying
32 // exponential back-off rules.
34 // Initial delay for exponential backoff in ms.
35 1000,
36 // Factor by which the waiting time will be multiplied.
38 // Fuzzing percentage. ex: 10% will spread requests randomly
39 // between 90%-100% of the calculated time.
40 0.1, // 10%
41 // Maximum amount of time we are willing to delay our request in ms.
42 1000 * 60 * 15, // 15 minutes.
43 // Time to keep an entry from being discarded even when it
44 // has no significant state, -1 to never discard.
45 -1,
46 // Don't use initial delay unless the last request was an error.
47 false,
50 const int kMaxFetcherRetries = 9;
52 } // namespace
54 DeviceActivityFetcher::DeviceActivityFetcher(
55 SigninClient* signin_client,
56 DeviceActivityFetcher::Observer* observer)
57 : fetcher_backoff_(&kBackoffPolicy),
58 fetcher_retries_(0),
59 signin_client_(signin_client),
60 observer_(observer) {
63 DeviceActivityFetcher::~DeviceActivityFetcher() {
66 void DeviceActivityFetcher::Start() {
67 fetcher_retries_ = 0;
68 login_hint_ = std::string();
69 StartFetchingListIdpSessions();
72 void DeviceActivityFetcher::Stop() {
73 if (gaia_auth_fetcher_)
74 gaia_auth_fetcher_->CancelRequest();
75 if (url_fetcher_)
76 url_fetcher_.reset();
79 void DeviceActivityFetcher::StartFetchingListIdpSessions() {
80 gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
81 this, GaiaConstants::kChromeSource,
82 signin_client_->GetURLRequestContext()));
83 gaia_auth_fetcher_->StartListIDPSessions(kSyncListDevicesScope,
84 kChromeDomain);
87 void DeviceActivityFetcher::StartFetchingGetTokenResponse() {
88 gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
89 this, GaiaConstants::kChromeSource,
90 signin_client_->GetURLRequestContext()));
91 gaia_auth_fetcher_->StartGetTokenResponse(kSyncListDevicesScope,
92 kChromeDomain, login_hint_);
95 void DeviceActivityFetcher::StartFetchingListDevices() {
96 // Call the Sync Endpoint.
97 url_fetcher_ = net::URLFetcher::Create(GURL(kListDevicesEndpoint),
98 net::URLFetcher::GET, this);
99 url_fetcher_->SetRequestContext(signin_client_->GetURLRequestContext());
100 if (!access_token_.empty()) {
101 url_fetcher_->SetExtraRequestHeaders(
102 base::StringPrintf(kAuthorizationHeader, access_token_.c_str()));
104 url_fetcher_->Start();
107 void DeviceActivityFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
108 // TODO(mlerman): Uncomment the code below once we have a working proto.
109 // Work done under crbug.com/463611
111 // std::string response_string;
112 // ListDevices list_devices;
114 // if (!source->GetStatus().is_success()) {
115 // VLOG(1) << "Failed to fetch listdevices response. Retrying.";
116 // if (++fetcher_retries_ < kMaxFetcherRetries) {
117 // fetcher_backoff_.InformOfRequest(false);
118 // fetcher_timer_.Start(
119 // FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(), this,
120 // &DeviceActivityFetcher::StartFetchingListDevices);
121 // return;
122 // } else {
123 // observer_->OnFetchDeviceActivityFailure();
124 // return;
125 // }
126 // }
128 // net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>(
129 // source->GetResponseCode());
130 // if (response_status == net::HTTP_BAD_REQUEST ||
131 // response_status == net::HTTP_UNAUTHORIZED) {
132 // // BAD_REQUEST indicates that the request was malformed.
133 // // UNAUTHORIZED indicates that security token didn't match the id.
134 // VLOG(1) << "No point retrying the checkin with status: "
135 // << response_status << ". Checkin failed.";
136 // CheckinRequestStatus status = response_status == net::HTTP_BAD_REQUEST ?
137 // HTTP_BAD_REQUEST : HTTP_UNAUTHORIZED;
138 // RecordCheckinStatusAndReportUMA(status, recorder_, false);
139 // callback_.Run(response_proto);
140 // return;
141 // }
143 // if (response_status != net::HTTP_OK ||
144 // !source->GetResponseAsString(&response_string) ||
145 // !list_devices.ParseFromString(response_string)) {
146 // LOG(ERROR) << "Failed to get list devices response. HTTP Status: "
147 // << response_status;
148 // if (++fetcher_retries_ < kMaxFetcherRetries) {
149 // fetcher_backoff_.InformOfRequest(false);
150 // fetcher_timer_.Start(
151 // FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(), this,
152 // &DeviceActivityFetcher::StartFetchingListDevices);
153 // return;
154 // } else {
155 // observer_->OnFetchDeviceActivityFailure();
156 // return;
157 // }
158 // }
160 std::vector<DeviceActivity> devices;
161 // TODO(mlerman): Fill |devices| from the proto in |source|.
163 // Call this last as OnFetchDeviceActivitySuccess will delete |this|.
164 observer_->OnFetchDeviceActivitySuccess(devices);
167 void DeviceActivityFetcher::OnListIdpSessionsSuccess(
168 const std::string& login_hint) {
169 fetcher_backoff_.InformOfRequest(true);
170 login_hint_ = login_hint;
171 access_token_ = std::string();
172 StartFetchingGetTokenResponse();
175 void DeviceActivityFetcher::OnListIdpSessionsError(
176 const GoogleServiceAuthError& error) {
177 if (++fetcher_retries_ < kMaxFetcherRetries && error.IsTransientError()) {
178 fetcher_backoff_.InformOfRequest(false);
179 fetcher_timer_.Start(FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
180 this,
181 &DeviceActivityFetcher::StartFetchingListIdpSessions);
182 return;
184 observer_->OnFetchDeviceActivityFailure();
187 void DeviceActivityFetcher::OnGetTokenResponseSuccess(
188 const ClientOAuthResult& result) {
189 fetcher_backoff_.InformOfRequest(true);
190 access_token_ = result.access_token;
191 StartFetchingListDevices();
194 void DeviceActivityFetcher::OnGetTokenResponseError(
195 const GoogleServiceAuthError& error) {
196 if (++fetcher_retries_ < kMaxFetcherRetries && error.IsTransientError()) {
197 fetcher_backoff_.InformOfRequest(false);
198 fetcher_timer_.Start(FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
199 this,
200 &DeviceActivityFetcher::StartFetchingGetTokenResponse);
201 return;
203 observer_->OnFetchDeviceActivityFailure();