Home | History | Annotate | Download | only in gaia
      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 
     15 OAuth2TokenServiceRequest::TokenServiceProvider::TokenServiceProvider() {
     16 }
     17 
     18 OAuth2TokenServiceRequest::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.
     37 class 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 
     88 OAuth2TokenServiceRequest::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 
     98 OAuth2TokenServiceRequest::Core::~Core() {
     99 }
    100 
    101 void 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 
    109 void 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 
    128 bool OAuth2TokenServiceRequest::Core::IsStopped() const {
    129   DCHECK(CalledOnValidThread());
    130   return owner_ == NULL;
    131 }
    132 
    133 base::SingleThreadTaskRunner*
    134 OAuth2TokenServiceRequest::Core::token_service_task_runner() {
    135   return token_service_task_runner_.get();
    136 }
    137 
    138 OAuth2TokenService* OAuth2TokenServiceRequest::Core::token_service() {
    139   DCHECK(token_service_task_runner_->BelongsToCurrentThread());
    140   return provider_->GetTokenService();
    141 }
    142 
    143 OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::Core::owner() {
    144   DCHECK(CalledOnValidThread());
    145   return owner_;
    146 }
    147 
    148 void OAuth2TokenServiceRequest::Core::DoNothing() {
    149   DCHECK(CalledOnValidThread());
    150 }
    151 
    152 namespace {
    153 
    154 // An implementation of Core for getting an access token.
    155 class 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 
    198 RequestCore::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 
    216 RequestCore::~RequestCore() {
    217 }
    218 
    219 void RequestCore::StartOnTokenServiceThread() {
    220   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
    221   request_ = token_service()->StartRequest(account_id_, scopes_, this).Pass();
    222 }
    223 
    224 void RequestCore::StopOnTokenServiceThread() {
    225   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
    226   request_.reset();
    227 }
    228 
    229 void 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 
    243 void 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 
    253 void 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 
    261 void 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.
    269 class 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 
    295 InvalidateCore::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 
    311 InvalidateCore::~InvalidateCore() {
    312 }
    313 
    314 void InvalidateCore::StartOnTokenServiceThread() {
    315   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
    316   token_service()->InvalidateToken(account_id_, scopes_, access_token_);
    317 }
    318 
    319 void InvalidateCore::StopOnTokenServiceThread() {
    320   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
    321   // Nothing to do.
    322 }
    323 
    324 }  // namespace
    325 
    326 // static
    327 scoped_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
    341 void 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 
    353 OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
    354   core_->Stop();
    355 }
    356 
    357 std::string OAuth2TokenServiceRequest::GetAccountId() const {
    358   return account_id_;
    359 }
    360 
    361 OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
    362     const std::string& account_id)
    363     : account_id_(account_id) {
    364   DCHECK(!account_id_.empty());
    365 }
    366 
    367 void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr<Core>& core) {
    368   DCHECK(core.get());
    369   core_ = core;
    370   core_->Start();
    371 }
    372