Material PDF: Fix inconsistent behaviour in page selector, update styling
[chromium-blink-merge.git] / google_apis / gaia / oauth2_token_service.cc
blob524564614d39df6147b27b91ac9d5a0310eefb15
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.
5 #include "google_apis/gaia/oauth2_token_service.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/profiler/scoped_tracker.h"
14 #include "base/rand_util.h"
15 #include "base/stl_util.h"
16 #include "base/time/time.h"
17 #include "base/timer/timer.h"
18 #include "google_apis/gaia/gaia_urls.h"
19 #include "google_apis/gaia/google_service_auth_error.h"
20 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
21 #include "net/url_request/url_request_context_getter.h"
23 int OAuth2TokenService::max_fetch_retry_num_ = 5;
25 OAuth2TokenService::RequestParameters::RequestParameters(
26 const std::string& client_id,
27 const std::string& account_id,
28 const ScopeSet& scopes)
29 : client_id(client_id),
30 account_id(account_id),
31 scopes(scopes) {
34 OAuth2TokenService::RequestParameters::~RequestParameters() {
37 bool OAuth2TokenService::RequestParameters::operator<(
38 const RequestParameters& p) const {
39 if (client_id < p.client_id)
40 return true;
41 else if (p.client_id < client_id)
42 return false;
44 if (account_id < p.account_id)
45 return true;
46 else if (p.account_id < account_id)
47 return false;
49 return scopes < p.scopes;
52 OAuth2TokenService::RequestImpl::RequestImpl(
53 const std::string& account_id,
54 OAuth2TokenService::Consumer* consumer)
55 : account_id_(account_id),
56 consumer_(consumer) {
59 OAuth2TokenService::RequestImpl::~RequestImpl() {
60 DCHECK(CalledOnValidThread());
63 std::string OAuth2TokenService::RequestImpl::GetAccountId() const {
64 return account_id_;
67 std::string OAuth2TokenService::RequestImpl::GetConsumerId() const {
68 return consumer_->id();
71 void OAuth2TokenService::RequestImpl::InformConsumer(
72 const GoogleServiceAuthError& error,
73 const std::string& access_token,
74 const base::Time& expiration_date) {
75 DCHECK(CalledOnValidThread());
76 if (error.state() == GoogleServiceAuthError::NONE)
77 consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
78 else
79 consumer_->OnGetTokenFailure(this, error);
82 OAuth2TokenService::ScopedBatchChange::ScopedBatchChange(
83 OAuth2TokenService* token_service) : token_service_(token_service) {
84 DCHECK(token_service_);
85 token_service_->StartBatchChanges();
88 OAuth2TokenService::ScopedBatchChange::~ScopedBatchChange() {
89 token_service_->EndBatchChanges();
92 // Class that fetches an OAuth2 access token for a given account id and set of
93 // scopes.
95 // It aims to meet OAuth2TokenService's requirements on token fetching. Retry
96 // mechanism is used to handle failures.
98 // To use this class, call CreateAndStart() to create and start a Fetcher.
100 // The Fetcher will call back the service by calling
101 // OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is
102 // not destructed before it completes fetching; if the Fetcher is destructed
103 // before it completes fetching, the service will never be called back. The
104 // Fetcher destructs itself after calling back the service when finishes
105 // fetching.
107 // Requests that are waiting for the fetching results of this Fetcher can be
108 // added to the Fetcher by calling
109 // OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher
110 // completes fetching.
112 // The waiting requests are taken as weak pointers and they can be deleted.
113 // The waiting requests will be called back with fetching results if they are
114 // not deleted
115 // - when the Fetcher completes fetching, if the Fetcher is not destructed
116 // before it completes fetching, or
117 // - when the Fetcher is destructed if the Fetcher is destructed before it
118 // completes fetching (in this case, the waiting requests will be called
119 // back with error).
120 class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
121 public:
122 // Creates a Fetcher and starts fetching an OAuth2 access token for
123 // |account_id| and |scopes| in the request context obtained by |getter|.
124 // The given |oauth2_token_service| will be informed when fetching is done.
125 static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service,
126 const std::string& account_id,
127 net::URLRequestContextGetter* getter,
128 const std::string& client_id,
129 const std::string& client_secret,
130 const ScopeSet& scopes,
131 base::WeakPtr<RequestImpl> waiting_request);
132 ~Fetcher() override;
134 // Add a request that is waiting for the result of this Fetcher.
135 void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request);
137 // Returns count of waiting requests.
138 size_t GetWaitingRequestCount() const;
140 const std::vector<base::WeakPtr<RequestImpl> >& waiting_requests() const {
141 return waiting_requests_;
144 void Cancel();
146 const ScopeSet& GetScopeSet() const;
147 const std::string& GetClientId() const;
148 const std::string& GetAccountId() const;
150 // The error result from this fetcher.
151 const GoogleServiceAuthError& error() const { return error_; }
153 protected:
154 // OAuth2AccessTokenConsumer
155 void OnGetTokenSuccess(const std::string& access_token,
156 const base::Time& expiration_date) override;
157 void OnGetTokenFailure(const GoogleServiceAuthError& error) override;
159 private:
160 Fetcher(OAuth2TokenService* oauth2_token_service,
161 const std::string& account_id,
162 net::URLRequestContextGetter* getter,
163 const std::string& client_id,
164 const std::string& client_secret,
165 const OAuth2TokenService::ScopeSet& scopes,
166 base::WeakPtr<RequestImpl> waiting_request);
167 void Start();
168 void InformWaitingRequests();
169 void InformWaitingRequestsAndDelete();
170 static bool ShouldRetry(const GoogleServiceAuthError& error);
171 int64 ComputeExponentialBackOffMilliseconds(int retry_num);
173 // |oauth2_token_service_| remains valid for the life of this Fetcher, since
174 // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
175 // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
176 // (whichever comes first).
177 OAuth2TokenService* const oauth2_token_service_;
178 scoped_refptr<net::URLRequestContextGetter> getter_;
179 const std::string account_id_;
180 const ScopeSet scopes_;
181 std::vector<base::WeakPtr<RequestImpl> > waiting_requests_;
183 int retry_number_;
184 base::OneShotTimer<Fetcher> retry_timer_;
185 scoped_ptr<OAuth2AccessTokenFetcher> fetcher_;
187 // Variables that store fetch results.
188 // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle
189 // destruction.
190 GoogleServiceAuthError error_;
191 std::string access_token_;
192 base::Time expiration_date_;
194 // OAuth2 client id and secret.
195 std::string client_id_;
196 std::string client_secret_;
198 DISALLOW_COPY_AND_ASSIGN(Fetcher);
201 // static
202 OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart(
203 OAuth2TokenService* oauth2_token_service,
204 const std::string& account_id,
205 net::URLRequestContextGetter* getter,
206 const std::string& client_id,
207 const std::string& client_secret,
208 const OAuth2TokenService::ScopeSet& scopes,
209 base::WeakPtr<RequestImpl> waiting_request) {
210 OAuth2TokenService::Fetcher* fetcher = new Fetcher(
211 oauth2_token_service,
212 account_id,
213 getter,
214 client_id,
215 client_secret,
216 scopes,
217 waiting_request);
219 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
220 // fixed.
221 tracked_objects::ScopedTracker tracking_profile(
222 FROM_HERE_WITH_EXPLICIT_FUNCTION(
223 "422460 OAuth2TokenService::Fetcher::CreateAndStart"));
225 fetcher->Start();
226 return fetcher;
229 OAuth2TokenService::Fetcher::Fetcher(
230 OAuth2TokenService* oauth2_token_service,
231 const std::string& account_id,
232 net::URLRequestContextGetter* getter,
233 const std::string& client_id,
234 const std::string& client_secret,
235 const OAuth2TokenService::ScopeSet& scopes,
236 base::WeakPtr<RequestImpl> waiting_request)
237 : oauth2_token_service_(oauth2_token_service),
238 getter_(getter),
239 account_id_(account_id),
240 scopes_(scopes),
241 retry_number_(0),
242 error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
243 client_id_(client_id),
244 client_secret_(client_secret) {
245 DCHECK(oauth2_token_service_);
246 waiting_requests_.push_back(waiting_request);
249 OAuth2TokenService::Fetcher::~Fetcher() {
250 // Inform the waiting requests if it has not done so.
251 if (waiting_requests_.size())
252 InformWaitingRequests();
255 void OAuth2TokenService::Fetcher::Start() {
256 fetcher_.reset(oauth2_token_service_->CreateAccessTokenFetcher(
257 account_id_, getter_.get(), this));
258 DCHECK(fetcher_);
259 fetcher_->Start(client_id_,
260 client_secret_,
261 std::vector<std::string>(scopes_.begin(), scopes_.end()));
262 retry_timer_.Stop();
265 void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
266 const std::string& access_token,
267 const base::Time& expiration_date) {
268 fetcher_.reset();
270 // Fetch completes.
271 error_ = GoogleServiceAuthError::AuthErrorNone();
272 access_token_ = access_token;
273 expiration_date_ = expiration_date;
275 // Subclasses may override this method to skip caching in some cases, but
276 // we still inform all waiting Consumers of a successful token fetch below.
277 // This is intentional -- some consumers may need the token for cleanup
278 // tasks. https://chromiumcodereview.appspot.com/11312124/
279 oauth2_token_service_->RegisterCacheEntry(client_id_,
280 account_id_,
281 scopes_,
282 access_token_,
283 expiration_date_);
284 InformWaitingRequestsAndDelete();
287 void OAuth2TokenService::Fetcher::OnGetTokenFailure(
288 const GoogleServiceAuthError& error) {
289 fetcher_.reset();
291 if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) {
292 base::TimeDelta backoff = base::TimeDelta::FromMilliseconds(
293 ComputeExponentialBackOffMilliseconds(retry_number_));
294 ++retry_number_;
295 UMA_HISTOGRAM_ENUMERATION("Signin.OAuth2TokenGetRetry",
296 error.state(), GoogleServiceAuthError::NUM_STATES);
297 retry_timer_.Stop();
298 retry_timer_.Start(FROM_HERE,
299 backoff,
300 this,
301 &OAuth2TokenService::Fetcher::Start);
302 return;
305 UMA_HISTOGRAM_ENUMERATION("Signin.OAuth2TokenGetFailure",
306 error.state(), GoogleServiceAuthError::NUM_STATES);
307 error_ = error;
308 InformWaitingRequestsAndDelete();
311 // Returns an exponential backoff in milliseconds including randomness less than
312 // 1000 ms when retrying fetching an OAuth2 access token.
313 int64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
314 int retry_num) {
315 DCHECK(retry_num < max_fetch_retry_num_);
316 int64 exponential_backoff_in_seconds = 1 << retry_num;
317 // Returns a backoff with randomness < 1000ms
318 return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
321 // static
322 bool OAuth2TokenService::Fetcher::ShouldRetry(
323 const GoogleServiceAuthError& error) {
324 GoogleServiceAuthError::State error_state = error.state();
325 return error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
326 error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
327 error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
330 void OAuth2TokenService::Fetcher::InformWaitingRequests() {
331 std::vector<base::WeakPtr<RequestImpl> >::const_iterator iter =
332 waiting_requests_.begin();
333 for (; iter != waiting_requests_.end(); ++iter) {
334 base::WeakPtr<RequestImpl> waiting_request = *iter;
335 if (waiting_request.get())
336 waiting_request->InformConsumer(error_, access_token_, expiration_date_);
338 waiting_requests_.clear();
341 void OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
342 // Deregisters itself from the service to prevent more waiting requests to
343 // be added when it calls back the waiting requests.
344 oauth2_token_service_->OnFetchComplete(this);
345 InformWaitingRequests();
346 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
349 void OAuth2TokenService::Fetcher::AddWaitingRequest(
350 base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
351 waiting_requests_.push_back(waiting_request);
354 size_t OAuth2TokenService::Fetcher::GetWaitingRequestCount() const {
355 return waiting_requests_.size();
358 void OAuth2TokenService::Fetcher::Cancel() {
359 if (fetcher_)
360 fetcher_->CancelRequest();
361 fetcher_.reset();
362 retry_timer_.Stop();
363 error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
364 InformWaitingRequestsAndDelete();
367 const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet()
368 const {
369 return scopes_;
372 const std::string& OAuth2TokenService::Fetcher::GetClientId() const {
373 return client_id_;
376 const std::string& OAuth2TokenService::Fetcher::GetAccountId() const {
377 return account_id_;
380 OAuth2TokenService::Request::Request() {
383 OAuth2TokenService::Request::~Request() {
386 OAuth2TokenService::Consumer::Consumer(const std::string& id)
387 : id_(id) {}
389 OAuth2TokenService::Consumer::~Consumer() {
392 OAuth2TokenService::OAuth2TokenService() : batch_change_depth_(0) {
395 OAuth2TokenService::~OAuth2TokenService() {
396 // Release all the pending fetchers.
397 STLDeleteContainerPairSecondPointers(
398 pending_fetchers_.begin(), pending_fetchers_.end());
401 void OAuth2TokenService::AddObserver(Observer* observer) {
402 observer_list_.AddObserver(observer);
405 void OAuth2TokenService::RemoveObserver(Observer* observer) {
406 observer_list_.RemoveObserver(observer);
409 void OAuth2TokenService::AddDiagnosticsObserver(DiagnosticsObserver* observer) {
410 diagnostics_observer_list_.AddObserver(observer);
413 void OAuth2TokenService::RemoveDiagnosticsObserver(
414 DiagnosticsObserver* observer) {
415 diagnostics_observer_list_.RemoveObserver(observer);
418 std::vector<std::string> OAuth2TokenService::GetAccounts() {
419 return std::vector<std::string>();
422 scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
423 const std::string& account_id,
424 const OAuth2TokenService::ScopeSet& scopes,
425 OAuth2TokenService::Consumer* consumer) {
426 return StartRequestForClientWithContext(
427 account_id,
428 GetRequestContext(),
429 GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
430 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
431 scopes,
432 consumer);
435 scoped_ptr<OAuth2TokenService::Request>
436 OAuth2TokenService::StartRequestForClient(
437 const std::string& account_id,
438 const std::string& client_id,
439 const std::string& client_secret,
440 const OAuth2TokenService::ScopeSet& scopes,
441 OAuth2TokenService::Consumer* consumer) {
442 return StartRequestForClientWithContext(
443 account_id,
444 GetRequestContext(),
445 client_id,
446 client_secret,
447 scopes,
448 consumer);
451 scoped_ptr<OAuth2TokenService::Request>
452 OAuth2TokenService::StartRequestWithContext(
453 const std::string& account_id,
454 net::URLRequestContextGetter* getter,
455 const ScopeSet& scopes,
456 Consumer* consumer) {
457 return StartRequestForClientWithContext(
458 account_id,
459 getter,
460 GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
461 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
462 scopes,
463 consumer);
466 scoped_ptr<OAuth2TokenService::Request>
467 OAuth2TokenService::StartRequestForClientWithContext(
468 const std::string& account_id,
469 net::URLRequestContextGetter* getter,
470 const std::string& client_id,
471 const std::string& client_secret,
472 const ScopeSet& scopes,
473 Consumer* consumer) {
474 DCHECK(CalledOnValidThread());
476 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
477 // fixed.
478 tracked_objects::ScopedTracker tracking_profile1(
479 FROM_HERE_WITH_EXPLICIT_FUNCTION(
480 "422460 OAuth2TokenService::StartRequestForClientWithContext 1"));
482 scoped_ptr<RequestImpl> request(new RequestImpl(account_id, consumer));
483 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
484 OnAccessTokenRequested(account_id,
485 consumer->id(),
486 scopes));
488 if (!RefreshTokenIsAvailable(account_id)) {
489 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
490 // is fixed.
491 tracked_objects::ScopedTracker tracking_profile2(
492 FROM_HERE_WITH_EXPLICIT_FUNCTION(
493 "422460 OAuth2TokenService::StartRequestForClientWithContext 2"));
495 GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
497 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
498 OnFetchAccessTokenComplete(
499 account_id, consumer->id(), scopes, error,
500 base::Time()));
502 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
503 &RequestImpl::InformConsumer,
504 request->AsWeakPtr(),
505 error,
506 std::string(),
507 base::Time()));
508 return request.Pass();
511 RequestParameters request_parameters(client_id,
512 account_id,
513 scopes);
514 if (HasCacheEntry(request_parameters)) {
515 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
516 // is fixed.
517 tracked_objects::ScopedTracker tracking_profile3(
518 FROM_HERE_WITH_EXPLICIT_FUNCTION(
519 "422460 OAuth2TokenService::StartRequestForClientWithContext 3"));
521 StartCacheLookupRequest(request.get(), request_parameters, consumer);
522 } else {
523 FetchOAuth2Token(request.get(),
524 account_id,
525 getter,
526 client_id,
527 client_secret,
528 scopes);
530 return request.Pass();
533 void OAuth2TokenService::FetchOAuth2Token(RequestImpl* request,
534 const std::string& account_id,
535 net::URLRequestContextGetter* getter,
536 const std::string& client_id,
537 const std::string& client_secret,
538 const ScopeSet& scopes) {
539 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
540 // fixed.
541 tracked_objects::ScopedTracker tracking_profile(
542 FROM_HERE_WITH_EXPLICIT_FUNCTION(
543 "422460 OAuth2TokenService::FetchOAuth2Token"));
545 // If there is already a pending fetcher for |scopes| and |account_id|,
546 // simply register this |request| for those results rather than starting
547 // a new fetcher.
548 RequestParameters request_parameters = RequestParameters(client_id,
549 account_id,
550 scopes);
551 std::map<RequestParameters, Fetcher*>::iterator iter =
552 pending_fetchers_.find(request_parameters);
553 if (iter != pending_fetchers_.end()) {
554 iter->second->AddWaitingRequest(request->AsWeakPtr());
555 return;
558 pending_fetchers_[request_parameters] =
559 Fetcher::CreateAndStart(this,
560 account_id,
561 getter,
562 client_id,
563 client_secret,
564 scopes,
565 request->AsWeakPtr());
568 void OAuth2TokenService::StartCacheLookupRequest(
569 RequestImpl* request,
570 const OAuth2TokenService::RequestParameters& request_parameters,
571 OAuth2TokenService::Consumer* consumer) {
572 CHECK(HasCacheEntry(request_parameters));
573 const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
574 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
575 OnFetchAccessTokenComplete(
576 request_parameters.account_id,
577 consumer->id(),
578 request_parameters.scopes,
579 GoogleServiceAuthError::AuthErrorNone(),
580 cache_entry->expiration_date));
581 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
582 &RequestImpl::InformConsumer,
583 request->AsWeakPtr(),
584 GoogleServiceAuthError(GoogleServiceAuthError::NONE),
585 cache_entry->access_token,
586 cache_entry->expiration_date));
589 void OAuth2TokenService::InvalidateToken(const std::string& account_id,
590 const ScopeSet& scopes,
591 const std::string& access_token) {
592 InvalidateOAuth2Token(account_id,
593 GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
594 scopes,
595 access_token);
598 void OAuth2TokenService::InvalidateTokenForClient(
599 const std::string& account_id,
600 const std::string& client_id,
601 const ScopeSet& scopes,
602 const std::string& access_token) {
603 InvalidateOAuth2Token(account_id, client_id, scopes, access_token);
606 void OAuth2TokenService::InvalidateOAuth2Token(
607 const std::string& account_id,
608 const std::string& client_id,
609 const ScopeSet& scopes,
610 const std::string& access_token) {
611 DCHECK(CalledOnValidThread());
612 RemoveCacheEntry(
613 RequestParameters(client_id,
614 account_id,
615 scopes),
616 access_token);
619 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
620 DCHECK(CalledOnValidThread());
622 // Update the auth error state so auth errors are appropriately communicated
623 // to the user.
624 UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
626 // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh
627 // token and scope set. This is guaranteed as follows; here a Fetcher is said
628 // to be uncompleted if it has not finished calling back
629 // OAuth2TokenService::OnFetchComplete().
631 // (1) All the live Fetchers are created by this service.
632 // This is because (1) all the live Fetchers are created by a live
633 // service, as all the fetchers created by a service are destructed in the
634 // service's dtor.
636 // (2) All the uncompleted Fetchers created by this service are recorded in
637 // |pending_fetchers_|.
638 // This is because (1) all the created Fetchers are added to
639 // |pending_fetchers_| (in method StartRequest()) and (2) method
640 // OnFetchComplete() is the only place where a Fetcher is erased from
641 // |pending_fetchers_|. Note no Fetcher is erased in method
642 // StartRequest().
644 // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its
645 // refresh token and ScopeSet. This is guaranteed by Fetcher creation in
646 // method StartRequest().
648 // When this method is called, |fetcher| is alive and uncompleted.
649 // By (1), |fetcher| is created by this service.
650 // Then by (2), |fetcher| is recorded in |pending_fetchers_|.
651 // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet.
652 RequestParameters request_param(fetcher->GetClientId(),
653 fetcher->GetAccountId(),
654 fetcher->GetScopeSet());
656 const OAuth2TokenService::CacheEntry* entry = GetCacheEntry(request_param);
657 const std::vector<base::WeakPtr<RequestImpl> >& requests =
658 fetcher->waiting_requests();
659 for (size_t i = 0; i < requests.size(); ++i) {
660 const RequestImpl* req = requests[i].get();
661 if (req) {
662 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
663 OnFetchAccessTokenComplete(
664 req->GetAccountId(), req->GetConsumerId(),
665 fetcher->GetScopeSet(), fetcher->error(),
666 entry ? entry->expiration_date : base::Time()));
670 std::map<RequestParameters, Fetcher*>::iterator iter =
671 pending_fetchers_.find(request_param);
672 DCHECK(iter != pending_fetchers_.end());
673 DCHECK_EQ(fetcher, iter->second);
674 pending_fetchers_.erase(iter);
677 bool OAuth2TokenService::HasCacheEntry(
678 const RequestParameters& request_parameters) {
679 const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
680 return cache_entry && cache_entry->access_token.length();
683 const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
684 const RequestParameters& request_parameters) {
685 DCHECK(CalledOnValidThread());
686 TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
687 if (token_iterator == token_cache_.end())
688 return NULL;
689 if (token_iterator->second.expiration_date <= base::Time::Now()) {
690 token_cache_.erase(token_iterator);
691 return NULL;
693 return &token_iterator->second;
696 bool OAuth2TokenService::RemoveCacheEntry(
697 const RequestParameters& request_parameters,
698 const std::string& token_to_remove) {
699 DCHECK(CalledOnValidThread());
700 TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
701 if (token_iterator != token_cache_.end() &&
702 token_iterator->second.access_token == token_to_remove) {
703 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
704 OnTokenRemoved(request_parameters.account_id,
705 request_parameters.scopes));
706 token_cache_.erase(token_iterator);
707 return true;
709 return false;
712 void OAuth2TokenService::RegisterCacheEntry(
713 const std::string& client_id,
714 const std::string& account_id,
715 const OAuth2TokenService::ScopeSet& scopes,
716 const std::string& access_token,
717 const base::Time& expiration_date) {
718 DCHECK(CalledOnValidThread());
720 CacheEntry& token = token_cache_[RequestParameters(client_id,
721 account_id,
722 scopes)];
723 token.access_token = access_token;
724 token.expiration_date = expiration_date;
727 void OAuth2TokenService::UpdateAuthError(
728 const std::string& account_id,
729 const GoogleServiceAuthError& error) {
730 // Default implementation does nothing.
733 void OAuth2TokenService::ClearCache() {
734 DCHECK(CalledOnValidThread());
735 for (TokenCache::iterator iter = token_cache_.begin();
736 iter != token_cache_.end(); ++iter) {
737 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
738 OnTokenRemoved(iter->first.account_id,
739 iter->first.scopes));
742 token_cache_.clear();
745 void OAuth2TokenService::ClearCacheForAccount(const std::string& account_id) {
746 DCHECK(CalledOnValidThread());
747 for (TokenCache::iterator iter = token_cache_.begin();
748 iter != token_cache_.end();
749 /* iter incremented in body */) {
750 if (iter->first.account_id == account_id) {
751 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
752 OnTokenRemoved(account_id, iter->first.scopes));
753 token_cache_.erase(iter++);
754 } else {
755 ++iter;
760 void OAuth2TokenService::CancelAllRequests() {
761 std::vector<Fetcher*> fetchers_to_cancel;
762 for (std::map<RequestParameters, Fetcher*>::iterator iter =
763 pending_fetchers_.begin();
764 iter != pending_fetchers_.end();
765 ++iter) {
766 fetchers_to_cancel.push_back(iter->second);
768 CancelFetchers(fetchers_to_cancel);
771 void OAuth2TokenService::CancelRequestsForAccount(
772 const std::string& account_id) {
773 std::vector<Fetcher*> fetchers_to_cancel;
774 for (std::map<RequestParameters, Fetcher*>::iterator iter =
775 pending_fetchers_.begin();
776 iter != pending_fetchers_.end();
777 ++iter) {
778 if (iter->first.account_id == account_id)
779 fetchers_to_cancel.push_back(iter->second);
781 CancelFetchers(fetchers_to_cancel);
784 void OAuth2TokenService::CancelFetchers(
785 std::vector<Fetcher*> fetchers_to_cancel) {
786 for (std::vector<OAuth2TokenService::Fetcher*>::iterator iter =
787 fetchers_to_cancel.begin();
788 iter != fetchers_to_cancel.end();
789 ++iter) {
790 (*iter)->Cancel();
794 void OAuth2TokenService::FireRefreshTokenAvailable(
795 const std::string& account_id) {
796 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
797 // fixed.
798 tracked_objects::ScopedTracker tracking_profile(
799 FROM_HERE_WITH_EXPLICIT_FUNCTION(
800 "422460 OAuth2TokenService::FireRefreshTokenAvailable"));
802 FOR_EACH_OBSERVER(Observer, observer_list_,
803 OnRefreshTokenAvailable(account_id));
806 void OAuth2TokenService::FireRefreshTokenRevoked(
807 const std::string& account_id) {
808 FOR_EACH_OBSERVER(Observer, observer_list_,
809 OnRefreshTokenRevoked(account_id));
812 void OAuth2TokenService::FireRefreshTokensLoaded() {
813 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
814 // fixed.
815 tracked_objects::ScopedTracker tracking_profile(
816 FROM_HERE_WITH_EXPLICIT_FUNCTION(
817 "422460 OAuth2TokenService::FireRefreshTokensLoaded"));
819 FOR_EACH_OBSERVER(Observer, observer_list_, OnRefreshTokensLoaded());
822 void OAuth2TokenService::StartBatchChanges() {
823 ++batch_change_depth_;
824 if (batch_change_depth_ == 1)
825 FOR_EACH_OBSERVER(Observer, observer_list_, OnStartBatchChanges());
828 void OAuth2TokenService::EndBatchChanges() {
829 --batch_change_depth_;
830 DCHECK_LE(0, batch_change_depth_);
831 if (batch_change_depth_ == 0)
832 FOR_EACH_OBSERVER(Observer, observer_list_, OnEndBatchChanges());
835 int OAuth2TokenService::cache_size_for_testing() const {
836 return token_cache_.size();
839 void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
840 int max_retries) {
841 DCHECK(CalledOnValidThread());
842 max_fetch_retry_num_ = max_retries;
845 size_t OAuth2TokenService::GetNumPendingRequestsForTesting(
846 const std::string& client_id,
847 const std::string& account_id,
848 const ScopeSet& scopes) const {
849 PendingFetcherMap::const_iterator iter = pending_fetchers_.find(
850 OAuth2TokenService::RequestParameters(
851 client_id,
852 account_id,
853 scopes));
854 return iter == pending_fetchers_.end() ?
855 0 : iter->second->GetWaitingRequestCount();