• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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.h"
6 
7 #include <vector>
8 
9 #include "base/bind.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/rand_util.h"
13 #include "base/stl_util.h"
14 #include "base/time/time.h"
15 #include "base/timer/timer.h"
16 #include "google_apis/gaia/gaia_urls.h"
17 #include "google_apis/gaia/google_service_auth_error.h"
18 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
19 #include "net/url_request/url_request_context_getter.h"
20 
21 int OAuth2TokenService::max_fetch_retry_num_ = 5;
22 
RequestParameters(const std::string & client_id,const std::string & account_id,const ScopeSet & scopes)23 OAuth2TokenService::RequestParameters::RequestParameters(
24     const std::string& client_id,
25     const std::string& account_id,
26     const ScopeSet& scopes)
27     : client_id(client_id),
28       account_id(account_id),
29       scopes(scopes) {
30 }
31 
~RequestParameters()32 OAuth2TokenService::RequestParameters::~RequestParameters() {
33 }
34 
operator <(const RequestParameters & p) const35 bool OAuth2TokenService::RequestParameters::operator<(
36     const RequestParameters& p) const {
37   if (client_id < p.client_id)
38     return true;
39   else if (p.client_id < client_id)
40     return false;
41 
42   if (account_id < p.account_id)
43     return true;
44   else if (p.account_id < account_id)
45     return false;
46 
47   return scopes < p.scopes;
48 }
49 
RequestImpl(const std::string & account_id,OAuth2TokenService::Consumer * consumer)50 OAuth2TokenService::RequestImpl::RequestImpl(
51     const std::string& account_id,
52     OAuth2TokenService::Consumer* consumer)
53     : account_id_(account_id),
54       consumer_(consumer) {
55 }
56 
~RequestImpl()57 OAuth2TokenService::RequestImpl::~RequestImpl() {
58   DCHECK(CalledOnValidThread());
59 }
60 
GetAccountId() const61 std::string OAuth2TokenService::RequestImpl::GetAccountId() const {
62   return account_id_;
63 }
64 
GetConsumerId() const65 std::string OAuth2TokenService::RequestImpl::GetConsumerId() const {
66   return consumer_->id();
67 }
68 
InformConsumer(const GoogleServiceAuthError & error,const std::string & access_token,const base::Time & expiration_date)69 void OAuth2TokenService::RequestImpl::InformConsumer(
70     const GoogleServiceAuthError& error,
71     const std::string& access_token,
72     const base::Time& expiration_date) {
73   DCHECK(CalledOnValidThread());
74   if (error.state() == GoogleServiceAuthError::NONE)
75     consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
76   else
77     consumer_->OnGetTokenFailure(this, error);
78 }
79 
ScopedBacthChange(OAuth2TokenService * token_service)80 OAuth2TokenService::ScopedBacthChange::ScopedBacthChange(
81     OAuth2TokenService* token_service) : token_service_(token_service) {
82   DCHECK(token_service_);
83   token_service_->StartBatchChanges();
84 }
85 
~ScopedBacthChange()86 OAuth2TokenService::ScopedBacthChange::~ScopedBacthChange() {
87   token_service_->EndBatchChanges();
88 }
89 
90 // Class that fetches an OAuth2 access token for a given account id and set of
91 // scopes.
92 //
93 // It aims to meet OAuth2TokenService's requirements on token fetching. Retry
94 // mechanism is used to handle failures.
95 //
96 // To use this class, call CreateAndStart() to create and start a Fetcher.
97 //
98 // The Fetcher will call back the service by calling
99 // OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is
100 // not destructed before it completes fetching; if the Fetcher is destructed
101 // before it completes fetching, the service will never be called back. The
102 // Fetcher destructs itself after calling back the service when finishes
103 // fetching.
104 //
105 // Requests that are waiting for the fetching results of this Fetcher can be
106 // added to the Fetcher by calling
107 // OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher
108 // completes fetching.
109 //
110 // The waiting requests are taken as weak pointers and they can be deleted.
111 // The waiting requests will be called back with fetching results if they are
112 // not deleted
113 // - when the Fetcher completes fetching, if the Fetcher is not destructed
114 //   before it completes fetching, or
115 // - when the Fetcher is destructed if the Fetcher is destructed before it
116 //   completes fetching (in this case, the waiting requests will be called
117 //   back with error).
118 class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
119  public:
120   // Creates a Fetcher and starts fetching an OAuth2 access token for
121   // |account_id| and |scopes| in the request context obtained by |getter|.
122   // The given |oauth2_token_service| will be informed when fetching is done.
123   static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service,
124                                  const std::string& account_id,
125                                  net::URLRequestContextGetter* getter,
126                                  const std::string& client_id,
127                                  const std::string& client_secret,
128                                  const ScopeSet& scopes,
129                                  base::WeakPtr<RequestImpl> waiting_request);
130   virtual ~Fetcher();
131 
132   // Add a request that is waiting for the result of this Fetcher.
133   void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request);
134 
135   // Returns count of waiting requests.
136   size_t GetWaitingRequestCount() const;
137 
waiting_requests() const138   const std::vector<base::WeakPtr<RequestImpl> >& waiting_requests() const {
139     return waiting_requests_;
140   }
141 
142   void Cancel();
143 
144   const ScopeSet& GetScopeSet() const;
145   const std::string& GetClientId() const;
146   const std::string& GetAccountId() const;
147 
148   // The error result from this fetcher.
error() const149   const GoogleServiceAuthError& error() const { return error_; }
150 
151  protected:
152    // OAuth2AccessTokenConsumer
153   virtual void OnGetTokenSuccess(const std::string& access_token,
154                                  const base::Time& expiration_date) OVERRIDE;
155   virtual void OnGetTokenFailure(
156       const GoogleServiceAuthError& error) OVERRIDE;
157 
158  private:
159   Fetcher(OAuth2TokenService* oauth2_token_service,
160           const std::string& account_id,
161           net::URLRequestContextGetter* getter,
162           const std::string& client_id,
163           const std::string& client_secret,
164           const OAuth2TokenService::ScopeSet& scopes,
165           base::WeakPtr<RequestImpl> waiting_request);
166   void Start();
167   void InformWaitingRequests();
168   void InformWaitingRequestsAndDelete();
169   static bool ShouldRetry(const GoogleServiceAuthError& error);
170   int64 ComputeExponentialBackOffMilliseconds(int retry_num);
171 
172   // |oauth2_token_service_| remains valid for the life of this Fetcher, since
173   // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
174   // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
175   // (whichever comes first).
176   OAuth2TokenService* const oauth2_token_service_;
177   scoped_refptr<net::URLRequestContextGetter> getter_;
178   const std::string account_id_;
179   const ScopeSet scopes_;
180   std::vector<base::WeakPtr<RequestImpl> > waiting_requests_;
181 
182   int retry_number_;
183   base::OneShotTimer<Fetcher> retry_timer_;
184   scoped_ptr<OAuth2AccessTokenFetcher> fetcher_;
185 
186   // Variables that store fetch results.
187   // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle
188   // destruction.
189   GoogleServiceAuthError error_;
190   std::string access_token_;
191   base::Time expiration_date_;
192 
193   // OAuth2 client id and secret.
194   std::string client_id_;
195   std::string client_secret_;
196 
197   DISALLOW_COPY_AND_ASSIGN(Fetcher);
198 };
199 
200 // static
CreateAndStart(OAuth2TokenService * oauth2_token_service,const std::string & account_id,net::URLRequestContextGetter * getter,const std::string & client_id,const std::string & client_secret,const OAuth2TokenService::ScopeSet & scopes,base::WeakPtr<RequestImpl> waiting_request)201 OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart(
202     OAuth2TokenService* oauth2_token_service,
203     const std::string& account_id,
204     net::URLRequestContextGetter* getter,
205     const std::string& client_id,
206     const std::string& client_secret,
207     const OAuth2TokenService::ScopeSet& scopes,
208     base::WeakPtr<RequestImpl> waiting_request) {
209   OAuth2TokenService::Fetcher* fetcher = new Fetcher(
210       oauth2_token_service,
211       account_id,
212       getter,
213       client_id,
214       client_secret,
215       scopes,
216       waiting_request);
217   fetcher->Start();
218   return fetcher;
219 }
220 
Fetcher(OAuth2TokenService * oauth2_token_service,const std::string & account_id,net::URLRequestContextGetter * getter,const std::string & client_id,const std::string & client_secret,const OAuth2TokenService::ScopeSet & scopes,base::WeakPtr<RequestImpl> waiting_request)221 OAuth2TokenService::Fetcher::Fetcher(
222     OAuth2TokenService* oauth2_token_service,
223     const std::string& account_id,
224     net::URLRequestContextGetter* getter,
225     const std::string& client_id,
226     const std::string& client_secret,
227     const OAuth2TokenService::ScopeSet& scopes,
228     base::WeakPtr<RequestImpl> waiting_request)
229     : oauth2_token_service_(oauth2_token_service),
230       getter_(getter),
231       account_id_(account_id),
232       scopes_(scopes),
233       retry_number_(0),
234       error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
235       client_id_(client_id),
236       client_secret_(client_secret) {
237   DCHECK(oauth2_token_service_);
238   waiting_requests_.push_back(waiting_request);
239 }
240 
~Fetcher()241 OAuth2TokenService::Fetcher::~Fetcher() {
242   // Inform the waiting requests if it has not done so.
243   if (waiting_requests_.size())
244     InformWaitingRequests();
245 }
246 
Start()247 void OAuth2TokenService::Fetcher::Start() {
248   fetcher_.reset(oauth2_token_service_->CreateAccessTokenFetcher(
249       account_id_, getter_.get(), this));
250   DCHECK(fetcher_);
251   fetcher_->Start(client_id_,
252                   client_secret_,
253                   std::vector<std::string>(scopes_.begin(), scopes_.end()));
254   retry_timer_.Stop();
255 }
256 
OnGetTokenSuccess(const std::string & access_token,const base::Time & expiration_date)257 void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
258     const std::string& access_token,
259     const base::Time& expiration_date) {
260   fetcher_.reset();
261 
262   // Fetch completes.
263   error_ = GoogleServiceAuthError::AuthErrorNone();
264   access_token_ = access_token;
265   expiration_date_ = expiration_date;
266 
267   // Subclasses may override this method to skip caching in some cases, but
268   // we still inform all waiting Consumers of a successful token fetch below.
269   // This is intentional -- some consumers may need the token for cleanup
270   // tasks. https://chromiumcodereview.appspot.com/11312124/
271   oauth2_token_service_->RegisterCacheEntry(client_id_,
272                                             account_id_,
273                                             scopes_,
274                                             access_token_,
275                                             expiration_date_);
276   InformWaitingRequestsAndDelete();
277 }
278 
OnGetTokenFailure(const GoogleServiceAuthError & error)279 void OAuth2TokenService::Fetcher::OnGetTokenFailure(
280     const GoogleServiceAuthError& error) {
281   fetcher_.reset();
282 
283   if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) {
284     base::TimeDelta backoff = base::TimeDelta::FromMilliseconds(
285         ComputeExponentialBackOffMilliseconds(retry_number_));
286     ++retry_number_;
287     retry_timer_.Stop();
288     retry_timer_.Start(FROM_HERE,
289                        backoff,
290                        this,
291                        &OAuth2TokenService::Fetcher::Start);
292     return;
293   }
294 
295   error_ = error;
296   InformWaitingRequestsAndDelete();
297 }
298 
299 // Returns an exponential backoff in milliseconds including randomness less than
300 // 1000 ms when retrying fetching an OAuth2 access token.
ComputeExponentialBackOffMilliseconds(int retry_num)301 int64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
302     int retry_num) {
303   DCHECK(retry_num < max_fetch_retry_num_);
304   int64 exponential_backoff_in_seconds = 1 << retry_num;
305   // Returns a backoff with randomness < 1000ms
306   return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
307 }
308 
309 // static
ShouldRetry(const GoogleServiceAuthError & error)310 bool OAuth2TokenService::Fetcher::ShouldRetry(
311     const GoogleServiceAuthError& error) {
312   GoogleServiceAuthError::State error_state = error.state();
313   return error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
314          error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
315          error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
316 }
317 
InformWaitingRequests()318 void OAuth2TokenService::Fetcher::InformWaitingRequests() {
319   std::vector<base::WeakPtr<RequestImpl> >::const_iterator iter =
320       waiting_requests_.begin();
321   for (; iter != waiting_requests_.end(); ++iter) {
322     base::WeakPtr<RequestImpl> waiting_request = *iter;
323     if (waiting_request.get())
324       waiting_request->InformConsumer(error_, access_token_, expiration_date_);
325   }
326   waiting_requests_.clear();
327 }
328 
InformWaitingRequestsAndDelete()329 void OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
330   // Deregisters itself from the service to prevent more waiting requests to
331   // be added when it calls back the waiting requests.
332   oauth2_token_service_->OnFetchComplete(this);
333   InformWaitingRequests();
334   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
335 }
336 
AddWaitingRequest(base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request)337 void OAuth2TokenService::Fetcher::AddWaitingRequest(
338     base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
339   waiting_requests_.push_back(waiting_request);
340 }
341 
GetWaitingRequestCount() const342 size_t OAuth2TokenService::Fetcher::GetWaitingRequestCount() const {
343   return waiting_requests_.size();
344 }
345 
Cancel()346 void OAuth2TokenService::Fetcher::Cancel() {
347   if (fetcher_)
348     fetcher_->CancelRequest();
349   fetcher_.reset();
350   retry_timer_.Stop();
351   error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
352   InformWaitingRequestsAndDelete();
353 }
354 
GetScopeSet() const355 const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet()
356     const {
357   return scopes_;
358 }
359 
GetClientId() const360 const std::string& OAuth2TokenService::Fetcher::GetClientId() const {
361   return client_id_;
362 }
363 
GetAccountId() const364 const std::string& OAuth2TokenService::Fetcher::GetAccountId() const {
365   return account_id_;
366 }
367 
Request()368 OAuth2TokenService::Request::Request() {
369 }
370 
~Request()371 OAuth2TokenService::Request::~Request() {
372 }
373 
Consumer(const std::string & id)374 OAuth2TokenService::Consumer::Consumer(const std::string& id)
375     : id_(id) {}
376 
~Consumer()377 OAuth2TokenService::Consumer::~Consumer() {
378 }
379 
OAuth2TokenService()380 OAuth2TokenService::OAuth2TokenService() : batch_change_depth_(0) {
381 }
382 
~OAuth2TokenService()383 OAuth2TokenService::~OAuth2TokenService() {
384   // Release all the pending fetchers.
385   STLDeleteContainerPairSecondPointers(
386       pending_fetchers_.begin(), pending_fetchers_.end());
387 }
388 
AddObserver(Observer * observer)389 void OAuth2TokenService::AddObserver(Observer* observer) {
390   observer_list_.AddObserver(observer);
391 }
392 
RemoveObserver(Observer * observer)393 void OAuth2TokenService::RemoveObserver(Observer* observer) {
394   observer_list_.RemoveObserver(observer);
395 }
396 
AddDiagnosticsObserver(DiagnosticsObserver * observer)397 void OAuth2TokenService::AddDiagnosticsObserver(DiagnosticsObserver* observer) {
398   diagnostics_observer_list_.AddObserver(observer);
399 }
400 
RemoveDiagnosticsObserver(DiagnosticsObserver * observer)401 void OAuth2TokenService::RemoveDiagnosticsObserver(
402     DiagnosticsObserver* observer) {
403   diagnostics_observer_list_.RemoveObserver(observer);
404 }
405 
GetAccounts()406 std::vector<std::string> OAuth2TokenService::GetAccounts() {
407   return std::vector<std::string>();
408 }
409 
StartRequest(const std::string & account_id,const OAuth2TokenService::ScopeSet & scopes,OAuth2TokenService::Consumer * consumer)410 scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
411     const std::string& account_id,
412     const OAuth2TokenService::ScopeSet& scopes,
413     OAuth2TokenService::Consumer* consumer) {
414   return StartRequestForClientWithContext(
415       account_id,
416       GetRequestContext(),
417       GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
418       GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
419       scopes,
420       consumer);
421 }
422 
423 scoped_ptr<OAuth2TokenService::Request>
StartRequestForClient(const std::string & account_id,const std::string & client_id,const std::string & client_secret,const OAuth2TokenService::ScopeSet & scopes,OAuth2TokenService::Consumer * consumer)424 OAuth2TokenService::StartRequestForClient(
425     const std::string& account_id,
426     const std::string& client_id,
427     const std::string& client_secret,
428     const OAuth2TokenService::ScopeSet& scopes,
429     OAuth2TokenService::Consumer* consumer) {
430   return StartRequestForClientWithContext(
431       account_id,
432       GetRequestContext(),
433       client_id,
434       client_secret,
435       scopes,
436       consumer);
437 }
438 
439 scoped_ptr<OAuth2TokenService::Request>
StartRequestWithContext(const std::string & account_id,net::URLRequestContextGetter * getter,const ScopeSet & scopes,Consumer * consumer)440 OAuth2TokenService::StartRequestWithContext(
441     const std::string& account_id,
442     net::URLRequestContextGetter* getter,
443     const ScopeSet& scopes,
444     Consumer* consumer) {
445   return StartRequestForClientWithContext(
446       account_id,
447       getter,
448       GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
449       GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
450       scopes,
451       consumer);
452 }
453 
454 scoped_ptr<OAuth2TokenService::Request>
StartRequestForClientWithContext(const std::string & account_id,net::URLRequestContextGetter * getter,const std::string & client_id,const std::string & client_secret,const ScopeSet & scopes,Consumer * consumer)455 OAuth2TokenService::StartRequestForClientWithContext(
456     const std::string& account_id,
457     net::URLRequestContextGetter* getter,
458     const std::string& client_id,
459     const std::string& client_secret,
460     const ScopeSet& scopes,
461     Consumer* consumer) {
462   DCHECK(CalledOnValidThread());
463 
464   scoped_ptr<RequestImpl> request(new RequestImpl(account_id, consumer));
465   FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
466                     OnAccessTokenRequested(account_id,
467                                            consumer->id(),
468                                            scopes));
469 
470   if (!RefreshTokenIsAvailable(account_id)) {
471     GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
472 
473     FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
474                       OnFetchAccessTokenComplete(
475                           account_id, consumer->id(), scopes, error,
476                           base::Time()));
477 
478     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
479         &RequestImpl::InformConsumer,
480         request->AsWeakPtr(),
481         error,
482         std::string(),
483         base::Time()));
484     return request.PassAs<Request>();
485   }
486 
487   RequestParameters request_parameters(client_id,
488                                        account_id,
489                                        scopes);
490   if (HasCacheEntry(request_parameters)) {
491     StartCacheLookupRequest(request.get(), request_parameters, consumer);
492   } else {
493     FetchOAuth2Token(request.get(),
494                      account_id,
495                      getter,
496                      client_id,
497                      client_secret,
498                      scopes);
499   }
500   return request.PassAs<Request>();
501 }
502 
FetchOAuth2Token(RequestImpl * request,const std::string & account_id,net::URLRequestContextGetter * getter,const std::string & client_id,const std::string & client_secret,const ScopeSet & scopes)503 void OAuth2TokenService::FetchOAuth2Token(RequestImpl* request,
504                                           const std::string& account_id,
505                                           net::URLRequestContextGetter* getter,
506                                           const std::string& client_id,
507                                           const std::string& client_secret,
508                                           const ScopeSet& scopes) {
509   // If there is already a pending fetcher for |scopes| and |account_id|,
510   // simply register this |request| for those results rather than starting
511   // a new fetcher.
512   RequestParameters request_parameters = RequestParameters(client_id,
513                                                            account_id,
514                                                            scopes);
515   std::map<RequestParameters, Fetcher*>::iterator iter =
516       pending_fetchers_.find(request_parameters);
517   if (iter != pending_fetchers_.end()) {
518     iter->second->AddWaitingRequest(request->AsWeakPtr());
519     return;
520   }
521 
522   pending_fetchers_[request_parameters] =
523       Fetcher::CreateAndStart(this,
524                               account_id,
525                               getter,
526                               client_id,
527                               client_secret,
528                               scopes,
529                               request->AsWeakPtr());
530 }
531 
StartCacheLookupRequest(RequestImpl * request,const OAuth2TokenService::RequestParameters & request_parameters,OAuth2TokenService::Consumer * consumer)532 void OAuth2TokenService::StartCacheLookupRequest(
533     RequestImpl* request,
534     const OAuth2TokenService::RequestParameters& request_parameters,
535     OAuth2TokenService::Consumer* consumer) {
536   CHECK(HasCacheEntry(request_parameters));
537   const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
538   FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
539                     OnFetchAccessTokenComplete(
540                         request_parameters.account_id,
541                         consumer->id(),
542                         request_parameters.scopes,
543                         GoogleServiceAuthError::AuthErrorNone(),
544                         cache_entry->expiration_date));
545   base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
546       &RequestImpl::InformConsumer,
547       request->AsWeakPtr(),
548       GoogleServiceAuthError(GoogleServiceAuthError::NONE),
549       cache_entry->access_token,
550       cache_entry->expiration_date));
551 }
552 
InvalidateToken(const std::string & account_id,const ScopeSet & scopes,const std::string & access_token)553 void OAuth2TokenService::InvalidateToken(const std::string& account_id,
554                                          const ScopeSet& scopes,
555                                          const std::string& access_token) {
556   InvalidateOAuth2Token(account_id,
557                         GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
558                         scopes,
559                         access_token);
560 }
561 
InvalidateTokenForClient(const std::string & account_id,const std::string & client_id,const ScopeSet & scopes,const std::string & access_token)562 void OAuth2TokenService::InvalidateTokenForClient(
563     const std::string& account_id,
564     const std::string& client_id,
565     const ScopeSet& scopes,
566     const std::string& access_token) {
567   InvalidateOAuth2Token(account_id, client_id, scopes, access_token);
568 }
569 
InvalidateOAuth2Token(const std::string & account_id,const std::string & client_id,const ScopeSet & scopes,const std::string & access_token)570 void OAuth2TokenService::InvalidateOAuth2Token(
571     const std::string& account_id,
572     const std::string& client_id,
573     const ScopeSet& scopes,
574     const std::string& access_token) {
575   DCHECK(CalledOnValidThread());
576   RemoveCacheEntry(
577       RequestParameters(client_id,
578                         account_id,
579                         scopes),
580       access_token);
581 }
582 
OnFetchComplete(Fetcher * fetcher)583 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
584   DCHECK(CalledOnValidThread());
585 
586   // Update the auth error state so auth errors are appropriately communicated
587   // to the user.
588   UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
589 
590   // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh
591   // token and scope set. This is guaranteed as follows; here a Fetcher is said
592   // to be uncompleted if it has not finished calling back
593   // OAuth2TokenService::OnFetchComplete().
594   //
595   // (1) All the live Fetchers are created by this service.
596   //     This is because (1) all the live Fetchers are created by a live
597   //     service, as all the fetchers created by a service are destructed in the
598   //     service's dtor.
599   //
600   // (2) All the uncompleted Fetchers created by this service are recorded in
601   //     |pending_fetchers_|.
602   //     This is because (1) all the created Fetchers are added to
603   //     |pending_fetchers_| (in method StartRequest()) and (2) method
604   //     OnFetchComplete() is the only place where a Fetcher is erased from
605   //     |pending_fetchers_|. Note no Fetcher is erased in method
606   //     StartRequest().
607   //
608   // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its
609   //     refresh token and ScopeSet. This is guaranteed by Fetcher creation in
610   //     method StartRequest().
611   //
612   // When this method is called, |fetcher| is alive and uncompleted.
613   // By (1), |fetcher| is created by this service.
614   // Then by (2), |fetcher| is recorded in |pending_fetchers_|.
615   // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet.
616   RequestParameters request_param(fetcher->GetClientId(),
617                                   fetcher->GetAccountId(),
618                                   fetcher->GetScopeSet());
619 
620   const OAuth2TokenService::CacheEntry* entry = GetCacheEntry(request_param);
621   const std::vector<base::WeakPtr<RequestImpl> >& requests =
622       fetcher->waiting_requests();
623   for (size_t i = 0; i < requests.size(); ++i) {
624     const RequestImpl* req = requests[i].get();
625     if (req) {
626       FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
627                         OnFetchAccessTokenComplete(
628                             req->GetAccountId(), req->GetConsumerId(),
629                             fetcher->GetScopeSet(), fetcher->error(),
630                             entry ? entry->expiration_date : base::Time()));
631     }
632   }
633 
634   std::map<RequestParameters, Fetcher*>::iterator iter =
635     pending_fetchers_.find(request_param);
636   DCHECK(iter != pending_fetchers_.end());
637   DCHECK_EQ(fetcher, iter->second);
638   pending_fetchers_.erase(iter);
639 }
640 
HasCacheEntry(const RequestParameters & request_parameters)641 bool OAuth2TokenService::HasCacheEntry(
642     const RequestParameters& request_parameters) {
643   const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
644   return cache_entry && cache_entry->access_token.length();
645 }
646 
GetCacheEntry(const RequestParameters & request_parameters)647 const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
648     const RequestParameters& request_parameters) {
649   DCHECK(CalledOnValidThread());
650   TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
651   if (token_iterator == token_cache_.end())
652     return NULL;
653   if (token_iterator->second.expiration_date <= base::Time::Now()) {
654     token_cache_.erase(token_iterator);
655     return NULL;
656   }
657   return &token_iterator->second;
658 }
659 
RemoveCacheEntry(const RequestParameters & request_parameters,const std::string & token_to_remove)660 bool OAuth2TokenService::RemoveCacheEntry(
661     const RequestParameters& request_parameters,
662     const std::string& token_to_remove) {
663   DCHECK(CalledOnValidThread());
664   TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
665   if (token_iterator != token_cache_.end() &&
666       token_iterator->second.access_token == token_to_remove) {
667     FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
668                       OnTokenRemoved(request_parameters.account_id,
669                                      request_parameters.scopes));
670     token_cache_.erase(token_iterator);
671     return true;
672   }
673   return false;
674 }
675 
RegisterCacheEntry(const std::string & client_id,const std::string & account_id,const OAuth2TokenService::ScopeSet & scopes,const std::string & access_token,const base::Time & expiration_date)676 void OAuth2TokenService::RegisterCacheEntry(
677     const std::string& client_id,
678     const std::string& account_id,
679     const OAuth2TokenService::ScopeSet& scopes,
680     const std::string& access_token,
681     const base::Time& expiration_date) {
682   DCHECK(CalledOnValidThread());
683 
684   CacheEntry& token = token_cache_[RequestParameters(client_id,
685                                                      account_id,
686                                                      scopes)];
687   token.access_token = access_token;
688   token.expiration_date = expiration_date;
689 }
690 
UpdateAuthError(const std::string & account_id,const GoogleServiceAuthError & error)691 void OAuth2TokenService::UpdateAuthError(
692     const std::string& account_id,
693     const GoogleServiceAuthError& error) {
694   // Default implementation does nothing.
695 }
696 
ClearCache()697 void OAuth2TokenService::ClearCache() {
698   DCHECK(CalledOnValidThread());
699   for (TokenCache::iterator iter = token_cache_.begin();
700        iter != token_cache_.end(); ++iter) {
701     FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
702                       OnTokenRemoved(iter->first.account_id,
703                                      iter->first.scopes));
704   }
705 
706   token_cache_.clear();
707 }
708 
ClearCacheForAccount(const std::string & account_id)709 void OAuth2TokenService::ClearCacheForAccount(const std::string& account_id) {
710   DCHECK(CalledOnValidThread());
711   for (TokenCache::iterator iter = token_cache_.begin();
712        iter != token_cache_.end();
713        /* iter incremented in body */) {
714     if (iter->first.account_id == account_id) {
715       FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
716                         OnTokenRemoved(account_id, iter->first.scopes));
717       token_cache_.erase(iter++);
718     } else {
719       ++iter;
720     }
721   }
722 }
723 
CancelAllRequests()724 void OAuth2TokenService::CancelAllRequests() {
725   std::vector<Fetcher*> fetchers_to_cancel;
726   for (std::map<RequestParameters, Fetcher*>::iterator iter =
727            pending_fetchers_.begin();
728        iter != pending_fetchers_.end();
729        ++iter) {
730     fetchers_to_cancel.push_back(iter->second);
731   }
732   CancelFetchers(fetchers_to_cancel);
733 }
734 
CancelRequestsForAccount(const std::string & account_id)735 void OAuth2TokenService::CancelRequestsForAccount(
736     const std::string& account_id) {
737   std::vector<Fetcher*> fetchers_to_cancel;
738   for (std::map<RequestParameters, Fetcher*>::iterator iter =
739            pending_fetchers_.begin();
740        iter != pending_fetchers_.end();
741        ++iter) {
742     if (iter->first.account_id == account_id)
743       fetchers_to_cancel.push_back(iter->second);
744   }
745   CancelFetchers(fetchers_to_cancel);
746 }
747 
CancelFetchers(std::vector<Fetcher * > fetchers_to_cancel)748 void OAuth2TokenService::CancelFetchers(
749     std::vector<Fetcher*> fetchers_to_cancel) {
750   for (std::vector<OAuth2TokenService::Fetcher*>::iterator iter =
751            fetchers_to_cancel.begin();
752        iter != fetchers_to_cancel.end();
753        ++iter) {
754     (*iter)->Cancel();
755   }
756 }
757 
FireRefreshTokenAvailable(const std::string & account_id)758 void OAuth2TokenService::FireRefreshTokenAvailable(
759     const std::string& account_id) {
760   FOR_EACH_OBSERVER(Observer, observer_list_,
761                     OnRefreshTokenAvailable(account_id));
762 }
763 
FireRefreshTokenRevoked(const std::string & account_id)764 void OAuth2TokenService::FireRefreshTokenRevoked(
765     const std::string& account_id) {
766   FOR_EACH_OBSERVER(Observer, observer_list_,
767                     OnRefreshTokenRevoked(account_id));
768 }
769 
FireRefreshTokensLoaded()770 void OAuth2TokenService::FireRefreshTokensLoaded() {
771   FOR_EACH_OBSERVER(Observer, observer_list_, OnRefreshTokensLoaded());
772 }
773 
StartBatchChanges()774 void OAuth2TokenService::StartBatchChanges() {
775   ++batch_change_depth_;
776   if (batch_change_depth_ == 1)
777     FOR_EACH_OBSERVER(Observer, observer_list_, OnStartBatchChanges());
778 }
779 
EndBatchChanges()780 void OAuth2TokenService::EndBatchChanges() {
781   --batch_change_depth_;
782   DCHECK_LE(0, batch_change_depth_);
783   if (batch_change_depth_ == 0)
784     FOR_EACH_OBSERVER(Observer, observer_list_, OnEndBatchChanges());
785 }
786 
cache_size_for_testing() const787 int OAuth2TokenService::cache_size_for_testing() const {
788   return token_cache_.size();
789 }
790 
set_max_authorization_token_fetch_retries_for_testing(int max_retries)791 void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
792     int max_retries) {
793   DCHECK(CalledOnValidThread());
794   max_fetch_retry_num_ = max_retries;
795 }
796 
GetNumPendingRequestsForTesting(const std::string & client_id,const std::string & account_id,const ScopeSet & scopes) const797 size_t OAuth2TokenService::GetNumPendingRequestsForTesting(
798     const std::string& client_id,
799     const std::string& account_id,
800     const ScopeSet& scopes) const {
801   PendingFetcherMap::const_iterator iter = pending_fetchers_.find(
802       OAuth2TokenService::RequestParameters(
803           client_id,
804           account_id,
805           scopes));
806   return iter == pending_fetchers_.end() ?
807              0 : iter->second->GetWaitingRequestCount();
808 }
809