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