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