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 "google_apis/gaia/oauth2_token_service_request.h" 6 7#include "base/bind.h" 8#include "base/memory/ref_counted.h" 9#include "base/memory/scoped_ptr.h" 10#include "base/single_thread_task_runner.h" 11#include "base/thread_task_runner_handle.h" 12#include "google_apis/gaia/google_service_auth_error.h" 13#include "google_apis/gaia/oauth2_access_token_consumer.h" 14 15OAuth2TokenServiceRequest::TokenServiceProvider::TokenServiceProvider() { 16} 17 18OAuth2TokenServiceRequest::TokenServiceProvider::~TokenServiceProvider() { 19} 20 21// Core serves as the base class for OAuth2TokenService operations. Each 22// operation should be modeled as a derived type. 23// 24// Core is used like this: 25// 26// 1. Constructed on owner thread. 27// 28// 2. Start() is called on owner thread, which calls StartOnTokenServiceThread() 29// on token service thread. 30// 31// 3. Request is executed. 32// 33// 4. Stop() is called on owner thread, which calls StopOnTokenServiceThread() 34// on token service thread. 35// 36// 5. Core is destroyed on owner thread. 37class OAuth2TokenServiceRequest::Core 38 : public base::NonThreadSafe, 39 public base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core> { 40 public: 41 // Note the thread where an instance of Core is constructed is referred to as 42 // the "owner thread" here. 43 Core(OAuth2TokenServiceRequest* owner, 44 const scoped_refptr<TokenServiceProvider>& provider); 45 46 // Starts the core. Must be called on the owner thread. 47 void Start(); 48 49 // Stops the core. Must be called on the owner thread. 50 void Stop(); 51 52 // Returns true if this object has been stopped. Must be called on the owner 53 // thread. 54 bool IsStopped() const; 55 56 protected: 57 // Core must be destroyed on the owner thread. If data members must be 58 // cleaned up or destroyed on the token service thread, do so in the 59 // StopOnTokenServiceThread method. 60 virtual ~Core(); 61 62 // Called on the token service thread. 63 virtual void StartOnTokenServiceThread() = 0; 64 65 // Called on the token service thread. 66 virtual void StopOnTokenServiceThread() = 0; 67 68 base::SingleThreadTaskRunner* token_service_task_runner(); 69 OAuth2TokenService* token_service(); 70 OAuth2TokenServiceRequest* owner(); 71 72 private: 73 friend class base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>; 74 75 void DoNothing(); 76 77 scoped_refptr<base::SingleThreadTaskRunner> token_service_task_runner_; 78 OAuth2TokenServiceRequest* owner_; 79 80 // Clear on owner thread. OAuth2TokenServiceRequest promises to clear its 81 // last reference to TokenServiceProvider on the owner thread so the caller 82 // can ensure it is destroyed on the owner thread if desired. 83 scoped_refptr<TokenServiceProvider> provider_; 84 85 DISALLOW_COPY_AND_ASSIGN(Core); 86}; 87 88OAuth2TokenServiceRequest::Core::Core( 89 OAuth2TokenServiceRequest* owner, 90 const scoped_refptr<TokenServiceProvider>& provider) 91 : owner_(owner), provider_(provider) { 92 DCHECK(owner_); 93 DCHECK(provider_.get()); 94 token_service_task_runner_ = provider_->GetTokenServiceTaskRunner(); 95 DCHECK(token_service_task_runner_.get()); 96} 97 98OAuth2TokenServiceRequest::Core::~Core() { 99} 100 101void OAuth2TokenServiceRequest::Core::Start() { 102 DCHECK(CalledOnValidThread()); 103 token_service_task_runner_->PostTask( 104 FROM_HERE, 105 base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread, 106 this)); 107} 108 109void OAuth2TokenServiceRequest::Core::Stop() { 110 DCHECK(CalledOnValidThread()); 111 DCHECK(!IsStopped()); 112 113 // Detaches |owner_| from this instance so |owner_| will be called back only 114 // if |Stop()| has never been called. 115 owner_ = NULL; 116 117 // We are stopping and will likely be destroyed soon. Use a reply closure 118 // (DoNothing) to retain "this" and ensure we are destroyed in the owner 119 // thread, not the task runner thread. PostTaskAndReply guarantees that the 120 // reply closure will execute after StopOnTokenServiceThread has completed. 121 token_service_task_runner_->PostTaskAndReply( 122 FROM_HERE, 123 base::Bind(&OAuth2TokenServiceRequest::Core::StopOnTokenServiceThread, 124 this), 125 base::Bind(&OAuth2TokenServiceRequest::Core::DoNothing, this)); 126} 127 128bool OAuth2TokenServiceRequest::Core::IsStopped() const { 129 DCHECK(CalledOnValidThread()); 130 return owner_ == NULL; 131} 132 133base::SingleThreadTaskRunner* 134OAuth2TokenServiceRequest::Core::token_service_task_runner() { 135 return token_service_task_runner_.get(); 136} 137 138OAuth2TokenService* OAuth2TokenServiceRequest::Core::token_service() { 139 DCHECK(token_service_task_runner_->BelongsToCurrentThread()); 140 return provider_->GetTokenService(); 141} 142 143OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::Core::owner() { 144 DCHECK(CalledOnValidThread()); 145 return owner_; 146} 147 148void OAuth2TokenServiceRequest::Core::DoNothing() { 149 DCHECK(CalledOnValidThread()); 150} 151 152namespace { 153 154// An implementation of Core for getting an access token. 155class RequestCore : public OAuth2TokenServiceRequest::Core, 156 public OAuth2TokenService::Consumer { 157 public: 158 RequestCore(OAuth2TokenServiceRequest* owner, 159 const scoped_refptr< 160 OAuth2TokenServiceRequest::TokenServiceProvider>& provider, 161 OAuth2TokenService::Consumer* consumer, 162 const std::string& account_id, 163 const OAuth2TokenService::ScopeSet& scopes); 164 165 // OAuth2TokenService::Consumer. Must be called on the token service thread. 166 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request, 167 const std::string& access_token, 168 const base::Time& expiration_time) OVERRIDE; 169 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request, 170 const GoogleServiceAuthError& error) OVERRIDE; 171 172 private: 173 friend class base::RefCountedThreadSafe<RequestCore>; 174 175 // Must be destroyed on the owner thread. 176 virtual ~RequestCore(); 177 178 // Core implementation. 179 virtual void StartOnTokenServiceThread() OVERRIDE; 180 virtual void StopOnTokenServiceThread() OVERRIDE; 181 182 void InformOwnerOnGetTokenSuccess(std::string access_token, 183 base::Time expiration_time); 184 void InformOwnerOnGetTokenFailure(GoogleServiceAuthError error); 185 186 scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner_; 187 OAuth2TokenService::Consumer* const consumer_; 188 std::string account_id_; 189 OAuth2TokenService::ScopeSet scopes_; 190 191 // OAuth2TokenService request for fetching OAuth2 access token; it should be 192 // created, reset and accessed only on the token service thread. 193 scoped_ptr<OAuth2TokenService::Request> request_; 194 195 DISALLOW_COPY_AND_ASSIGN(RequestCore); 196}; 197 198RequestCore::RequestCore( 199 OAuth2TokenServiceRequest* owner, 200 const scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>& 201 provider, 202 OAuth2TokenService::Consumer* consumer, 203 const std::string& account_id, 204 const OAuth2TokenService::ScopeSet& scopes) 205 : OAuth2TokenServiceRequest::Core(owner, provider), 206 OAuth2TokenService::Consumer("oauth2_token_service"), 207 owner_task_runner_(base::ThreadTaskRunnerHandle::Get()), 208 consumer_(consumer), 209 account_id_(account_id), 210 scopes_(scopes) { 211 DCHECK(consumer_); 212 DCHECK(!account_id_.empty()); 213 DCHECK(!scopes_.empty()); 214} 215 216RequestCore::~RequestCore() { 217} 218 219void RequestCore::StartOnTokenServiceThread() { 220 DCHECK(token_service_task_runner()->BelongsToCurrentThread()); 221 request_ = token_service()->StartRequest(account_id_, scopes_, this).Pass(); 222} 223 224void RequestCore::StopOnTokenServiceThread() { 225 DCHECK(token_service_task_runner()->BelongsToCurrentThread()); 226 request_.reset(); 227} 228 229void RequestCore::OnGetTokenSuccess(const OAuth2TokenService::Request* request, 230 const std::string& access_token, 231 const base::Time& expiration_time) { 232 DCHECK(token_service_task_runner()->BelongsToCurrentThread()); 233 DCHECK_EQ(request_.get(), request); 234 owner_task_runner_->PostTask( 235 FROM_HERE, 236 base::Bind(&RequestCore::InformOwnerOnGetTokenSuccess, 237 this, 238 access_token, 239 expiration_time)); 240 request_.reset(); 241} 242 243void RequestCore::OnGetTokenFailure(const OAuth2TokenService::Request* request, 244 const GoogleServiceAuthError& error) { 245 DCHECK(token_service_task_runner()->BelongsToCurrentThread()); 246 DCHECK_EQ(request_.get(), request); 247 owner_task_runner_->PostTask( 248 FROM_HERE, 249 base::Bind(&RequestCore::InformOwnerOnGetTokenFailure, this, error)); 250 request_.reset(); 251} 252 253void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token, 254 base::Time expiration_time) { 255 DCHECK(CalledOnValidThread()); 256 if (!IsStopped()) { 257 consumer_->OnGetTokenSuccess(owner(), access_token, expiration_time); 258 } 259} 260 261void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error) { 262 DCHECK(CalledOnValidThread()); 263 if (!IsStopped()) { 264 consumer_->OnGetTokenFailure(owner(), error); 265 } 266} 267 268// An implementation of Core for invalidating an access token. 269class InvalidateCore : public OAuth2TokenServiceRequest::Core { 270 public: 271 InvalidateCore(OAuth2TokenServiceRequest* owner, 272 const scoped_refptr< 273 OAuth2TokenServiceRequest::TokenServiceProvider>& provider, 274 const std::string& access_token, 275 const std::string& account_id, 276 const OAuth2TokenService::ScopeSet& scopes); 277 278 private: 279 friend class base::RefCountedThreadSafe<InvalidateCore>; 280 281 // Must be destroyed on the owner thread. 282 virtual ~InvalidateCore(); 283 284 // Core implementation. 285 virtual void StartOnTokenServiceThread() OVERRIDE; 286 virtual void StopOnTokenServiceThread() OVERRIDE; 287 288 std::string access_token_; 289 std::string account_id_; 290 OAuth2TokenService::ScopeSet scopes_; 291 292 DISALLOW_COPY_AND_ASSIGN(InvalidateCore); 293}; 294 295InvalidateCore::InvalidateCore( 296 OAuth2TokenServiceRequest* owner, 297 const scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>& 298 provider, 299 const std::string& access_token, 300 const std::string& account_id, 301 const OAuth2TokenService::ScopeSet& scopes) 302 : OAuth2TokenServiceRequest::Core(owner, provider), 303 access_token_(access_token), 304 account_id_(account_id), 305 scopes_(scopes) { 306 DCHECK(!access_token_.empty()); 307 DCHECK(!account_id_.empty()); 308 DCHECK(!scopes.empty()); 309} 310 311InvalidateCore::~InvalidateCore() { 312} 313 314void InvalidateCore::StartOnTokenServiceThread() { 315 DCHECK(token_service_task_runner()->BelongsToCurrentThread()); 316 token_service()->InvalidateToken(account_id_, scopes_, access_token_); 317} 318 319void InvalidateCore::StopOnTokenServiceThread() { 320 DCHECK(token_service_task_runner()->BelongsToCurrentThread()); 321 // Nothing to do. 322} 323 324} // namespace 325 326// static 327scoped_ptr<OAuth2TokenServiceRequest> OAuth2TokenServiceRequest::CreateAndStart( 328 const scoped_refptr<TokenServiceProvider>& provider, 329 const std::string& account_id, 330 const OAuth2TokenService::ScopeSet& scopes, 331 OAuth2TokenService::Consumer* consumer) { 332 scoped_ptr<OAuth2TokenServiceRequest> request( 333 new OAuth2TokenServiceRequest(account_id)); 334 scoped_refptr<Core> core( 335 new RequestCore(request.get(), provider, consumer, account_id, scopes)); 336 request->StartWithCore(core); 337 return request.Pass(); 338} 339 340// static 341void OAuth2TokenServiceRequest::InvalidateToken( 342 const scoped_refptr<TokenServiceProvider>& provider, 343 const std::string& account_id, 344 const OAuth2TokenService::ScopeSet& scopes, 345 const std::string& access_token) { 346 scoped_ptr<OAuth2TokenServiceRequest> request( 347 new OAuth2TokenServiceRequest(account_id)); 348 scoped_refptr<Core> core(new InvalidateCore( 349 request.get(), provider, access_token, account_id, scopes)); 350 request->StartWithCore(core); 351} 352 353OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() { 354 core_->Stop(); 355} 356 357std::string OAuth2TokenServiceRequest::GetAccountId() const { 358 return account_id_; 359} 360 361OAuth2TokenServiceRequest::OAuth2TokenServiceRequest( 362 const std::string& account_id) 363 : account_id_(account_id) { 364 DCHECK(!account_id_.empty()); 365} 366 367void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr<Core>& core) { 368 DCHECK(core.get()); 369 core_ = core; 370 core_->Start(); 371} 372