Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / signin / core / browser / refresh_token_annotation_request.cc
blob82b06f2da92c30cd474bee7f66871700637e0039
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.
5 #include "components/signin/core/browser/refresh_token_annotation_request.h"
7 #include "base/location.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/rand_util.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "components/signin/core/browser/signin_client.h"
16 #include "components/signin/core/common/signin_pref_names.h"
17 #include "google_apis/gaia/gaia_constants.h"
18 #include "google_apis/gaia/gaia_urls.h"
19 #include "net/base/escape.h"
20 #include "net/url_request/url_request_context_getter.h"
22 namespace {
24 void RecordRequestStatusHistogram(bool success) {
25 UMA_HISTOGRAM_BOOLEAN("Signin.RefreshTokenAnnotationRequest", success);
29 RefreshTokenAnnotationRequest::RefreshTokenAnnotationRequest(
30 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
31 const std::string& product_version,
32 const std::string& device_id,
33 const std::string& client_id,
34 const base::Closure& request_callback)
35 : OAuth2TokenService::Consumer("refresh_token_annotation"),
36 request_context_getter_(request_context_getter),
37 product_version_(product_version),
38 device_id_(device_id),
39 client_id_(client_id),
40 request_callback_(request_callback) {
43 RefreshTokenAnnotationRequest::~RefreshTokenAnnotationRequest() {
44 DCHECK(CalledOnValidThread());
47 // static
48 scoped_ptr<RefreshTokenAnnotationRequest>
49 RefreshTokenAnnotationRequest::SendIfNeeded(
50 PrefService* pref_service,
51 OAuth2TokenService* token_service,
52 SigninClient* signin_client,
53 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
54 const std::string& account_id,
55 const base::Closure& request_callback) {
56 scoped_ptr<RefreshTokenAnnotationRequest> request;
58 if (!ShouldSendNow(pref_service))
59 return request.Pass();
61 // Don't send request if device_id is disabled.
62 std::string device_id = signin_client->GetSigninScopedDeviceId();
63 if (device_id.empty())
64 return request.Pass();
66 request.reset(new RefreshTokenAnnotationRequest(
67 request_context_getter, signin_client->GetProductVersion(), device_id,
68 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), request_callback));
69 request->RequestAccessToken(token_service, account_id);
70 return request.Pass();
73 // static
74 bool RefreshTokenAnnotationRequest::ShouldSendNow(PrefService* pref_service) {
75 bool should_send_now = false;
76 // Read scheduled time from prefs.
77 base::Time scheduled_time =
78 base::Time::FromInternalValue(pref_service->GetInt64(
79 prefs::kGoogleServicesRefreshTokenAnnotateScheduledTime));
81 if (!scheduled_time.is_null() && scheduled_time <= base::Time::Now()) {
82 DVLOG(2) << "Sending RefreshTokenAnnotationRequest";
83 should_send_now = true;
84 // Reset scheduled_time so that it gets rescheduled later in the function.
85 scheduled_time = base::Time();
88 if (scheduled_time.is_null()) {
89 // Random delay in interval [0, 20] days.
90 double delay_in_sec = base::RandDouble() * 20.0 * 24.0 * 3600.0;
91 scheduled_time =
92 base::Time::Now() + base::TimeDelta::FromSecondsD(delay_in_sec);
93 DVLOG(2) << "RefreshTokenAnnotationRequest scheduled for "
94 << scheduled_time;
95 pref_service->SetInt64(
96 prefs::kGoogleServicesRefreshTokenAnnotateScheduledTime,
97 scheduled_time.ToInternalValue());
99 return should_send_now;
102 void RefreshTokenAnnotationRequest::RequestAccessToken(
103 OAuth2TokenService* token_service,
104 const std::string& account_id) {
105 DCHECK(CalledOnValidThread());
106 OAuth2TokenService::ScopeSet scopes;
107 scopes.insert(GaiaConstants::kOAuth1LoginScope);
108 access_token_request_ = token_service->StartRequest(account_id, scopes, this);
111 void RefreshTokenAnnotationRequest::OnGetTokenSuccess(
112 const OAuth2TokenService::Request* request,
113 const std::string& access_token,
114 const base::Time& expiration_time) {
115 DCHECK(CalledOnValidThread());
116 DVLOG(2) << "Got access token";
117 Start(request_context_getter_.get(), access_token);
120 void RefreshTokenAnnotationRequest::OnGetTokenFailure(
121 const OAuth2TokenService::Request* request,
122 const GoogleServiceAuthError& error) {
123 DCHECK(CalledOnValidThread());
124 DVLOG(2) << "Failed to get access token";
125 RecordRequestStatusHistogram(false);
126 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, request_callback_);
127 request_callback_.Reset();
130 GURL RefreshTokenAnnotationRequest::CreateApiCallUrl() {
131 return GaiaUrls::GetInstance()->oauth2_issue_token_url();
134 std::string RefreshTokenAnnotationRequest::CreateApiCallBody() {
135 // response_type=none means we don't want any token back, just record that
136 // this request was sent.
137 const char kIssueTokenBodyFormat[] =
138 "force=true"
139 "&response_type=none"
140 "&scope=%s"
141 "&client_id=%s"
142 "&device_id=%s"
143 "&device_type=chrome"
144 "&lib_ver=%s";
146 // It doesn't matter which scope to use for IssueToken request, any common
147 // scope would do. In this case I'm using "userinfo.email".
148 return base::StringPrintf(
149 kIssueTokenBodyFormat,
150 net::EscapeUrlEncodedData(GaiaConstants::kGoogleUserInfoEmail, true)
151 .c_str(),
152 net::EscapeUrlEncodedData(client_id_, true).c_str(),
153 net::EscapeUrlEncodedData(device_id_, true).c_str(),
154 net::EscapeUrlEncodedData(product_version_, true).c_str());
157 void RefreshTokenAnnotationRequest::ProcessApiCallSuccess(
158 const net::URLFetcher* source) {
159 DCHECK(CalledOnValidThread());
160 DVLOG(2) << "Request succeeded";
161 RecordRequestStatusHistogram(true);
162 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, request_callback_);
163 request_callback_.Reset();
166 void RefreshTokenAnnotationRequest::ProcessApiCallFailure(
167 const net::URLFetcher* source) {
168 DCHECK(CalledOnValidThread());
169 DVLOG(2) << "Request failed";
170 RecordRequestStatusHistogram(false);
171 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, request_callback_);
172 request_callback_.Reset();