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