1424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "google_apis/gaia/oauth2_token_service.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <vector>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/weak_ptr.h"
119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint OAuth2TokenService::max_fetch_retry_num_ = 5;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)OAuth2TokenService::RequestParameters::RequestParameters(
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
2568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const ScopeSet& scopes)
2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : client_id(client_id),
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id(account_id),
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      scopes(scopes) {
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)OAuth2TokenService::RequestParameters::~RequestParameters() {
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool OAuth2TokenService::RequestParameters::operator<(
3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const RequestParameters& p) const {
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (client_id < p.client_id)
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return true;
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  else if (p.client_id < client_id)
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (account_id < p.account_id)
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return true;
4468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  else if (p.account_id < account_id)
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return scopes < p.scopes;
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::RequestImpl::RequestImpl(
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& account_id,
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OAuth2TokenService::Consumer* consumer)
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : account_id_(account_id),
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      consumer_(consumer) {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::RequestImpl::~RequestImpl() {
58424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::string OAuth2TokenService::RequestImpl::GetAccountId() const {
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return account_id_;
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string OAuth2TokenService::RequestImpl::GetConsumerId() const {
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return consumer_->id();
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::RequestImpl::InformConsumer(
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GoogleServiceAuthError& error,
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& access_token,
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time& expiration_date) {
73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error.state() == GoogleServiceAuthError::NONE)
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    consumer_->OnGetTokenFailure(this, error);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
80116680a4aac90f2aa7413d9095a592090648e557Ben MurdochOAuth2TokenService::ScopedBacthChange::ScopedBacthChange(
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    OAuth2TokenService* token_service) : token_service_(token_service) {
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(token_service_);
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  token_service_->StartBatchChanges();
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
86116680a4aac90f2aa7413d9095a592090648e557Ben MurdochOAuth2TokenService::ScopedBacthChange::~ScopedBacthChange() {
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  token_service_->EndBatchChanges();
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Class that fetches an OAuth2 access token for a given account id and set of
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// scopes.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// It aims to meet OAuth2TokenService's requirements on token fetching. Retry
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// mechanism is used to handle failures.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// To use this class, call CreateAndStart() to create and start a Fetcher.
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The Fetcher will call back the service by calling
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// not destructed before it completes fetching; if the Fetcher is destructed
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// before it completes fetching, the service will never be called back. The
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Fetcher destructs itself after calling back the service when finishes
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// fetching.
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Requests that are waiting for the fetching results of this Fetcher can be
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// added to the Fetcher by calling
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// completes fetching.
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// The waiting requests are taken as weak pointers and they can be deleted.
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// The waiting requests will be called back with fetching results if they are
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// not deleted
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - when the Fetcher completes fetching, if the Fetcher is not destructed
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//   before it completes fetching, or
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - when the Fetcher is destructed if the Fetcher is destructed before it
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//   completes fetching (in this case, the waiting requests will be called
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//   back with error).
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creates a Fetcher and starts fetching an OAuth2 access token for
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // |account_id| and |scopes| in the request context obtained by |getter|.
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The given |oauth2_token_service| will be informed when fetching is done.
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service,
12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                 const std::string& account_id,
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 net::URLRequestContextGetter* getter,
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 const std::string& client_id,
12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 const std::string& client_secret,
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 const ScopeSet& scopes,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 base::WeakPtr<RequestImpl> waiting_request);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~Fetcher();
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add a request that is waiting for the result of this Fetcher.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request);
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Returns count of waiting requests.
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  size_t GetWaitingRequestCount() const;
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::vector<base::WeakPtr<RequestImpl> >& waiting_requests() const {
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return waiting_requests_;
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
142a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Cancel();
143a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const ScopeSet& GetScopeSet() const;
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const std::string& GetClientId() const;
14668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const std::string& GetAccountId() const;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The error result from this fetcher.
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const GoogleServiceAuthError& error() const { return error_; }
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected:
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   // OAuth2AccessTokenConsumer
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnGetTokenSuccess(const std::string& access_token,
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 const base::Time& expiration_date) OVERRIDE;
15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual void OnGetTokenFailure(
15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      const GoogleServiceAuthError& error) OVERRIDE;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Fetcher(OAuth2TokenService* oauth2_token_service,
16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          const std::string& account_id,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          net::URLRequestContextGetter* getter,
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          const std::string& client_id,
16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          const std::string& client_secret,
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          const OAuth2TokenService::ScopeSet& scopes,
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::WeakPtr<RequestImpl> waiting_request);
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start();
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void InformWaitingRequests();
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void InformWaitingRequestsAndDelete();
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static bool ShouldRetry(const GoogleServiceAuthError& error);
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 ComputeExponentialBackOffMilliseconds(int retry_num);
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |oauth2_token_service_| remains valid for the life of this Fetcher, since
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // (whichever comes first).
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OAuth2TokenService* const oauth2_token_service_;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<net::URLRequestContextGetter> getter_;
17868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const std::string account_id_;
17958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const ScopeSet scopes_;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::WeakPtr<RequestImpl> > waiting_requests_;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int retry_number_;
18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::OneShotTimer<Fetcher> retry_timer_;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<OAuth2AccessTokenFetcher> fetcher_;
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Variables that store fetch results.
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // destruction.
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GoogleServiceAuthError error_;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string access_token_;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Time expiration_date_;
19258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
193a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // OAuth2 client id and secret.
19458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string client_id_;
19558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string client_secret_;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Fetcher);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart(
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OAuth2TokenService* oauth2_token_service,
20368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* getter,
20558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
20658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_secret,
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<RequestImpl> waiting_request) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OAuth2TokenService::Fetcher* fetcher = new Fetcher(
210a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      oauth2_token_service,
21168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id,
212a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      getter,
21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client_id,
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client_secret,
215a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scopes,
216a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      waiting_request);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher->Start();
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return fetcher;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Fetcher::Fetcher(
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OAuth2TokenService* oauth2_token_service,
22368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* getter,
22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_secret,
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<RequestImpl> waiting_request)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : oauth2_token_service_(oauth2_token_service),
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      getter_(getter),
23168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id_(account_id),
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scopes_(scopes),
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      retry_number_(0),
234a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
23558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client_id_(client_id),
23658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client_secret_(client_secret) {
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(oauth2_token_service_);
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  waiting_requests_.push_back(waiting_request);
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Fetcher::~Fetcher() {
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Inform the waiting requests if it has not done so.
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (waiting_requests_.size())
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InformWaitingRequests();
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::Start() {
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  fetcher_.reset(oauth2_token_service_->CreateAccessTokenFetcher(
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      account_id_, getter_.get(), this));
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(fetcher_);
25158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  fetcher_->Start(client_id_,
25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                  client_secret_,
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  std::vector<std::string>(scopes_.begin(), scopes_.end()));
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  retry_timer_.Stop();
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& access_token,
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time& expiration_date) {
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher_.reset();
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fetch completes.
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  error_ = GoogleServiceAuthError::AuthErrorNone();
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  access_token_ = access_token;
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expiration_date_ = expiration_date;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Subclasses may override this method to skip caching in some cases, but
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // we still inform all waiting Consumers of a successful token fetch below.
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // This is intentional -- some consumers may need the token for cleanup
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // tasks. https://chromiumcodereview.appspot.com/11312124/
27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  oauth2_token_service_->RegisterCacheEntry(client_id_,
27268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                            account_id_,
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            scopes_,
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            access_token_,
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            expiration_date_);
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  InformWaitingRequestsAndDelete();
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::OnGetTokenFailure(
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GoogleServiceAuthError& error) {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher_.reset();
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) {
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::TimeDelta backoff = base::TimeDelta::FromMilliseconds(
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ComputeExponentialBackOffMilliseconds(retry_number_));
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++retry_number_;
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    retry_timer_.Stop();
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    retry_timer_.Start(FROM_HERE,
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       backoff,
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       this,
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       &OAuth2TokenService::Fetcher::Start);
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_ = error;
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  InformWaitingRequestsAndDelete();
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Returns an exponential backoff in milliseconds including randomness less than
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 1000 ms when retrying fetching an OAuth2 access token.
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int retry_num) {
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(retry_num < max_fetch_retry_num_);
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 exponential_backoff_in_seconds = 1 << retry_num;
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Returns a backoff with randomness < 1000ms
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool OAuth2TokenService::Fetcher::ShouldRetry(
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GoogleServiceAuthError& error) {
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GoogleServiceAuthError::State error_state = error.state();
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::InformWaitingRequests() {
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::WeakPtr<RequestImpl> >::const_iterator iter =
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      waiting_requests_.begin();
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (; iter != waiting_requests_.end(); ++iter) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<RequestImpl> waiting_request = *iter;
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (waiting_request.get())
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      waiting_request->InformConsumer(error_, access_token_, expiration_date_);
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  waiting_requests_.clear();
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Deregisters itself from the service to prevent more waiting requests to
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // be added when it calls back the waiting requests.
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  oauth2_token_service_->OnFetchComplete(this);
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  InformWaitingRequests();
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::AddWaitingRequest(
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  waiting_requests_.push_back(waiting_request);
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
34258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)size_t OAuth2TokenService::Fetcher::GetWaitingRequestCount() const {
34358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return waiting_requests_.size();
34458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
34558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
346a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void OAuth2TokenService::Fetcher::Cancel() {
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (fetcher_)
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    fetcher_->CancelRequest();
349a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  fetcher_.reset();
350a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  retry_timer_.Stop();
351a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
352a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  InformWaitingRequestsAndDelete();
353a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
354a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet()
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const {
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return scopes_;
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
36058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const std::string& OAuth2TokenService::Fetcher::GetClientId() const {
36158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return client_id_;
36258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
36358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
36468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const std::string& OAuth2TokenService::Fetcher::GetAccountId() const {
36568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return account_id_;
36668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
36768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Request::Request() {
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Request::~Request() {
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)OAuth2TokenService::Consumer::Consumer(const std::string& id)
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : id_(id) {}
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Consumer::~Consumer() {
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
380116680a4aac90f2aa7413d9095a592090648e557Ben MurdochOAuth2TokenService::OAuth2TokenService() : batch_change_depth_(0) {
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::~OAuth2TokenService() {
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Release all the pending fetchers.
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteContainerPairSecondPointers(
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pending_fetchers_.begin(), pending_fetchers_.end());
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::AddObserver(Observer* observer) {
3907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  observer_list_.AddObserver(observer);
3917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::RemoveObserver(Observer* observer) {
3947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  observer_list_.RemoveObserver(observer);
3957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void OAuth2TokenService::AddDiagnosticsObserver(DiagnosticsObserver* observer) {
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  diagnostics_observer_list_.AddObserver(observer);
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void OAuth2TokenService::RemoveDiagnosticsObserver(
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DiagnosticsObserver* observer) {
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  diagnostics_observer_list_.RemoveObserver(observer);
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
40668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::vector<std::string> OAuth2TokenService::GetAccounts() {
40768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return std::vector<std::string>();
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
41168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OAuth2TokenService::Consumer* consumer) {
414a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return StartRequestForClientWithContext(
41568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id,
416a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GetRequestContext(),
417a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
418a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
419a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scopes,
420a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      consumer);
421a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
422a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
423a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)scoped_ptr<OAuth2TokenService::Request>
424a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)OAuth2TokenService::StartRequestForClient(
42568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
426a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_id,
427a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_secret,
428a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
429a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    OAuth2TokenService::Consumer* consumer) {
430a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return StartRequestForClientWithContext(
43168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id,
432a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GetRequestContext(),
433a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      client_id,
434a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      client_secret,
435a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scopes,
436a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      consumer);
43758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
43858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
43958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochscoped_ptr<OAuth2TokenService::Request>
44058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben MurdochOAuth2TokenService::StartRequestWithContext(
44168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
44258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    net::URLRequestContextGetter* getter,
44358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    const ScopeSet& scopes,
44458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    Consumer* consumer) {
445a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return StartRequestForClientWithContext(
44668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id,
447a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      getter,
448a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
449a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
450a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scopes,
451a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      consumer);
452a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
453a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
454a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)scoped_ptr<OAuth2TokenService::Request>
455a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)OAuth2TokenService::StartRequestForClientWithContext(
45668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
457a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    net::URLRequestContextGetter* getter,
458a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_id,
459a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_secret,
460a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const ScopeSet& scopes,
461a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    Consumer* consumer) {
462424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
464a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<RequestImpl> request(new RequestImpl(account_id, consumer));
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    OnAccessTokenRequested(account_id,
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           consumer->id(),
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           scopes));
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
47068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!RefreshTokenIsAvailable(account_id)) {
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      OnFetchAccessTokenComplete(
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          account_id, consumer->id(), scopes, error,
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          base::Time()));
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
47890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
479868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &RequestImpl::InformConsumer,
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request->AsWeakPtr(),
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        error,
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string(),
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time()));
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return request.PassAs<Request>();
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
48768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RequestParameters request_parameters(client_id,
48868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                       account_id,
48968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                       scopes);
49068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (HasCacheEntry(request_parameters)) {
49168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    StartCacheLookupRequest(request.get(), request_parameters, consumer);
4923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
4933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    FetchOAuth2Token(request.get(),
49468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     account_id,
4953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     getter,
4963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     client_id,
4973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     client_secret,
4983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     scopes);
4993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return request.PassAs<Request>();
5013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void OAuth2TokenService::FetchOAuth2Token(RequestImpl* request,
50468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                          const std::string& account_id,
5053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          net::URLRequestContextGetter* getter,
5063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          const std::string& client_id,
5073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          const std::string& client_secret,
5083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          const ScopeSet& scopes) {
50968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // If there is already a pending fetcher for |scopes| and |account_id|,
510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // simply register this |request| for those results rather than starting
511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // a new fetcher.
51268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RequestParameters request_parameters = RequestParameters(client_id,
51368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                           account_id,
51468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                           scopes);
51568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::map<RequestParameters, Fetcher*>::iterator iter =
51668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      pending_fetchers_.find(request_parameters);
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (iter != pending_fetchers_.end()) {
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iter->second->AddWaitingRequest(request->AsWeakPtr());
5193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
521eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
52268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  pending_fetchers_[request_parameters] =
523a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      Fetcher::CreateAndStart(this,
52468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                              account_id,
525a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              getter,
526a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              client_id,
527a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              client_secret,
528a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              scopes,
529868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              request->AsWeakPtr());
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void OAuth2TokenService::StartCacheLookupRequest(
5333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    RequestImpl* request,
53468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const OAuth2TokenService::RequestParameters& request_parameters,
5353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    OAuth2TokenService::Consumer* consumer) {
53668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CHECK(HasCacheEntry(request_parameters));
53768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    OnFetchAccessTokenComplete(
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        request_parameters.account_id,
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        consumer->id(),
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        request_parameters.scopes,
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        GoogleServiceAuthError::AuthErrorNone(),
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        cache_entry->expiration_date));
54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
546868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      &RequestImpl::InformConsumer,
547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      request->AsWeakPtr(),
548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GoogleServiceAuthError(GoogleServiceAuthError::NONE),
549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cache_entry->access_token,
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cache_entry->expiration_date));
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
55368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::InvalidateToken(const std::string& account_id,
55468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                         const ScopeSet& scopes,
55568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                         const std::string& access_token) {
55668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  InvalidateOAuth2Token(account_id,
55768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
55868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        scopes,
55968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        access_token);
56068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
56168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
56268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::InvalidateTokenForClient(
56368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
56468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& client_id,
56568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const ScopeSet& scopes,
56668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& access_token) {
56768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  InvalidateOAuth2Token(account_id, client_id, scopes, access_token);
56868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
56968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
57068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::InvalidateOAuth2Token(
57168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
57268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& client_id,
57368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const ScopeSet& scopes,
57468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& access_token) {
575424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
57658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RemoveCacheEntry(
57768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      RequestParameters(client_id,
57868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        account_id,
57968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        scopes),
58068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      access_token);
581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
584424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the auth error state so auth errors are appropriately communicated
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to the user.
58868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // token and scope set. This is guaranteed as follows; here a Fetcher is said
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to be uncompleted if it has not finished calling back
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // OAuth2TokenService::OnFetchComplete().
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (1) All the live Fetchers are created by this service.
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     This is because (1) all the live Fetchers are created by a live
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     service, as all the fetchers created by a service are destructed in the
598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //     service's dtor.
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (2) All the uncompleted Fetchers created by this service are recorded in
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     |pending_fetchers_|.
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     This is because (1) all the created Fetchers are added to
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     |pending_fetchers_| (in method StartRequest()) and (2) method
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     OnFetchComplete() is the only place where a Fetcher is erased from
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     |pending_fetchers_|. Note no Fetcher is erased in method
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     StartRequest().
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     refresh token and ScopeSet. This is guaranteed by Fetcher creation in
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //     method StartRequest().
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When this method is called, |fetcher| is alive and uncompleted.
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // By (1), |fetcher| is created by this service.
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Then by (2), |fetcher| is recorded in |pending_fetchers_|.
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet.
6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RequestParameters request_param(fetcher->GetClientId(),
6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  fetcher->GetAccountId(),
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  fetcher->GetScopeSet());
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const OAuth2TokenService::CacheEntry* entry = GetCacheEntry(request_param);
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::vector<base::WeakPtr<RequestImpl> >& requests =
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fetcher->waiting_requests();
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < requests.size(); ++i) {
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const RequestImpl* req = requests[i].get();
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (req) {
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        OnFetchAccessTokenComplete(
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            req->GetAccountId(), req->GetConsumerId(),
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            fetcher->GetScopeSet(), fetcher->error(),
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            entry ? entry->expiration_date : base::Time()));
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
63468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::map<RequestParameters, Fetcher*>::iterator iter =
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pending_fetchers_.find(request_param);
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(iter != pending_fetchers_.end());
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(fetcher, iter->second);
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pending_fetchers_.erase(iter);
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
641c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool OAuth2TokenService::HasCacheEntry(
64268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const RequestParameters& request_parameters) {
64368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return cache_entry && cache_entry->access_token.length();
645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
64868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const RequestParameters& request_parameters) {
649424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
65068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (token_iterator == token_cache_.end())
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (token_iterator->second.expiration_date <= base::Time::Now()) {
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token_cache_.erase(token_iterator);
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return &token_iterator->second;
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool OAuth2TokenService::RemoveCacheEntry(
66168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const RequestParameters& request_parameters,
662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& token_to_remove) {
663424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
66468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
665868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (token_iterator != token_cache_.end() &&
666c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      token_iterator->second.access_token == token_to_remove) {
6675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
6685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      OnTokenRemoved(request_parameters.account_id,
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     request_parameters.scopes));
670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    token_cache_.erase(token_iterator);
671c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
673c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
674c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
675c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::RegisterCacheEntry(
67758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
67868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& access_token,
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time& expiration_date) {
682424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
68468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CacheEntry& token = token_cache_[RequestParameters(client_id,
68568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     account_id,
68668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     scopes)];
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  token.access_token = access_token;
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  token.expiration_date = expiration_date;
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
69168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::UpdateAuthError(
69268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
69368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const GoogleServiceAuthError& error) {
694c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Default implementation does nothing.
695c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
697c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void OAuth2TokenService::ClearCache() {
698424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (TokenCache::iterator iter = token_cache_.begin();
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != token_cache_.end(); ++iter) {
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
7025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      OnTokenRemoved(iter->first.account_id,
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     iter->first.scopes));
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  token_cache_.clear();
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
70968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::ClearCacheForAccount(const std::string& account_id) {
71068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(CalledOnValidThread());
71168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (TokenCache::iterator iter = token_cache_.begin();
71268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)       iter != token_cache_.end();
71368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)       /* iter incremented in body */) {
71468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (iter->first.account_id == account_id) {
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        OnTokenRemoved(account_id, iter->first.scopes));
71768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      token_cache_.erase(iter++);
71868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    } else {
71968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ++iter;
72068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
72168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
72268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
72368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
724a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void OAuth2TokenService::CancelAllRequests() {
725a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::vector<Fetcher*> fetchers_to_cancel;
72668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (std::map<RequestParameters, Fetcher*>::iterator iter =
727a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)           pending_fetchers_.begin();
728a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       iter != pending_fetchers_.end();
729a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       ++iter) {
730a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    fetchers_to_cancel.push_back(iter->second);
731a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
732a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  CancelFetchers(fetchers_to_cancel);
733a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
734a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
73568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::CancelRequestsForAccount(
73668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id) {
737a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::vector<Fetcher*> fetchers_to_cancel;
73868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (std::map<RequestParameters, Fetcher*>::iterator iter =
739a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)           pending_fetchers_.begin();
740a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       iter != pending_fetchers_.end();
741a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       ++iter) {
74268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (iter->first.account_id == account_id)
743a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      fetchers_to_cancel.push_back(iter->second);
744a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
745a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  CancelFetchers(fetchers_to_cancel);
746a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
747a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
748a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void OAuth2TokenService::CancelFetchers(
749a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::vector<Fetcher*> fetchers_to_cancel) {
750a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (std::vector<OAuth2TokenService::Fetcher*>::iterator iter =
751a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)           fetchers_to_cancel.begin();
752a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       iter != fetchers_to_cancel.end();
753a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       ++iter) {
754a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    (*iter)->Cancel();
755a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
756a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
757a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
7587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::FireRefreshTokenAvailable(
7597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& account_id) {
7607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  FOR_EACH_OBSERVER(Observer, observer_list_,
7617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    OnRefreshTokenAvailable(account_id));
7627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::FireRefreshTokenRevoked(
7653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& account_id) {
7667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  FOR_EACH_OBSERVER(Observer, observer_list_,
7673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    OnRefreshTokenRevoked(account_id));
7687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::FireRefreshTokensLoaded() {
7717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  FOR_EACH_OBSERVER(Observer, observer_list_, OnRefreshTokensLoaded());
7727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
774116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid OAuth2TokenService::StartBatchChanges() {
775116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ++batch_change_depth_;
776116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (batch_change_depth_ == 1)
777116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    FOR_EACH_OBSERVER(Observer, observer_list_, OnStartBatchChanges());
778116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
779116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
780116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid OAuth2TokenService::EndBatchChanges() {
781116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  --batch_change_depth_;
782116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_LE(0, batch_change_depth_);
783116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (batch_change_depth_ == 0)
784116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    FOR_EACH_OBSERVER(Observer, observer_list_, OnEndBatchChanges());
785116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
786116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
787c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int OAuth2TokenService::cache_size_for_testing() const {
788c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return token_cache_.size();
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
790eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
791eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
792eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int max_retries) {
793424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
794eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  max_fetch_retry_num_ = max_retries;
795eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
79658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
79758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)size_t OAuth2TokenService::GetNumPendingRequestsForTesting(
79858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
79968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
80058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const ScopeSet& scopes) const {
80158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  PendingFetcherMap::const_iterator iter = pending_fetchers_.find(
80268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      OAuth2TokenService::RequestParameters(
80358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          client_id,
80468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          account_id,
80558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          scopes));
80658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return iter == pending_fetchers_.end() ?
80758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)             0 : iter->second->GetWaitingRequestCount();
80858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
809