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