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/message_loop/message_loop.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/rand_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/time/time.h"
12 #include "components/signin/core/browser/signin_client.h"
13 #include "components/signin/core/common/signin_pref_names.h"
14 #include "google_apis/gaia/gaia_constants.h"
15 #include "google_apis/gaia/gaia_urls.h"
16 #include "net/base/escape.h"
17 #include "net/url_request/url_request_context_getter.h"
19 RefreshTokenAnnotationRequest::RefreshTokenAnnotationRequest(
20 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
21 const std::string
& device_id
,
22 const std::string
& client_id
,
23 const base::Closure
& request_callback
)
24 : OAuth2TokenService::Consumer("refresh_token_annotation"),
25 request_context_getter_(request_context_getter
),
26 device_id_(device_id
),
27 client_id_(client_id
),
28 request_callback_(request_callback
) {
31 RefreshTokenAnnotationRequest::~RefreshTokenAnnotationRequest() {
32 DCHECK(CalledOnValidThread());
36 scoped_ptr
<RefreshTokenAnnotationRequest
>
37 RefreshTokenAnnotationRequest::SendIfNeeded(
38 PrefService
* pref_service
,
39 OAuth2TokenService
* token_service
,
40 SigninClient
* signin_client
,
41 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
42 const std::string
& account_id
,
43 const base::Closure
& request_callback
) {
44 scoped_ptr
<RefreshTokenAnnotationRequest
> request
;
45 if (ShouldSendNow(pref_service
)) {
46 request
.reset(new RefreshTokenAnnotationRequest(
47 request_context_getter
, signin_client
->GetSigninScopedDeviceId(),
48 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), request_callback
));
49 request
->RequestAccessToken(token_service
, account_id
);
51 return request
.Pass();
55 bool RefreshTokenAnnotationRequest::ShouldSendNow(PrefService
* pref_service
) {
56 bool should_send_now
= false;
57 // Read scheduled time from prefs.
58 base::Time scheduled_time
=
59 base::Time::FromInternalValue(pref_service
->GetInt64(
60 prefs::kGoogleServicesRefreshTokenAnnotateScheduledTime
));
62 if (!scheduled_time
.is_null() && scheduled_time
<= base::Time::Now()) {
63 DVLOG(2) << "Sending RefreshTokenAnnotationRequest";
64 should_send_now
= true;
65 // Reset scheduled_time so that it gets rescheduled later in the function.
66 scheduled_time
= base::Time();
69 if (scheduled_time
.is_null()) {
70 // Random delay in interval [0, 20] days.
71 double delay_in_sec
= base::RandDouble() * 20.0 * 24.0 * 3600.0;
73 base::Time::Now() + base::TimeDelta::FromSecondsD(delay_in_sec
);
74 DVLOG(2) << "RefreshTokenAnnotationRequest scheduled for "
76 pref_service
->SetInt64(
77 prefs::kGoogleServicesRefreshTokenAnnotateScheduledTime
,
78 scheduled_time
.ToInternalValue());
80 return should_send_now
;
83 void RefreshTokenAnnotationRequest::RequestAccessToken(
84 OAuth2TokenService
* token_service
,
85 const std::string
& account_id
) {
86 DCHECK(CalledOnValidThread());
87 OAuth2TokenService::ScopeSet scopes
;
88 scopes
.insert(GaiaConstants::kOAuth1LoginScope
);
89 access_token_request_
= token_service
->StartRequest(account_id
, scopes
, this);
92 void RefreshTokenAnnotationRequest::OnGetTokenSuccess(
93 const OAuth2TokenService::Request
* request
,
94 const std::string
& access_token
,
95 const base::Time
& expiration_time
) {
96 DCHECK(CalledOnValidThread());
97 DVLOG(2) << "Got access token";
98 Start(request_context_getter_
.get(), access_token
);
101 void RefreshTokenAnnotationRequest::OnGetTokenFailure(
102 const OAuth2TokenService::Request
* request
,
103 const GoogleServiceAuthError
& error
) {
104 DCHECK(CalledOnValidThread());
105 DVLOG(2) << "Failed to get access token";
106 base::MessageLoop::current()->PostTask(FROM_HERE
, request_callback_
);
107 request_callback_
.Reset();
110 GURL
RefreshTokenAnnotationRequest::CreateApiCallUrl() {
111 return GaiaUrls::GetInstance()->oauth2_issue_token_url();
114 std::string
RefreshTokenAnnotationRequest::CreateApiCallBody() {
115 // response_type=none means we don't want any token back, just record that
116 // this request was sent.
117 const char kIssueTokenBodyFormat
[] =
119 "&response_type=none"
123 "&device_type=chrome";
125 // It doesn't matter which scope to use for IssueToken request, any common
126 // scope would do. In this case I'm using "userinfo.email".
127 return base::StringPrintf(
128 kIssueTokenBodyFormat
,
129 net::EscapeUrlEncodedData(GaiaConstants::kGoogleUserInfoEmail
, true)
131 net::EscapeUrlEncodedData(client_id_
, true).c_str(),
132 net::EscapeUrlEncodedData(device_id_
, true).c_str());
135 void RefreshTokenAnnotationRequest::ProcessApiCallSuccess(
136 const net::URLFetcher
* source
) {
137 DCHECK(CalledOnValidThread());
138 DVLOG(2) << "Request succeeded";
139 base::MessageLoop::current()->PostTask(FROM_HERE
, request_callback_
);
140 request_callback_
.Reset();
143 void RefreshTokenAnnotationRequest::ProcessApiCallFailure(
144 const net::URLFetcher
* source
) {
145 DCHECK(CalledOnValidThread());
146 DVLOG(2) << "Request failed";
147 base::MessageLoop::current()->PostTask(FROM_HERE
, request_callback_
);
148 request_callback_
.Reset();