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 "google_apis/gaia/oauth2_token_service_request.h"
8 #include "base/location.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "google_apis/gaia/google_service_auth_error.h"
14 #include "google_apis/gaia/oauth2_access_token_consumer.h"
16 OAuth2TokenServiceRequest::TokenServiceProvider::TokenServiceProvider() {
19 OAuth2TokenServiceRequest::TokenServiceProvider::~TokenServiceProvider() {
22 // Core serves as the base class for OAuth2TokenService operations. Each
23 // operation should be modeled as a derived type.
25 // Core is used like this:
27 // 1. Constructed on owner thread.
29 // 2. Start() is called on owner thread, which calls StartOnTokenServiceThread()
30 // on token service thread.
32 // 3. Request is executed.
34 // 4. Stop() is called on owner thread, which calls StopOnTokenServiceThread()
35 // on token service thread.
37 // 5. Core is destroyed on owner thread.
38 class OAuth2TokenServiceRequest::Core
39 : public base::NonThreadSafe
,
40 public base::RefCountedThreadSafe
<OAuth2TokenServiceRequest::Core
> {
42 // Note the thread where an instance of Core is constructed is referred to as
43 // the "owner thread" here.
44 Core(OAuth2TokenServiceRequest
* owner
,
45 const scoped_refptr
<TokenServiceProvider
>& provider
);
47 // Starts the core. Must be called on the owner thread.
50 // Stops the core. Must be called on the owner thread.
53 // Returns true if this object has been stopped. Must be called on the owner
55 bool IsStopped() const;
58 // Core must be destroyed on the owner thread. If data members must be
59 // cleaned up or destroyed on the token service thread, do so in the
60 // StopOnTokenServiceThread method.
63 // Called on the token service thread.
64 virtual void StartOnTokenServiceThread() = 0;
66 // Called on the token service thread.
67 virtual void StopOnTokenServiceThread() = 0;
69 base::SingleThreadTaskRunner
* token_service_task_runner();
70 OAuth2TokenService
* token_service();
71 OAuth2TokenServiceRequest
* owner();
74 friend class base::RefCountedThreadSafe
<OAuth2TokenServiceRequest::Core
>;
78 scoped_refptr
<base::SingleThreadTaskRunner
> token_service_task_runner_
;
79 OAuth2TokenServiceRequest
* owner_
;
81 // Clear on owner thread. OAuth2TokenServiceRequest promises to clear its
82 // last reference to TokenServiceProvider on the owner thread so the caller
83 // can ensure it is destroyed on the owner thread if desired.
84 scoped_refptr
<TokenServiceProvider
> provider_
;
86 DISALLOW_COPY_AND_ASSIGN(Core
);
89 OAuth2TokenServiceRequest::Core::Core(
90 OAuth2TokenServiceRequest
* owner
,
91 const scoped_refptr
<TokenServiceProvider
>& provider
)
92 : owner_(owner
), provider_(provider
) {
94 DCHECK(provider_
.get());
95 token_service_task_runner_
= provider_
->GetTokenServiceTaskRunner();
96 DCHECK(token_service_task_runner_
.get());
99 OAuth2TokenServiceRequest::Core::~Core() {
102 void OAuth2TokenServiceRequest::Core::Start() {
103 DCHECK(CalledOnValidThread());
104 token_service_task_runner_
->PostTask(
106 base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread
,
110 void OAuth2TokenServiceRequest::Core::Stop() {
111 DCHECK(CalledOnValidThread());
112 DCHECK(!IsStopped());
114 // Detaches |owner_| from this instance so |owner_| will be called back only
115 // if |Stop()| has never been called.
118 // We are stopping and will likely be destroyed soon. Use a reply closure
119 // (DoNothing) to retain "this" and ensure we are destroyed in the owner
120 // thread, not the task runner thread. PostTaskAndReply guarantees that the
121 // reply closure will execute after StopOnTokenServiceThread has completed.
122 token_service_task_runner_
->PostTaskAndReply(
124 base::Bind(&OAuth2TokenServiceRequest::Core::StopOnTokenServiceThread
,
126 base::Bind(&OAuth2TokenServiceRequest::Core::DoNothing
, this));
129 bool OAuth2TokenServiceRequest::Core::IsStopped() const {
130 DCHECK(CalledOnValidThread());
131 return owner_
== NULL
;
134 base::SingleThreadTaskRunner
*
135 OAuth2TokenServiceRequest::Core::token_service_task_runner() {
136 return token_service_task_runner_
.get();
139 OAuth2TokenService
* OAuth2TokenServiceRequest::Core::token_service() {
140 DCHECK(token_service_task_runner_
->BelongsToCurrentThread());
141 return provider_
->GetTokenService();
144 OAuth2TokenServiceRequest
* OAuth2TokenServiceRequest::Core::owner() {
145 DCHECK(CalledOnValidThread());
149 void OAuth2TokenServiceRequest::Core::DoNothing() {
150 DCHECK(CalledOnValidThread());
155 // An implementation of Core for getting an access token.
156 class RequestCore
: public OAuth2TokenServiceRequest::Core
,
157 public OAuth2TokenService::Consumer
{
159 RequestCore(OAuth2TokenServiceRequest
* owner
,
161 OAuth2TokenServiceRequest::TokenServiceProvider
>& provider
,
162 OAuth2TokenService::Consumer
* consumer
,
163 const std::string
& account_id
,
164 const OAuth2TokenService::ScopeSet
& scopes
);
166 // OAuth2TokenService::Consumer. Must be called on the token service thread.
167 void OnGetTokenSuccess(const OAuth2TokenService::Request
* request
,
168 const std::string
& access_token
,
169 const base::Time
& expiration_time
) override
;
170 void OnGetTokenFailure(const OAuth2TokenService::Request
* request
,
171 const GoogleServiceAuthError
& error
) override
;
174 friend class base::RefCountedThreadSafe
<RequestCore
>;
176 // Must be destroyed on the owner thread.
177 ~RequestCore() override
;
179 // Core implementation.
180 void StartOnTokenServiceThread() override
;
181 void StopOnTokenServiceThread() override
;
183 void InformOwnerOnGetTokenSuccess(std::string access_token
,
184 base::Time expiration_time
);
185 void InformOwnerOnGetTokenFailure(GoogleServiceAuthError error
);
187 scoped_refptr
<base::SingleThreadTaskRunner
> owner_task_runner_
;
188 OAuth2TokenService::Consumer
* const consumer_
;
189 std::string account_id_
;
190 OAuth2TokenService::ScopeSet scopes_
;
192 // OAuth2TokenService request for fetching OAuth2 access token; it should be
193 // created, reset and accessed only on the token service thread.
194 scoped_ptr
<OAuth2TokenService::Request
> request_
;
196 DISALLOW_COPY_AND_ASSIGN(RequestCore
);
199 RequestCore::RequestCore(
200 OAuth2TokenServiceRequest
* owner
,
201 const scoped_refptr
<OAuth2TokenServiceRequest::TokenServiceProvider
>&
203 OAuth2TokenService::Consumer
* consumer
,
204 const std::string
& account_id
,
205 const OAuth2TokenService::ScopeSet
& scopes
)
206 : OAuth2TokenServiceRequest::Core(owner
, provider
),
207 OAuth2TokenService::Consumer("oauth2_token_service"),
208 owner_task_runner_(base::ThreadTaskRunnerHandle::Get()),
210 account_id_(account_id
),
213 DCHECK(!account_id_
.empty());
214 DCHECK(!scopes_
.empty());
217 RequestCore::~RequestCore() {
220 void RequestCore::StartOnTokenServiceThread() {
221 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
222 request_
= token_service()->StartRequest(account_id_
, scopes_
, this).Pass();
225 void RequestCore::StopOnTokenServiceThread() {
226 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
230 void RequestCore::OnGetTokenSuccess(const OAuth2TokenService::Request
* request
,
231 const std::string
& access_token
,
232 const base::Time
& expiration_time
) {
233 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
234 DCHECK_EQ(request_
.get(), request
);
235 owner_task_runner_
->PostTask(
237 base::Bind(&RequestCore::InformOwnerOnGetTokenSuccess
,
244 void RequestCore::OnGetTokenFailure(const OAuth2TokenService::Request
* request
,
245 const GoogleServiceAuthError
& error
) {
246 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
247 DCHECK_EQ(request_
.get(), request
);
248 owner_task_runner_
->PostTask(
250 base::Bind(&RequestCore::InformOwnerOnGetTokenFailure
, this, error
));
254 void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token
,
255 base::Time expiration_time
) {
256 DCHECK(CalledOnValidThread());
258 consumer_
->OnGetTokenSuccess(owner(), access_token
, expiration_time
);
262 void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error
) {
263 DCHECK(CalledOnValidThread());
265 consumer_
->OnGetTokenFailure(owner(), error
);
269 // An implementation of Core for invalidating an access token.
270 class InvalidateCore
: public OAuth2TokenServiceRequest::Core
{
272 InvalidateCore(OAuth2TokenServiceRequest
* owner
,
274 OAuth2TokenServiceRequest::TokenServiceProvider
>& provider
,
275 const std::string
& access_token
,
276 const std::string
& account_id
,
277 const OAuth2TokenService::ScopeSet
& scopes
);
280 friend class base::RefCountedThreadSafe
<InvalidateCore
>;
282 // Must be destroyed on the owner thread.
283 ~InvalidateCore() override
;
285 // Core implementation.
286 void StartOnTokenServiceThread() override
;
287 void StopOnTokenServiceThread() override
;
289 std::string access_token_
;
290 std::string account_id_
;
291 OAuth2TokenService::ScopeSet scopes_
;
293 DISALLOW_COPY_AND_ASSIGN(InvalidateCore
);
296 InvalidateCore::InvalidateCore(
297 OAuth2TokenServiceRequest
* owner
,
298 const scoped_refptr
<OAuth2TokenServiceRequest::TokenServiceProvider
>&
300 const std::string
& access_token
,
301 const std::string
& account_id
,
302 const OAuth2TokenService::ScopeSet
& scopes
)
303 : OAuth2TokenServiceRequest::Core(owner
, provider
),
304 access_token_(access_token
),
305 account_id_(account_id
),
307 DCHECK(!access_token_
.empty());
308 DCHECK(!account_id_
.empty());
309 DCHECK(!scopes
.empty());
312 InvalidateCore::~InvalidateCore() {
315 void InvalidateCore::StartOnTokenServiceThread() {
316 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
317 token_service()->InvalidateAccessToken(account_id_
, scopes_
, access_token_
);
320 void InvalidateCore::StopOnTokenServiceThread() {
321 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
328 scoped_ptr
<OAuth2TokenServiceRequest
> OAuth2TokenServiceRequest::CreateAndStart(
329 const scoped_refptr
<TokenServiceProvider
>& provider
,
330 const std::string
& account_id
,
331 const OAuth2TokenService::ScopeSet
& scopes
,
332 OAuth2TokenService::Consumer
* consumer
) {
333 scoped_ptr
<OAuth2TokenServiceRequest
> request(
334 new OAuth2TokenServiceRequest(account_id
));
335 scoped_refptr
<Core
> core(
336 new RequestCore(request
.get(), provider
, consumer
, account_id
, scopes
));
337 request
->StartWithCore(core
);
338 return request
.Pass();
342 void OAuth2TokenServiceRequest::InvalidateToken(
343 const scoped_refptr
<TokenServiceProvider
>& provider
,
344 const std::string
& account_id
,
345 const OAuth2TokenService::ScopeSet
& scopes
,
346 const std::string
& access_token
) {
347 scoped_ptr
<OAuth2TokenServiceRequest
> request(
348 new OAuth2TokenServiceRequest(account_id
));
349 scoped_refptr
<Core
> core(new InvalidateCore(
350 request
.get(), provider
, access_token
, account_id
, scopes
));
351 request
->StartWithCore(core
);
354 OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
358 std::string
OAuth2TokenServiceRequest::GetAccountId() const {
362 OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
363 const std::string
& account_id
)
364 : account_id_(account_id
) {
365 DCHECK(!account_id_
.empty());
368 void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr
<Core
>& core
) {