oauth2_token_service.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint OAuth2TokenService::max_fetch_retry_num_ = 5;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)OAuth2TokenService::RequestParameters::RequestParameters(
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const ScopeSet& scopes)
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : client_id(client_id),
2768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id(account_id),
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      scopes(scopes) {
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)OAuth2TokenService::RequestParameters::~RequestParameters() {
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool OAuth2TokenService::RequestParameters::operator<(
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const RequestParameters& p) const {
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (client_id < p.client_id)
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return true;
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  else if (p.client_id < client_id)
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (account_id < p.account_id)
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return true;
4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  else if (p.account_id < account_id)
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return scopes < p.scopes;
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::RequestImpl::RequestImpl(
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OAuth2TokenService::Consumer* consumer)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : consumer_(consumer) {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::RequestImpl::~RequestImpl() {
55424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::RequestImpl::InformConsumer(
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GoogleServiceAuthError& error,
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& access_token,
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time& expiration_date) {
62424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error.state() == GoogleServiceAuthError::NONE)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    consumer_->OnGetTokenFailure(this, error);
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Class that fetches an OAuth2 access token for a given set of scopes and
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// OAuth2 refresh token.
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Class that fetches OAuth2 access tokens for given scopes and refresh token.
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// It aims to meet OAuth2TokenService's requirements on token fetching. Retry
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// mechanism is used to handle failures.
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// To use this class, call CreateAndStart() to create and start a Fetcher.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The Fetcher will call back the service by calling
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// not destructed before it completes fetching; if the Fetcher is destructed
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// before it completes fetching, the service will never be called back. The
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Fetcher destructs itself after calling back the service when finishes
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// fetching.
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Requests that are waiting for the fetching results of this Fetcher can be
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// added to the Fetcher by calling
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// completes fetching.
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// The waiting requests are taken as weak pointers and they can be deleted.
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// The waiting requests will be called back with fetching results if they are
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// not deleted
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - when the Fetcher completes fetching, if the Fetcher is not destructed
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//   before it completes fetching, or
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - when the Fetcher is destructed if the Fetcher is destructed before it
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//   completes fetching (in this case, the waiting requests will be called
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//   back with error).
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creates a Fetcher and starts fetching an OAuth2 access token for
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |refresh_token| and |scopes| in the request context obtained by |getter|.
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The given |oauth2_token_service| will be informed when fetching is done.
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service,
10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                 const std::string& account_id,
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 net::URLRequestContextGetter* getter,
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 const std::string& client_id,
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 const std::string& client_secret,
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 const std::string& refresh_token,
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 const ScopeSet& scopes,
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 base::WeakPtr<RequestImpl> waiting_request);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~Fetcher();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add a request that is waiting for the result of this Fetcher.
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request);
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Returns count of waiting requests.
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  size_t GetWaitingRequestCount() const;
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Cancel();
121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const ScopeSet& GetScopeSet() const;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string& GetRefreshToken() const;
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const std::string& GetClientId() const;
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const std::string& GetAccountId() const;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The error result from this fetcher.
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const GoogleServiceAuthError& error() const { return error_; }
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected:
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   // OAuth2AccessTokenConsumer
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnGetTokenSuccess(const std::string& access_token,
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 const base::Time& expiration_date) OVERRIDE;
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual void OnGetTokenFailure(
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      const GoogleServiceAuthError& error) OVERRIDE;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Fetcher(OAuth2TokenService* oauth2_token_service,
13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          const std::string& account_id,
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          net::URLRequestContextGetter* getter,
14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          const std::string& client_id,
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          const std::string& client_secret,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          const std::string& refresh_token,
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          const OAuth2TokenService::ScopeSet& scopes,
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::WeakPtr<RequestImpl> waiting_request);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start();
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void InformWaitingRequests();
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void InformWaitingRequestsAndDelete();
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static bool ShouldRetry(const GoogleServiceAuthError& error);
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 ComputeExponentialBackOffMilliseconds(int retry_num);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |oauth2_token_service_| remains valid for the life of this Fetcher, since
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // (whichever comes first).
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OAuth2TokenService* const oauth2_token_service_;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<net::URLRequestContextGetter> getter_;
15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const std::string account_id_;
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string refresh_token_;
16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const ScopeSet scopes_;
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::WeakPtr<RequestImpl> > waiting_requests_;
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int retry_number_;
16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::OneShotTimer<Fetcher> retry_timer_;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<OAuth2AccessTokenFetcher> fetcher_;
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Variables that store fetch results.
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // destruction.
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GoogleServiceAuthError error_;
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string access_token_;
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Time expiration_date_;
17358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
174a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // OAuth2 client id and secret.
17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string client_id_;
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string client_secret_;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Fetcher);
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart(
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OAuth2TokenService* oauth2_token_service,
18468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* getter,
18658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
18758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_secret,
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& refresh_token,
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<RequestImpl> waiting_request) {
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OAuth2TokenService::Fetcher* fetcher = new Fetcher(
192a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      oauth2_token_service,
19368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id,
194a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      getter,
19558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client_id,
19658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client_secret,
197a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      refresh_token,
198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scopes,
199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      waiting_request);
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher->Start();
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return fetcher;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Fetcher::Fetcher(
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OAuth2TokenService* oauth2_token_service,
20668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* getter,
20858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_secret,
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& refresh_token,
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<RequestImpl> waiting_request)
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : oauth2_token_service_(oauth2_token_service),
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      getter_(getter),
21568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id_(account_id),
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      refresh_token_(refresh_token),
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scopes_(scopes),
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      retry_number_(0),
219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client_id_(client_id),
22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client_secret_(client_secret) {
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(oauth2_token_service_);
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(getter_.get());
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(refresh_token_.length());
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  waiting_requests_.push_back(waiting_request);
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Fetcher::~Fetcher() {
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Inform the waiting requests if it has not done so.
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (waiting_requests_.size())
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InformWaitingRequests();
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::Start() {
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  fetcher_.reset(new OAuth2AccessTokenFetcher(this, getter_.get()));
23658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  fetcher_->Start(client_id_,
23758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                  client_secret_,
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  refresh_token_,
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  std::vector<std::string>(scopes_.begin(), scopes_.end()));
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  retry_timer_.Stop();
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& access_token,
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time& expiration_date) {
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher_.reset();
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fetch completes.
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  error_ = GoogleServiceAuthError::AuthErrorNone();
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  access_token_ = access_token;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expiration_date_ = expiration_date;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Subclasses may override this method to skip caching in some cases, but
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // we still inform all waiting Consumers of a successful token fetch below.
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // This is intentional -- some consumers may need the token for cleanup
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // tasks. https://chromiumcodereview.appspot.com/11312124/
25758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  oauth2_token_service_->RegisterCacheEntry(client_id_,
25868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                            account_id_,
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            scopes_,
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            access_token_,
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            expiration_date_);
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  InformWaitingRequestsAndDelete();
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::OnGetTokenFailure(
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GoogleServiceAuthError& error) {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher_.reset();
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) {
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 backoff = ComputeExponentialBackOffMilliseconds(retry_number_);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++retry_number_;
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    retry_timer_.Stop();
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    retry_timer_.Start(FROM_HERE,
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       base::TimeDelta::FromMilliseconds(backoff),
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       this,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       &OAuth2TokenService::Fetcher::Start);
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_ = error;
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  InformWaitingRequestsAndDelete();
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Returns an exponential backoff in milliseconds including randomness less than
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// 1000 ms when retrying fetching an OAuth2 access token.
286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int retry_num) {
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(retry_num < max_fetch_retry_num_);
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 exponential_backoff_in_seconds = 1 << retry_num;
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Returns a backoff with randomness < 1000ms
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool OAuth2TokenService::Fetcher::ShouldRetry(
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GoogleServiceAuthError& error) {
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GoogleServiceAuthError::State error_state = error.state();
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::InformWaitingRequests() {
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::WeakPtr<RequestImpl> >::const_iterator iter =
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      waiting_requests_.begin();
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (; iter != waiting_requests_.end(); ++iter) {
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<RequestImpl> waiting_request = *iter;
308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (waiting_request.get())
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      waiting_request->InformConsumer(error_, access_token_, expiration_date_);
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  waiting_requests_.clear();
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Deregisters itself from the service to prevent more waiting requests to
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // be added when it calls back the waiting requests.
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  oauth2_token_service_->OnFetchComplete(this);
318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  InformWaitingRequests();
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::Fetcher::AddWaitingRequest(
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  waiting_requests_.push_back(waiting_request);
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
32758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)size_t OAuth2TokenService::Fetcher::GetWaitingRequestCount() const {
32858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return waiting_requests_.size();
32958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
33058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
331a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void OAuth2TokenService::Fetcher::Cancel() {
332a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  fetcher_.reset();
333a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  retry_timer_.Stop();
334a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
335a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  InformWaitingRequestsAndDelete();
336a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
337a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet()
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const {
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return scopes_;
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string& OAuth2TokenService::Fetcher::GetRefreshToken() const {
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return refresh_token_;
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const std::string& OAuth2TokenService::Fetcher::GetClientId() const {
34858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return client_id_;
34958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
35058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
35168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const std::string& OAuth2TokenService::Fetcher::GetAccountId() const {
35268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return account_id_;
35368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
35468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Request::Request() {
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Request::~Request() {
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Consumer::Consumer() {
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::Consumer::~Consumer() {
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
367ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochOAuth2TokenService::OAuth2TokenService() {
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2TokenService::~OAuth2TokenService() {
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Release all the pending fetchers.
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteContainerPairSecondPointers(
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pending_fetchers_.begin(), pending_fetchers_.end());
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::AddObserver(Observer* observer) {
3777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  observer_list_.AddObserver(observer);
3787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::RemoveObserver(Observer* observer) {
3817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  observer_list_.RemoveObserver(observer);
3827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
38468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool OAuth2TokenService::RefreshTokenIsAvailable(
38568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id) {
38668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(CalledOnValidThread());
38768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return !GetRefreshToken(account_id).empty();
38868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
38968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
39068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::vector<std::string> OAuth2TokenService::GetAccounts() {
39168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return std::vector<std::string>();
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
39568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OAuth2TokenService::Consumer* consumer) {
398a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return StartRequestForClientWithContext(
39968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id,
400a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GetRequestContext(),
401a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
402a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
403a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scopes,
404a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      consumer);
405a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
406a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
407a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)scoped_ptr<OAuth2TokenService::Request>
408a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)OAuth2TokenService::StartRequestForClient(
40968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
410a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_id,
411a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_secret,
412a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
413a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    OAuth2TokenService::Consumer* consumer) {
414a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return StartRequestForClientWithContext(
41568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id,
416a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GetRequestContext(),
417a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      client_id,
418a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      client_secret,
419a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scopes,
420a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      consumer);
42158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
42258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
42358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochscoped_ptr<OAuth2TokenService::Request>
42458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben MurdochOAuth2TokenService::StartRequestWithContext(
42568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
42658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    net::URLRequestContextGetter* getter,
42758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    const ScopeSet& scopes,
42858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    Consumer* consumer) {
429a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return StartRequestForClientWithContext(
43068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id,
431a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      getter,
432a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
433a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
434a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scopes,
435a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      consumer);
436a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
437a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
438a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)scoped_ptr<OAuth2TokenService::Request>
439a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)OAuth2TokenService::StartRequestForClientWithContext(
44068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
441a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    net::URLRequestContextGetter* getter,
442a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_id,
443a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_secret,
444a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const ScopeSet& scopes,
445a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    Consumer* consumer) {
446424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
44868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  scoped_ptr<RequestImpl> request = CreateRequest(consumer);
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
45068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!RefreshTokenIsAvailable(account_id)) {
45190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
452868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &RequestImpl::InformConsumer,
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request->AsWeakPtr(),
4543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP),
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string(),
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Time()));
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return request.PassAs<Request>();
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
46068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RequestParameters request_parameters(client_id,
46168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                       account_id,
46268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                       scopes);
46368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (HasCacheEntry(request_parameters)) {
46468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    StartCacheLookupRequest(request.get(), request_parameters, consumer);
4653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
4663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    FetchOAuth2Token(request.get(),
46768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     account_id,
4683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     getter,
4693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     client_id,
4703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     client_secret,
4713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     scopes);
4723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return request.PassAs<Request>();
4743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
47668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)scoped_ptr<OAuth2TokenService::RequestImpl> OAuth2TokenService::CreateRequest(
47768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    Consumer* consumer) {
47868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return scoped_ptr<RequestImpl>(new RequestImpl(consumer));
47968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
48068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void OAuth2TokenService::FetchOAuth2Token(RequestImpl* request,
48268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                          const std::string& account_id,
4833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          net::URLRequestContextGetter* getter,
4843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          const std::string& client_id,
4853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          const std::string& client_secret,
4863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          const ScopeSet& scopes) {
48768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string refresh_token = GetRefreshToken(account_id);
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
48968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // If there is already a pending fetcher for |scopes| and |account_id|,
490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // simply register this |request| for those results rather than starting
491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // a new fetcher.
49268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RequestParameters request_parameters = RequestParameters(client_id,
49368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                           account_id,
49468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                           scopes);
49568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::map<RequestParameters, Fetcher*>::iterator iter =
49668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      pending_fetchers_.find(request_parameters);
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (iter != pending_fetchers_.end()) {
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iter->second->AddWaitingRequest(request->AsWeakPtr());
4993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
50268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  pending_fetchers_[request_parameters] =
503a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      Fetcher::CreateAndStart(this,
50468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                              account_id,
505a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              getter,
506a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              client_id,
507a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              client_secret,
508a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              refresh_token,
509a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              scopes,
510868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              request->AsWeakPtr());
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void OAuth2TokenService::StartCacheLookupRequest(
5143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    RequestImpl* request,
51568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const OAuth2TokenService::RequestParameters& request_parameters,
5163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    OAuth2TokenService::Consumer* consumer) {
51768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CHECK(HasCacheEntry(request_parameters));
51868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
520868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      &RequestImpl::InformConsumer,
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      request->AsWeakPtr(),
522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GoogleServiceAuthError(GoogleServiceAuthError::NONE),
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cache_entry->access_token,
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cache_entry->expiration_date));
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::InvalidateToken(const std::string& account_id,
52868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                         const ScopeSet& scopes,
52968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                         const std::string& access_token) {
53068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  InvalidateOAuth2Token(account_id,
53168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
53268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        scopes,
53368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        access_token);
53468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
53568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
53668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::InvalidateTokenForClient(
53768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
53868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& client_id,
53968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const ScopeSet& scopes,
54068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& access_token) {
54168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  InvalidateOAuth2Token(account_id, client_id, scopes, access_token);
54268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
54368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
54468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::InvalidateOAuth2Token(
54568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
54668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& client_id,
54768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const ScopeSet& scopes,
54868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& access_token) {
549424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
55058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RemoveCacheEntry(
55168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      RequestParameters(client_id,
55268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        account_id,
55368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                        scopes),
55468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      access_token);
555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
558424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the auth error state so auth errors are appropriately communicated
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to the user.
56268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // token and scope set. This is guaranteed as follows; here a Fetcher is said
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to be uncompleted if it has not finished calling back
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // OAuth2TokenService::OnFetchComplete().
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (1) All the live Fetchers are created by this service.
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     This is because (1) all the live Fetchers are created by a live
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     service, as all the fetchers created by a service are destructed in the
572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //     service's dtor.
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (2) All the uncompleted Fetchers created by this service are recorded in
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     |pending_fetchers_|.
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     This is because (1) all the created Fetchers are added to
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     |pending_fetchers_| (in method StartRequest()) and (2) method
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     OnFetchComplete() is the only place where a Fetcher is erased from
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     |pending_fetchers_|. Note no Fetcher is erased in method
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     StartRequest().
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //     refresh token and ScopeSet. This is guaranteed by Fetcher creation in
584c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //     method StartRequest().
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When this method is called, |fetcher| is alive and uncompleted.
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // By (1), |fetcher| is created by this service.
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Then by (2), |fetcher| is recorded in |pending_fetchers_|.
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet.
59068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::map<RequestParameters, Fetcher*>::iterator iter =
59168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    pending_fetchers_.find(RequestParameters(
59258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        fetcher->GetClientId(),
59368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        fetcher->GetAccountId(),
59458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        fetcher->GetScopeSet()));
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(iter != pending_fetchers_.end());
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(fetcher, iter->second);
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pending_fetchers_.erase(iter);
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool OAuth2TokenService::HasCacheEntry(
60168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const RequestParameters& request_parameters) {
60268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return cache_entry && cache_entry->access_token.length();
604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
60768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const RequestParameters& request_parameters) {
608424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
60968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (token_iterator == token_cache_.end())
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (token_iterator->second.expiration_date <= base::Time::Now()) {
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token_cache_.erase(token_iterator);
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return &token_iterator->second;
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool OAuth2TokenService::RemoveCacheEntry(
62068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const RequestParameters& request_parameters,
621c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& token_to_remove) {
622424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
62368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
624868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (token_iterator != token_cache_.end() &&
625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      token_iterator->second.access_token == token_to_remove) {
626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    token_cache_.erase(token_iterator);
627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2TokenService::RegisterCacheEntry(
63358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
63468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& access_token,
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time& expiration_date) {
638424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
64068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CacheEntry& token = token_cache_[RequestParameters(client_id,
64168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     account_id,
64268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     scopes)];
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  token.access_token = access_token;
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  token.expiration_date = expiration_date;
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
64768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::UpdateAuthError(
64868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
64968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const GoogleServiceAuthError& error) {
650c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Default implementation does nothing.
651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void OAuth2TokenService::ClearCache() {
654424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  token_cache_.clear();
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
65868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::ClearCacheForAccount(const std::string& account_id) {
65968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(CalledOnValidThread());
66068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (TokenCache::iterator iter = token_cache_.begin();
66168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)       iter != token_cache_.end();
66268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)       /* iter incremented in body */) {
66368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (iter->first.account_id == account_id) {
66468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      token_cache_.erase(iter++);
66568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    } else {
66668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ++iter;
66768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
66868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
66968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
67068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
671a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void OAuth2TokenService::CancelAllRequests() {
672a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::vector<Fetcher*> fetchers_to_cancel;
67368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (std::map<RequestParameters, Fetcher*>::iterator iter =
674a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)           pending_fetchers_.begin();
675a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       iter != pending_fetchers_.end();
676a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       ++iter) {
677a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    fetchers_to_cancel.push_back(iter->second);
678a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
679a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  CancelFetchers(fetchers_to_cancel);
680a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
681a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
68268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OAuth2TokenService::CancelRequestsForAccount(
68368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id) {
684a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::vector<Fetcher*> fetchers_to_cancel;
68568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (std::map<RequestParameters, Fetcher*>::iterator iter =
686a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)           pending_fetchers_.begin();
687a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       iter != pending_fetchers_.end();
688a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       ++iter) {
68968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (iter->first.account_id == account_id)
690a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      fetchers_to_cancel.push_back(iter->second);
691a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
692a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  CancelFetchers(fetchers_to_cancel);
693a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
694a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
695a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void OAuth2TokenService::CancelFetchers(
696a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::vector<Fetcher*> fetchers_to_cancel) {
697a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (std::vector<OAuth2TokenService::Fetcher*>::iterator iter =
698a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)           fetchers_to_cancel.begin();
699a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       iter != fetchers_to_cancel.end();
700a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       ++iter) {
701a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    (*iter)->Cancel();
702a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
703a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
704a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
7057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::FireRefreshTokenAvailable(
7067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& account_id) {
7077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  FOR_EACH_OBSERVER(Observer, observer_list_,
7087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    OnRefreshTokenAvailable(account_id));
7097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::FireRefreshTokenRevoked(
7123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& account_id) {
7137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  FOR_EACH_OBSERVER(Observer, observer_list_,
7143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    OnRefreshTokenRevoked(account_id));
7157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenService::FireRefreshTokensLoaded() {
7187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  FOR_EACH_OBSERVER(Observer, observer_list_, OnRefreshTokensLoaded());
7197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
721c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int OAuth2TokenService::cache_size_for_testing() const {
722c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return token_cache_.size();
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
724eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
725eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
726eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int max_retries) {
727424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
728eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  max_fetch_retry_num_ = max_retries;
729eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
73058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
73158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)size_t OAuth2TokenService::GetNumPendingRequestsForTesting(
73258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& client_id,
73368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
73458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const ScopeSet& scopes) const {
73558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  PendingFetcherMap::const_iterator iter = pending_fetchers_.find(
73668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      OAuth2TokenService::RequestParameters(
73758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          client_id,
73868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          account_id,
73958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          scopes));
74058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return iter == pending_fetchers_.end() ?
74158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)             0 : iter->second->GetWaitingRequestCount();
74258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
743