This source file includes following definitions.
- scopes
- consumer_
- GetAccountId
- GetConsumerId
- InformConsumer
- waiting_requests
- error
- CreateAndStart
- client_secret_
- Start
- OnGetTokenSuccess
- OnGetTokenFailure
- ComputeExponentialBackOffMilliseconds
- ShouldRetry
- InformWaitingRequests
- InformWaitingRequestsAndDelete
- AddWaitingRequest
- GetWaitingRequestCount
- Cancel
- GetScopeSet
- GetClientId
- GetAccountId
- AddObserver
- RemoveObserver
- AddDiagnosticsObserver
- RemoveDiagnosticsObserver
- GetAccounts
- StartRequest
- StartRequestForClient
- StartRequestWithContext
- StartRequestForClientWithContext
- FetchOAuth2Token
- StartCacheLookupRequest
- InvalidateToken
- InvalidateTokenForClient
- InvalidateOAuth2Token
- OnFetchComplete
- HasCacheEntry
- GetCacheEntry
- RemoveCacheEntry
- RegisterCacheEntry
- UpdateAuthError
- ClearCache
- ClearCacheForAccount
- CancelAllRequests
- CancelRequestsForAccount
- CancelFetchers
- FireRefreshTokenAvailable
- FireRefreshTokenRevoked
- FireRefreshTokensLoaded
- cache_size_for_testing
- set_max_authorization_token_fetch_retries_for_testing
- GetNumPendingRequestsForTesting
#include "google_apis/gaia/oauth2_token_service.h"
#include <vector>
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#include "net/url_request/url_request_context_getter.h"
int OAuth2TokenService::max_fetch_retry_num_ = 5;
OAuth2TokenService::RequestParameters::RequestParameters(
const std::string& client_id,
const std::string& account_id,
const ScopeSet& scopes)
: client_id(client_id),
account_id(account_id),
scopes(scopes) {
}
OAuth2TokenService::RequestParameters::~RequestParameters() {
}
bool OAuth2TokenService::RequestParameters::operator<(
const RequestParameters& p) const {
if (client_id < p.client_id)
return true;
else if (p.client_id < client_id)
return false;
if (account_id < p.account_id)
return true;
else if (p.account_id < account_id)
return false;
return scopes < p.scopes;
}
OAuth2TokenService::RequestImpl::RequestImpl(
const std::string& account_id,
OAuth2TokenService::Consumer* consumer)
: account_id_(account_id),
consumer_(consumer) {
}
OAuth2TokenService::RequestImpl::~RequestImpl() {
DCHECK(CalledOnValidThread());
}
std::string OAuth2TokenService::RequestImpl::GetAccountId() const {
return account_id_;
}
std::string OAuth2TokenService::RequestImpl::GetConsumerId() const {
return consumer_->id();
}
void OAuth2TokenService::RequestImpl::InformConsumer(
const GoogleServiceAuthError& error,
const std::string& access_token,
const base::Time& expiration_date) {
DCHECK(CalledOnValidThread());
if (error.state() == GoogleServiceAuthError::NONE)
consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
else
consumer_->OnGetTokenFailure(this, error);
}
class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
public:
static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service,
const std::string& account_id,
net::URLRequestContextGetter* getter,
const std::string& client_id,
const std::string& client_secret,
const ScopeSet& scopes,
base::WeakPtr<RequestImpl> waiting_request);
virtual ~Fetcher();
void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request);
size_t GetWaitingRequestCount() const;
const std::vector<base::WeakPtr<RequestImpl> >& waiting_requests() const {
return waiting_requests_;
}
void Cancel();
const ScopeSet& GetScopeSet() const;
const std::string& GetClientId() const;
const std::string& GetAccountId() const;
const GoogleServiceAuthError& error() const { return error_; }
protected:
virtual void OnGetTokenSuccess(const std::string& access_token,
const base::Time& expiration_date) OVERRIDE;
virtual void OnGetTokenFailure(
const GoogleServiceAuthError& error) OVERRIDE;
private:
Fetcher(OAuth2TokenService* oauth2_token_service,
const std::string& account_id,
net::URLRequestContextGetter* getter,
const std::string& client_id,
const std::string& client_secret,
const OAuth2TokenService::ScopeSet& scopes,
base::WeakPtr<RequestImpl> waiting_request);
void Start();
void InformWaitingRequests();
void InformWaitingRequestsAndDelete();
static bool ShouldRetry(const GoogleServiceAuthError& error);
int64 ComputeExponentialBackOffMilliseconds(int retry_num);
OAuth2TokenService* const oauth2_token_service_;
scoped_refptr<net::URLRequestContextGetter> getter_;
const std::string account_id_;
const ScopeSet scopes_;
std::vector<base::WeakPtr<RequestImpl> > waiting_requests_;
int retry_number_;
base::OneShotTimer<Fetcher> retry_timer_;
scoped_ptr<OAuth2AccessTokenFetcher> fetcher_;
GoogleServiceAuthError error_;
std::string access_token_;
base::Time expiration_date_;
std::string client_id_;
std::string client_secret_;
DISALLOW_COPY_AND_ASSIGN(Fetcher);
};
OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart(
OAuth2TokenService* oauth2_token_service,
const std::string& account_id,
net::URLRequestContextGetter* getter,
const std::string& client_id,
const std::string& client_secret,
const OAuth2TokenService::ScopeSet& scopes,
base::WeakPtr<RequestImpl> waiting_request) {
OAuth2TokenService::Fetcher* fetcher = new Fetcher(
oauth2_token_service,
account_id,
getter,
client_id,
client_secret,
scopes,
waiting_request);
fetcher->Start();
return fetcher;
}
OAuth2TokenService::Fetcher::Fetcher(
OAuth2TokenService* oauth2_token_service,
const std::string& account_id,
net::URLRequestContextGetter* getter,
const std::string& client_id,
const std::string& client_secret,
const OAuth2TokenService::ScopeSet& scopes,
base::WeakPtr<RequestImpl> waiting_request)
: oauth2_token_service_(oauth2_token_service),
getter_(getter),
account_id_(account_id),
scopes_(scopes),
retry_number_(0),
error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
client_id_(client_id),
client_secret_(client_secret) {
DCHECK(oauth2_token_service_);
DCHECK(getter_.get());
waiting_requests_.push_back(waiting_request);
}
OAuth2TokenService::Fetcher::~Fetcher() {
if (waiting_requests_.size())
InformWaitingRequests();
}
void OAuth2TokenService::Fetcher::Start() {
fetcher_.reset(oauth2_token_service_->CreateAccessTokenFetcher(
account_id_, getter_.get(), this));
DCHECK(fetcher_);
fetcher_->Start(client_id_,
client_secret_,
std::vector<std::string>(scopes_.begin(), scopes_.end()));
retry_timer_.Stop();
}
void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
const std::string& access_token,
const base::Time& expiration_date) {
fetcher_.reset();
error_ = GoogleServiceAuthError::AuthErrorNone();
access_token_ = access_token;
expiration_date_ = expiration_date;
oauth2_token_service_->RegisterCacheEntry(client_id_,
account_id_,
scopes_,
access_token_,
expiration_date_);
InformWaitingRequestsAndDelete();
}
void OAuth2TokenService::Fetcher::OnGetTokenFailure(
const GoogleServiceAuthError& error) {
fetcher_.reset();
if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) {
base::TimeDelta backoff = base::TimeDelta::FromMilliseconds(
ComputeExponentialBackOffMilliseconds(retry_number_));
++retry_number_;
retry_timer_.Stop();
retry_timer_.Start(FROM_HERE,
backoff,
this,
&OAuth2TokenService::Fetcher::Start);
return;
}
error_ = error;
InformWaitingRequestsAndDelete();
}
int64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
int retry_num) {
DCHECK(retry_num < max_fetch_retry_num_);
int64 exponential_backoff_in_seconds = 1 << retry_num;
return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
}
bool OAuth2TokenService::Fetcher::ShouldRetry(
const GoogleServiceAuthError& error) {
GoogleServiceAuthError::State error_state = error.state();
return error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
}
void OAuth2TokenService::Fetcher::InformWaitingRequests() {
std::vector<base::WeakPtr<RequestImpl> >::const_iterator iter =
waiting_requests_.begin();
for (; iter != waiting_requests_.end(); ++iter) {
base::WeakPtr<RequestImpl> waiting_request = *iter;
if (waiting_request.get())
waiting_request->InformConsumer(error_, access_token_, expiration_date_);
}
waiting_requests_.clear();
}
void OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
oauth2_token_service_->OnFetchComplete(this);
InformWaitingRequests();
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
void OAuth2TokenService::Fetcher::AddWaitingRequest(
base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
waiting_requests_.push_back(waiting_request);
}
size_t OAuth2TokenService::Fetcher::GetWaitingRequestCount() const {
return waiting_requests_.size();
}
void OAuth2TokenService::Fetcher::Cancel() {
fetcher_.reset();
retry_timer_.Stop();
error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
InformWaitingRequestsAndDelete();
}
const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet()
const {
return scopes_;
}
const std::string& OAuth2TokenService::Fetcher::GetClientId() const {
return client_id_;
}
const std::string& OAuth2TokenService::Fetcher::GetAccountId() const {
return account_id_;
}
OAuth2TokenService::Request::Request() {
}
OAuth2TokenService::Request::~Request() {
}
OAuth2TokenService::Consumer::Consumer(const std::string& id)
: id_(id) {}
OAuth2TokenService::Consumer::~Consumer() {
}
OAuth2TokenService::OAuth2TokenService() {
}
OAuth2TokenService::~OAuth2TokenService() {
STLDeleteContainerPairSecondPointers(
pending_fetchers_.begin(), pending_fetchers_.end());
}
void OAuth2TokenService::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void OAuth2TokenService::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void OAuth2TokenService::AddDiagnosticsObserver(DiagnosticsObserver* observer) {
diagnostics_observer_list_.AddObserver(observer);
}
void OAuth2TokenService::RemoveDiagnosticsObserver(
DiagnosticsObserver* observer) {
diagnostics_observer_list_.RemoveObserver(observer);
}
std::vector<std::string> OAuth2TokenService::GetAccounts() {
return std::vector<std::string>();
}
scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
const std::string& account_id,
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer) {
return StartRequestForClientWithContext(
account_id,
GetRequestContext(),
GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
scopes,
consumer);
}
scoped_ptr<OAuth2TokenService::Request>
OAuth2TokenService::StartRequestForClient(
const std::string& account_id,
const std::string& client_id,
const std::string& client_secret,
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer) {
return StartRequestForClientWithContext(
account_id,
GetRequestContext(),
client_id,
client_secret,
scopes,
consumer);
}
scoped_ptr<OAuth2TokenService::Request>
OAuth2TokenService::StartRequestWithContext(
const std::string& account_id,
net::URLRequestContextGetter* getter,
const ScopeSet& scopes,
Consumer* consumer) {
return StartRequestForClientWithContext(
account_id,
getter,
GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
scopes,
consumer);
}
scoped_ptr<OAuth2TokenService::Request>
OAuth2TokenService::StartRequestForClientWithContext(
const std::string& account_id,
net::URLRequestContextGetter* getter,
const std::string& client_id,
const std::string& client_secret,
const ScopeSet& scopes,
Consumer* consumer) {
DCHECK(CalledOnValidThread());
scoped_ptr<RequestImpl> request(new RequestImpl(account_id, consumer));
FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
OnAccessTokenRequested(account_id,
consumer->id(),
scopes));
if (!RefreshTokenIsAvailable(account_id)) {
GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
OnFetchAccessTokenComplete(
account_id, consumer->id(), scopes, error,
base::Time()));
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
&RequestImpl::InformConsumer,
request->AsWeakPtr(),
error,
std::string(),
base::Time()));
return request.PassAs<Request>();
}
RequestParameters request_parameters(client_id,
account_id,
scopes);
if (HasCacheEntry(request_parameters)) {
StartCacheLookupRequest(request.get(), request_parameters, consumer);
} else {
FetchOAuth2Token(request.get(),
account_id,
getter,
client_id,
client_secret,
scopes);
}
return request.PassAs<Request>();
}
void OAuth2TokenService::FetchOAuth2Token(RequestImpl* request,
const std::string& account_id,
net::URLRequestContextGetter* getter,
const std::string& client_id,
const std::string& client_secret,
const ScopeSet& scopes) {
RequestParameters request_parameters = RequestParameters(client_id,
account_id,
scopes);
std::map<RequestParameters, Fetcher*>::iterator iter =
pending_fetchers_.find(request_parameters);
if (iter != pending_fetchers_.end()) {
iter->second->AddWaitingRequest(request->AsWeakPtr());
return;
}
pending_fetchers_[request_parameters] =
Fetcher::CreateAndStart(this,
account_id,
getter,
client_id,
client_secret,
scopes,
request->AsWeakPtr());
}
void OAuth2TokenService::StartCacheLookupRequest(
RequestImpl* request,
const OAuth2TokenService::RequestParameters& request_parameters,
OAuth2TokenService::Consumer* consumer) {
CHECK(HasCacheEntry(request_parameters));
const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
OnFetchAccessTokenComplete(
request_parameters.account_id,
consumer->id(),
request_parameters.scopes,
GoogleServiceAuthError::AuthErrorNone(),
cache_entry->expiration_date));
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
&RequestImpl::InformConsumer,
request->AsWeakPtr(),
GoogleServiceAuthError(GoogleServiceAuthError::NONE),
cache_entry->access_token,
cache_entry->expiration_date));
}
void OAuth2TokenService::InvalidateToken(const std::string& account_id,
const ScopeSet& scopes,
const std::string& access_token) {
InvalidateOAuth2Token(account_id,
GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
scopes,
access_token);
}
void OAuth2TokenService::InvalidateTokenForClient(
const std::string& account_id,
const std::string& client_id,
const ScopeSet& scopes,
const std::string& access_token) {
InvalidateOAuth2Token(account_id, client_id, scopes, access_token);
}
void OAuth2TokenService::InvalidateOAuth2Token(
const std::string& account_id,
const std::string& client_id,
const ScopeSet& scopes,
const std::string& access_token) {
DCHECK(CalledOnValidThread());
RemoveCacheEntry(
RequestParameters(client_id,
account_id,
scopes),
access_token);
}
void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
DCHECK(CalledOnValidThread());
UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
RequestParameters request_param(fetcher->GetClientId(),
fetcher->GetAccountId(),
fetcher->GetScopeSet());
const OAuth2TokenService::CacheEntry* entry = GetCacheEntry(request_param);
const std::vector<base::WeakPtr<RequestImpl> >& requests =
fetcher->waiting_requests();
for (size_t i = 0; i < requests.size(); ++i) {
const RequestImpl* req = requests[i].get();
if (req) {
FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
OnFetchAccessTokenComplete(
req->GetAccountId(), req->GetConsumerId(),
fetcher->GetScopeSet(), fetcher->error(),
entry ? entry->expiration_date : base::Time()));
}
}
std::map<RequestParameters, Fetcher*>::iterator iter =
pending_fetchers_.find(request_param);
DCHECK(iter != pending_fetchers_.end());
DCHECK_EQ(fetcher, iter->second);
pending_fetchers_.erase(iter);
}
bool OAuth2TokenService::HasCacheEntry(
const RequestParameters& request_parameters) {
const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
return cache_entry && cache_entry->access_token.length();
}
const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
const RequestParameters& request_parameters) {
DCHECK(CalledOnValidThread());
TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
if (token_iterator == token_cache_.end())
return NULL;
if (token_iterator->second.expiration_date <= base::Time::Now()) {
token_cache_.erase(token_iterator);
return NULL;
}
return &token_iterator->second;
}
bool OAuth2TokenService::RemoveCacheEntry(
const RequestParameters& request_parameters,
const std::string& token_to_remove) {
DCHECK(CalledOnValidThread());
TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
if (token_iterator != token_cache_.end() &&
token_iterator->second.access_token == token_to_remove) {
FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
OnTokenRemoved(request_parameters.account_id,
request_parameters.scopes));
token_cache_.erase(token_iterator);
return true;
}
return false;
}
void OAuth2TokenService::RegisterCacheEntry(
const std::string& client_id,
const std::string& account_id,
const OAuth2TokenService::ScopeSet& scopes,
const std::string& access_token,
const base::Time& expiration_date) {
DCHECK(CalledOnValidThread());
CacheEntry& token = token_cache_[RequestParameters(client_id,
account_id,
scopes)];
token.access_token = access_token;
token.expiration_date = expiration_date;
}
void OAuth2TokenService::UpdateAuthError(
const std::string& account_id,
const GoogleServiceAuthError& error) {
}
void OAuth2TokenService::ClearCache() {
DCHECK(CalledOnValidThread());
for (TokenCache::iterator iter = token_cache_.begin();
iter != token_cache_.end(); ++iter) {
FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
OnTokenRemoved(iter->first.account_id,
iter->first.scopes));
}
token_cache_.clear();
}
void OAuth2TokenService::ClearCacheForAccount(const std::string& account_id) {
DCHECK(CalledOnValidThread());
for (TokenCache::iterator iter = token_cache_.begin();
iter != token_cache_.end();
) {
if (iter->first.account_id == account_id) {
FOR_EACH_OBSERVER(DiagnosticsObserver, diagnostics_observer_list_,
OnTokenRemoved(account_id, iter->first.scopes));
token_cache_.erase(iter++);
} else {
++iter;
}
}
}
void OAuth2TokenService::CancelAllRequests() {
std::vector<Fetcher*> fetchers_to_cancel;
for (std::map<RequestParameters, Fetcher*>::iterator iter =
pending_fetchers_.begin();
iter != pending_fetchers_.end();
++iter) {
fetchers_to_cancel.push_back(iter->second);
}
CancelFetchers(fetchers_to_cancel);
}
void OAuth2TokenService::CancelRequestsForAccount(
const std::string& account_id) {
std::vector<Fetcher*> fetchers_to_cancel;
for (std::map<RequestParameters, Fetcher*>::iterator iter =
pending_fetchers_.begin();
iter != pending_fetchers_.end();
++iter) {
if (iter->first.account_id == account_id)
fetchers_to_cancel.push_back(iter->second);
}
CancelFetchers(fetchers_to_cancel);
}
void OAuth2TokenService::CancelFetchers(
std::vector<Fetcher*> fetchers_to_cancel) {
for (std::vector<OAuth2TokenService::Fetcher*>::iterator iter =
fetchers_to_cancel.begin();
iter != fetchers_to_cancel.end();
++iter) {
(*iter)->Cancel();
}
}
void OAuth2TokenService::FireRefreshTokenAvailable(
const std::string& account_id) {
FOR_EACH_OBSERVER(Observer, observer_list_,
OnRefreshTokenAvailable(account_id));
}
void OAuth2TokenService::FireRefreshTokenRevoked(
const std::string& account_id) {
FOR_EACH_OBSERVER(Observer, observer_list_,
OnRefreshTokenRevoked(account_id));
}
void OAuth2TokenService::FireRefreshTokensLoaded() {
FOR_EACH_OBSERVER(Observer, observer_list_, OnRefreshTokensLoaded());
}
int OAuth2TokenService::cache_size_for_testing() const {
return token_cache_.size();
}
void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
int max_retries) {
DCHECK(CalledOnValidThread());
max_fetch_retry_num_ = max_retries;
}
size_t OAuth2TokenService::GetNumPendingRequestsForTesting(
const std::string& client_id,
const std::string& account_id,
const ScopeSet& scopes) const {
PendingFetcherMap::const_iterator iter = pending_fetchers_.find(
OAuth2TokenService::RequestParameters(
client_id,
account_id,
scopes));
return iter == pending_fetchers_.end() ?
0 : iter->second->GetWaitingRequestCount();
}