Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / google_apis / gaia / oauth2_token_service.cc
blob01e5d96a5b609d0279ba30ded63029a0e65acfa5
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 "google_apis/gaia/oauth2_token_service_delegate.h"
22 #include "net/url_request/url_request_context_getter.h"
24 int OAuth2TokenService::max_fetch_retry_num_ = 5;
26 OAuth2TokenService::RequestParameters::RequestParameters(
27 const std::string& client_id,
28 const std::string& account_id,
29 const ScopeSet& scopes)
30 : client_id(client_id),
31 account_id(account_id),
32 scopes(scopes) {
35 OAuth2TokenService::RequestParameters::~RequestParameters() {
38 bool OAuth2TokenService::RequestParameters::operator<(
39 const RequestParameters& p) const {
40 if (client_id < p.client_id)
41 return true;
42 else if (p.client_id < client_id)
43 return false;
45 if (account_id < p.account_id)
46 return true;
47 else if (p.account_id < account_id)
48 return false;
50 return scopes < p.scopes;
53 OAuth2TokenService::RequestImpl::RequestImpl(
54 const std::string& account_id,
55 OAuth2TokenService::Consumer* consumer)
56 : account_id_(account_id),
57 consumer_(consumer) {
60 OAuth2TokenService::RequestImpl::~RequestImpl() {
61 DCHECK(CalledOnValidThread());
64 std::string OAuth2TokenService::RequestImpl::GetAccountId() const {
65 return account_id_;
68 std::string OAuth2TokenService::RequestImpl::GetConsumerId() const {
69 return consumer_->id();
72 void OAuth2TokenService::RequestImpl::InformConsumer(
73 const GoogleServiceAuthError& error,
74 const std::string& access_token,
75 const base::Time& expiration_date) {
76 DCHECK(CalledOnValidThread());
77 if (error.state() == GoogleServiceAuthError::NONE)
78 consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
79 else
80 consumer_->OnGetTokenFailure(this, error);
83 // Class that fetches an OAuth2 access token for a given account id and set of
84 // scopes.
86 // It aims to meet OAuth2TokenService's requirements on token fetching. Retry
87 // mechanism is used to handle failures.
89 // To use this class, call CreateAndStart() to create and start a Fetcher.
91 // The Fetcher will call back the service by calling
92 // OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is
93 // not destroyed before it completes fetching; if the Fetcher is destroyed
94 // before it completes fetching, the service will never be called back. The
95 // Fetcher destroys itself after calling back the service when it finishes
96 // fetching.
98 // Requests that are waiting for the fetching results of this Fetcher can be
99 // added to the Fetcher by calling
100 // OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher
101 // completes fetching.
103 // The waiting requests are taken as weak pointers and they can be deleted.
104 // They will be called back with the result when either the Fetcher completes
105 // fetching or is destroyed, whichever comes first. In the latter case, the
106 // waiting requests will be called back with an error.
108 // The OAuth2TokenService and the waiting requests will never be called back on
109 // the same turn of the message loop as when the fetcher is started, even if an
110 // immediate error occurred.
111 class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
112 public:
113 // Creates a Fetcher and starts fetching an OAuth2 access token for
114 // |account_id| and |scopes| in the request context obtained by |getter|.
115 // The given |oauth2_token_service| will be informed when fetching is done.
116 static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service,
117 const std::string& account_id,
118 net::URLRequestContextGetter* getter,
119 const std::string& client_id,
120 const std::string& client_secret,
121 const ScopeSet& scopes,
122 base::WeakPtr<RequestImpl> waiting_request);
123 ~Fetcher() override;
125 // Add a request that is waiting for the result of this Fetcher.
126 void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request);
128 // Returns count of waiting requests.
129 size_t GetWaitingRequestCount() const;
131 const std::vector<base::WeakPtr<RequestImpl> >& waiting_requests() const {
132 return waiting_requests_;
135 void Cancel();
137 const ScopeSet& GetScopeSet() const;
138 const std::string& GetClientId() const;
139 const std::string& GetAccountId() const;
141 // The error result from this fetcher.
142 const GoogleServiceAuthError& error() const { return error_; }
144 protected:
145 // OAuth2AccessTokenConsumer
146 void OnGetTokenSuccess(const std::string& access_token,
147 const base::Time& expiration_date) override;
148 void OnGetTokenFailure(const GoogleServiceAuthError& error) override;
150 private:
151 Fetcher(OAuth2TokenService* oauth2_token_service,
152 const std::string& account_id,
153 net::URLRequestContextGetter* getter,
154 const std::string& client_id,
155 const std::string& client_secret,
156 const OAuth2TokenService::ScopeSet& scopes,
157 base::WeakPtr<RequestImpl> waiting_request);
158 void Start();
159 void InformWaitingRequests();
160 void InformWaitingRequestsAndDelete();
161 static bool ShouldRetry(const GoogleServiceAuthError& error);
162 int64 ComputeExponentialBackOffMilliseconds(int retry_num);
164 // |oauth2_token_service_| remains valid for the life of this Fetcher, since
165 // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
166 // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
167 // (whichever comes first).
168 OAuth2TokenService* const oauth2_token_service_;
169 scoped_refptr<net::URLRequestContextGetter> getter_;
170 const std::string account_id_;
171 const ScopeSet scopes_;
172 std::vector<base::WeakPtr<RequestImpl> > waiting_requests_;
174 int retry_number_;
175 base::OneShotTimer<Fetcher> retry_timer_;
176 scoped_ptr<OAuth2AccessTokenFetcher> fetcher_;
178 // Variables that store fetch results.
179 // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle
180 // destruction.
181 GoogleServiceAuthError error_;
182 std::string access_token_;
183 base::Time expiration_date_;
185 // OAuth2 client id and secret.
186 std::string client_id_;
187 std::string client_secret_;
189 DISALLOW_COPY_AND_ASSIGN(Fetcher);
192 // static
193 OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart(
194 OAuth2TokenService* oauth2_token_service,
195 const std::string& account_id,
196 net::URLRequestContextGetter* getter,
197 const std::string& client_id,
198 const std::string& client_secret,
199 const OAuth2TokenService::ScopeSet& scopes,
200 base::WeakPtr<RequestImpl> waiting_request) {
201 OAuth2TokenService::Fetcher* fetcher = new Fetcher(
202 oauth2_token_service,
203 account_id,
204 getter,
205 client_id,
206 client_secret,
207 scopes,
208 waiting_request);
210 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
211 // fixed.
212 tracked_objects::ScopedTracker tracking_profile(
213 FROM_HERE_WITH_EXPLICIT_FUNCTION(
214 "422460 OAuth2TokenService::Fetcher::CreateAndStart"));
216 fetcher->Start();
217 return fetcher;
220 OAuth2TokenService::Fetcher::Fetcher(
221 OAuth2TokenService* oauth2_token_service,
222 const std::string& account_id,
223 net::URLRequestContextGetter* getter,
224 const std::string& client_id,
225 const std::string& client_secret,
226 const OAuth2TokenService::ScopeSet& scopes,
227 base::WeakPtr<RequestImpl> waiting_request)
228 : oauth2_token_service_(oauth2_token_service),
229 getter_(getter),
230 account_id_(account_id),
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 waiting_requests_.push_back(waiting_request);
240 OAuth2TokenService::Fetcher::~Fetcher() {
241 // Inform the waiting requests if it has not done so.
242 if (waiting_requests_.size())
243 InformWaitingRequests();
246 void OAuth2TokenService::Fetcher::Start() {
247 fetcher_.reset(oauth2_token_service_->CreateAccessTokenFetcher(
248 account_id_, getter_.get(), this));
249 DCHECK(fetcher_);
251 // Stop the timer before starting the fetch, as defense in depth against the
252 // fetcher calling us back synchronously (which might restart the timer).
253 retry_timer_.Stop();
254 fetcher_->Start(client_id_,
255 client_secret_,
256 std::vector<std::string>(scopes_.begin(), scopes_.end()));
259 void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
260 const std::string& access_token,
261 const base::Time& expiration_date) {
262 fetcher_.reset();
264 // Fetch completes.
265 error_ = GoogleServiceAuthError::AuthErrorNone();
266 access_token_ = access_token;
267 expiration_date_ = expiration_date;
269 // Subclasses may override this method to skip caching in some cases, but
270 // we still inform all waiting Consumers of a successful token fetch below.
271 // This is intentional -- some consumers may need the token for cleanup
272 // tasks. https://chromiumcodereview.appspot.com/11312124/
273 oauth2_token_service_->RegisterCacheEntry(client_id_,
274 account_id_,
275 scopes_,
276 access_token_,
277 expiration_date_);
278 InformWaitingRequestsAndDelete();
281 void OAuth2TokenService::Fetcher::OnGetTokenFailure(
282 const GoogleServiceAuthError& error) {
283 fetcher_.reset();
285 if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) {
286 base::TimeDelta backoff = base::TimeDelta::FromMilliseconds(
287 ComputeExponentialBackOffMilliseconds(retry_number_));
288 ++retry_number_;
289 UMA_HISTOGRAM_ENUMERATION("Signin.OAuth2TokenGetRetry",
290 error.state(), GoogleServiceAuthError::NUM_STATES);
291 retry_timer_.Stop();
292 retry_timer_.Start(FROM_HERE,
293 backoff,
294 this,
295 &OAuth2TokenService::Fetcher::Start);
296 return;
299 UMA_HISTOGRAM_ENUMERATION("Signin.OAuth2TokenGetFailure",
300 error.state(), GoogleServiceAuthError::NUM_STATES);
301 error_ = error;
302 InformWaitingRequestsAndDelete();
305 // Returns an exponential backoff in milliseconds including randomness less than
306 // 1000 ms when retrying fetching an OAuth2 access token.
307 int64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
308 int retry_num) {
309 DCHECK(retry_num < max_fetch_retry_num_);
310 int64 exponential_backoff_in_seconds = 1 << retry_num;
311 // Returns a backoff with randomness < 1000ms
312 return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
315 // static
316 bool OAuth2TokenService::Fetcher::ShouldRetry(
317 const GoogleServiceAuthError& error) {
318 GoogleServiceAuthError::State error_state = error.state();
319 return error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
320 error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
321 error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
324 void OAuth2TokenService::Fetcher::InformWaitingRequests() {
325 std::vector<base::WeakPtr<RequestImpl> >::const_iterator iter =
326 waiting_requests_.begin();
327 for (; iter != waiting_requests_.end(); ++iter) {
328 base::WeakPtr<RequestImpl> waiting_request = *iter;
329 if (waiting_request.get())
330 waiting_request->InformConsumer(error_, access_token_, expiration_date_);
332 waiting_requests_.clear();
335 void OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
336 // Deregisters itself from the service to prevent more waiting requests to
337 // be added when it calls back the waiting requests.
338 oauth2_token_service_->OnFetchComplete(this);
339 InformWaitingRequests();
340 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
343 void OAuth2TokenService::Fetcher::AddWaitingRequest(
344 base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
345 waiting_requests_.push_back(waiting_request);
348 size_t OAuth2TokenService::Fetcher::GetWaitingRequestCount() const {
349 return waiting_requests_.size();
352 void OAuth2TokenService::Fetcher::Cancel() {
353 if (fetcher_)
354 fetcher_->CancelRequest();
355 fetcher_.reset();
356 retry_timer_.Stop();
357 error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
358 InformWaitingRequestsAndDelete();
361 const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet()
362 const {
363 return scopes_;
366 const std::string& OAuth2TokenService::Fetcher::GetClientId() const {
367 return client_id_;
370 const std::string& OAuth2TokenService::Fetcher::GetAccountId() const {
371 return account_id_;
374 OAuth2TokenService::Request::Request() {
377 OAuth2TokenService::Request::~Request() {
380 OAuth2TokenService::Consumer::Consumer(const std::string& id)
381 : id_(id) {}
383 OAuth2TokenService::Consumer::~Consumer() {
386 OAuth2TokenService::OAuth2TokenService(OAuth2TokenServiceDelegate* delegate)
387 : delegate_(delegate) {
388 DCHECK(delegate_);
391 OAuth2TokenService::~OAuth2TokenService() {
392 // Release all the pending fetchers.
393 STLDeleteContainerPairSecondPointers(
394 pending_fetchers_.begin(), pending_fetchers_.end());
397 OAuth2TokenServiceDelegate* OAuth2TokenService::GetDelegate() {
398 return delegate_.get();
401 void OAuth2TokenService::AddObserver(Observer* observer) {
402 delegate_->AddObserver(observer);
405 void OAuth2TokenService::RemoveObserver(Observer* observer) {
406 delegate_->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 scoped_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);
431 scoped_ptr<OAuth2TokenService::Request>
432 OAuth2TokenService::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);
447 net::URLRequestContextGetter* OAuth2TokenService::GetRequestContext() const {
448 return delegate_->GetRequestContext();
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"));
481 scoped_ptr<RequestImpl> request(new RequestImpl(account_id, consumer));
482 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
483 OnAccessTokenRequested(account_id,
484 consumer->id(),
485 scopes));
487 if (!RefreshTokenIsAvailable(account_id)) {
488 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
489 // is fixed.
490 tracked_objects::ScopedTracker tracking_profile2(
491 FROM_HERE_WITH_EXPLICIT_FUNCTION(
492 "422460 OAuth2TokenService::StartRequestForClientWithContext 2"));
494 GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
496 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
497 OnFetchAccessTokenComplete(
498 account_id, consumer->id(), scopes, error,
499 base::Time()));
501 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
502 &RequestImpl::InformConsumer,
503 request->AsWeakPtr(),
504 error,
505 std::string(),
506 base::Time()));
507 return request.Pass();
510 RequestParameters request_parameters(client_id,
511 account_id,
512 scopes);
513 if (HasCacheEntry(request_parameters)) {
514 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
515 // is fixed.
516 tracked_objects::ScopedTracker tracking_profile3(
517 FROM_HERE_WITH_EXPLICIT_FUNCTION(
518 "422460 OAuth2TokenService::StartRequestForClientWithContext 3"));
520 StartCacheLookupRequest(request.get(), request_parameters, consumer);
521 } else {
522 FetchOAuth2Token(request.get(),
523 account_id,
524 getter,
525 client_id,
526 client_secret,
527 scopes);
529 return request.Pass();
532 void OAuth2TokenService::FetchOAuth2Token(RequestImpl* request,
533 const std::string& account_id,
534 net::URLRequestContextGetter* getter,
535 const std::string& client_id,
536 const std::string& client_secret,
537 const ScopeSet& scopes) {
538 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
539 // fixed.
540 tracked_objects::ScopedTracker tracking_profile(
541 FROM_HERE_WITH_EXPLICIT_FUNCTION(
542 "422460 OAuth2TokenService::FetchOAuth2Token"));
544 // If there is already a pending fetcher for |scopes| and |account_id|,
545 // simply register this |request| for those results rather than starting
546 // a new fetcher.
547 RequestParameters request_parameters = RequestParameters(client_id,
548 account_id,
549 scopes);
550 std::map<RequestParameters, Fetcher*>::iterator iter =
551 pending_fetchers_.find(request_parameters);
552 if (iter != pending_fetchers_.end()) {
553 iter->second->AddWaitingRequest(request->AsWeakPtr());
554 return;
557 pending_fetchers_[request_parameters] =
558 Fetcher::CreateAndStart(this,
559 account_id,
560 getter,
561 client_id,
562 client_secret,
563 scopes,
564 request->AsWeakPtr());
567 OAuth2AccessTokenFetcher* OAuth2TokenService::CreateAccessTokenFetcher(
568 const std::string& account_id,
569 net::URLRequestContextGetter* getter,
570 OAuth2AccessTokenConsumer* consumer) {
571 return delegate_->CreateAccessTokenFetcher(account_id, getter, consumer);
574 void OAuth2TokenService::StartCacheLookupRequest(
575 RequestImpl* request,
576 const OAuth2TokenService::RequestParameters& request_parameters,
577 OAuth2TokenService::Consumer* consumer) {
578 CHECK(HasCacheEntry(request_parameters));
579 const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
580 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
581 OnFetchAccessTokenComplete(
582 request_parameters.account_id,
583 consumer->id(),
584 request_parameters.scopes,
585 GoogleServiceAuthError::AuthErrorNone(),
586 cache_entry->expiration_date));
587 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
588 &RequestImpl::InformConsumer,
589 request->AsWeakPtr(),
590 GoogleServiceAuthError(GoogleServiceAuthError::NONE),
591 cache_entry->access_token,
592 cache_entry->expiration_date));
595 std::vector<std::string> OAuth2TokenService::GetAccounts() const {
596 return delegate_->GetAccounts();
599 bool OAuth2TokenService::RefreshTokenIsAvailable(
600 const std::string& account_id) const {
601 return delegate_->RefreshTokenIsAvailable(account_id);
604 void OAuth2TokenService::RevokeAllCredentials() {
605 CancelAllRequests();
606 ClearCache();
607 delegate_->RevokeAllCredentials();
610 void OAuth2TokenService::InvalidateAccessToken(
611 const std::string& account_id,
612 const ScopeSet& scopes,
613 const std::string& access_token) {
614 InvalidateAccessTokenImpl(account_id,
615 GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
616 scopes, access_token);
619 void OAuth2TokenService::InvalidateAccessTokenForClient(
620 const std::string& account_id,
621 const std::string& client_id,
622 const ScopeSet& scopes,
623 const std::string& access_token) {
624 InvalidateAccessTokenImpl(account_id, client_id, scopes, access_token);
627 void OAuth2TokenService::InvalidateAccessTokenImpl(
628 const std::string& account_id,
629 const std::string& client_id,
630 const ScopeSet& scopes,
631 const std::string& access_token) {
632 DCHECK(CalledOnValidThread());
633 RemoveCacheEntry(
634 RequestParameters(client_id,
635 account_id,
636 scopes),
637 access_token);
638 delegate_->InvalidateAccessToken(account_id, client_id, scopes, access_token);
641 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
642 DCHECK(CalledOnValidThread());
644 // Update the auth error state so auth errors are appropriately communicated
645 // to the user.
646 UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
648 // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh
649 // token and scope set. This is guaranteed as follows; here a Fetcher is said
650 // to be uncompleted if it has not finished calling back
651 // OAuth2TokenService::OnFetchComplete().
653 // (1) All the live Fetchers are created by this service.
654 // This is because (1) all the live Fetchers are created by a live
655 // service, as all the fetchers created by a service are destructed in the
656 // service's dtor.
658 // (2) All the uncompleted Fetchers created by this service are recorded in
659 // |pending_fetchers_|.
660 // This is because (1) all the created Fetchers are added to
661 // |pending_fetchers_| (in method StartRequest()) and (2) method
662 // OnFetchComplete() is the only place where a Fetcher is erased from
663 // |pending_fetchers_|. Note no Fetcher is erased in method
664 // StartRequest().
666 // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its
667 // refresh token and ScopeSet. This is guaranteed by Fetcher creation in
668 // method StartRequest().
670 // When this method is called, |fetcher| is alive and uncompleted.
671 // By (1), |fetcher| is created by this service.
672 // Then by (2), |fetcher| is recorded in |pending_fetchers_|.
673 // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet.
674 RequestParameters request_param(fetcher->GetClientId(),
675 fetcher->GetAccountId(),
676 fetcher->GetScopeSet());
678 const OAuth2TokenService::CacheEntry* entry = GetCacheEntry(request_param);
679 const std::vector<base::WeakPtr<RequestImpl> >& requests =
680 fetcher->waiting_requests();
681 for (size_t i = 0; i < requests.size(); ++i) {
682 const RequestImpl* req = requests[i].get();
683 if (req) {
684 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
685 OnFetchAccessTokenComplete(
686 req->GetAccountId(), req->GetConsumerId(),
687 fetcher->GetScopeSet(), fetcher->error(),
688 entry ? entry->expiration_date : base::Time()));
692 std::map<RequestParameters, Fetcher*>::iterator iter =
693 pending_fetchers_.find(request_param);
694 DCHECK(iter != pending_fetchers_.end());
695 DCHECK_EQ(fetcher, iter->second);
696 pending_fetchers_.erase(iter);
699 bool OAuth2TokenService::HasCacheEntry(
700 const RequestParameters& request_parameters) {
701 const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
702 return cache_entry && cache_entry->access_token.length();
705 const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
706 const RequestParameters& request_parameters) {
707 DCHECK(CalledOnValidThread());
708 TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
709 if (token_iterator == token_cache_.end())
710 return NULL;
711 if (token_iterator->second.expiration_date <= base::Time::Now()) {
712 token_cache_.erase(token_iterator);
713 return NULL;
715 return &token_iterator->second;
718 bool OAuth2TokenService::RemoveCacheEntry(
719 const RequestParameters& request_parameters,
720 const std::string& token_to_remove) {
721 DCHECK(CalledOnValidThread());
722 TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
723 if (token_iterator != token_cache_.end() &&
724 token_iterator->second.access_token == token_to_remove) {
725 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
726 OnTokenRemoved(request_parameters.account_id,
727 request_parameters.scopes));
728 token_cache_.erase(token_iterator);
729 return true;
731 return false;
733 void OAuth2TokenService::UpdateAuthError(const std::string& account_id,
734 const GoogleServiceAuthError& error) {
735 delegate_->UpdateAuthError(account_id, error);
738 void OAuth2TokenService::RegisterCacheEntry(
739 const std::string& client_id,
740 const std::string& account_id,
741 const OAuth2TokenService::ScopeSet& scopes,
742 const std::string& access_token,
743 const base::Time& expiration_date) {
744 DCHECK(CalledOnValidThread());
746 CacheEntry& token = token_cache_[RequestParameters(client_id,
747 account_id,
748 scopes)];
749 token.access_token = access_token;
750 token.expiration_date = expiration_date;
753 void OAuth2TokenService::ClearCache() {
754 DCHECK(CalledOnValidThread());
755 for (TokenCache::iterator iter = token_cache_.begin();
756 iter != token_cache_.end(); ++iter) {
757 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
758 OnTokenRemoved(iter->first.account_id,
759 iter->first.scopes));
762 token_cache_.clear();
765 void OAuth2TokenService::ClearCacheForAccount(const std::string& account_id) {
766 DCHECK(CalledOnValidThread());
767 for (TokenCache::iterator iter = token_cache_.begin();
768 iter != token_cache_.end();
769 /* iter incremented in body */) {
770 if (iter->first.account_id == account_id) {
771 FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
772 OnTokenRemoved(account_id, iter->first.scopes));
773 token_cache_.erase(iter++);
774 } else {
775 ++iter;
780 void OAuth2TokenService::CancelAllRequests() {
781 std::vector<Fetcher*> fetchers_to_cancel;
782 for (std::map<RequestParameters, Fetcher*>::iterator iter =
783 pending_fetchers_.begin();
784 iter != pending_fetchers_.end();
785 ++iter) {
786 fetchers_to_cancel.push_back(iter->second);
788 CancelFetchers(fetchers_to_cancel);
791 void OAuth2TokenService::CancelRequestsForAccount(
792 const std::string& account_id) {
793 std::vector<Fetcher*> fetchers_to_cancel;
794 for (std::map<RequestParameters, Fetcher*>::iterator iter =
795 pending_fetchers_.begin();
796 iter != pending_fetchers_.end();
797 ++iter) {
798 if (iter->first.account_id == account_id)
799 fetchers_to_cancel.push_back(iter->second);
801 CancelFetchers(fetchers_to_cancel);
804 void OAuth2TokenService::CancelFetchers(
805 std::vector<Fetcher*> fetchers_to_cancel) {
806 for (std::vector<OAuth2TokenService::Fetcher*>::iterator iter =
807 fetchers_to_cancel.begin();
808 iter != fetchers_to_cancel.end();
809 ++iter) {
810 (*iter)->Cancel();
814 void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
815 int max_retries) {
816 DCHECK(CalledOnValidThread());
817 max_fetch_retry_num_ = max_retries;
820 size_t OAuth2TokenService::GetNumPendingRequestsForTesting(
821 const std::string& client_id,
822 const std::string& account_id,
823 const ScopeSet& scopes) const {
824 PendingFetcherMap::const_iterator iter = pending_fetchers_.find(
825 OAuth2TokenService::RequestParameters(
826 client_id,
827 account_id,
828 scopes));
829 return iter == pending_fetchers_.end() ?
830 0 : iter->second->GetWaitingRequestCount();