Chromium Code Reviews| Index: chrome/browser/signin/oauth2_token_service.cc |
| diff --git a/chrome/browser/signin/oauth2_token_service.cc b/chrome/browser/signin/oauth2_token_service.cc |
| index 0b6bd5dce376e5af55b6df43bd591f3e9129c0ef..8eb7db3b42b9e7e2e36c200a85e0a45cfa814879 100644 |
| --- a/chrome/browser/signin/oauth2_token_service.cc |
| +++ b/chrome/browser/signin/oauth2_token_service.cc |
| @@ -12,16 +12,55 @@ |
| #include "base/rand_util.h" |
| #include "base/stl_util.h" |
| #include "base/time/time.h" |
| -#include "base/timer/timer.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "google_apis/gaia/gaia_urls.h" |
| #include "google_apis/gaia/google_service_auth_error.h" |
| -#include "google_apis/gaia/oauth2_access_token_consumer.h" |
| -#include "google_apis/gaia/oauth2_access_token_fetcher.h" |
| #include "net/url_request/url_request_context_getter.h" |
| int OAuth2TokenService::max_fetch_retry_num_ = 5; |
| +OAuth2TokenService::ClientScopeSet::ClientScopeSet( |
| + const std::string& request_origin, |
| + const std::string& client_id, |
| + const ScopeSet& scopes) |
| + : request_origin(request_origin), |
| + client_id(client_id), |
| + scopes(scopes) { |
| +} |
| + |
| +bool OAuth2TokenService::ClientScopeSet::operator<( |
| + const ClientScopeSet& s) const { |
| + return ((request_origin < s.request_origin) || |
| + (!(s.request_origin < request_origin) && (client_id < s.client_id))) || |
|
Andrew T Wilson (Slow)
2013/08/19 14:04:19
I wonder if this would be more legible as if state
zel
2013/08/19 16:03:17
I've also got deceived believing that what you pro
fgorski
2013/08/19 16:16:06
There is a way to rewrite the conditions in a long
zel
2013/08/19 16:25:48
Right. Done. PTAL.
|
| + (!(s.request_origin < request_origin) && |
| + !(s.client_id < client_id) && |
| + (scopes < s.scopes)); |
| +} |
| + |
| +OAuth2TokenService::FetchParameters::FetchParameters( |
| + const std::string& request_origin, |
| + const std::string& client_id, |
| + const std::string& refresh_token, |
| + const ScopeSet& scopes) |
| + : request_origin(request_origin), |
| + client_id(client_id), |
| + refresh_token(refresh_token), |
| + scopes(scopes) { |
| +} |
| + |
| +bool OAuth2TokenService::FetchParameters::operator<( |
| + const FetchParameters& p) const { |
| + return ((request_origin < p.request_origin) || |
| + (!(p.request_origin < request_origin) && (client_id < p.client_id))) || |
| + (!(p.request_origin < request_origin) && |
|
Andrew T Wilson (Slow)
2013/08/19 14:04:19
See my previous comment. This nested logic just se
zel
2013/08/19 16:03:17
See my comments above. There aren't many obvious w
|
| + !(p.client_id < client_id) && |
| + (refresh_token < p.refresh_token)) || |
| + (!(p.request_origin < request_origin) && |
| + !(p.client_id < client_id) && |
| + !(p.refresh_token < refresh_token) && |
| + (scopes < p.scopes)); |
| +} |
| + |
| OAuth2TokenService::RequestImpl::RequestImpl( |
| OAuth2TokenService::Consumer* consumer) |
| : consumer_(consumer) { |
| @@ -43,119 +82,22 @@ void OAuth2TokenService::RequestImpl::InformConsumer( |
| consumer_->OnGetTokenFailure(this, error); |
| } |
| -// Class that fetches OAuth2 access tokens for given scopes and refresh token. |
| -// |
| -// It aims to meet OAuth2TokenService's requirements on token fetching. Retry |
| -// mechanism is used to handle failures. |
| -// |
| -// To use this class, call CreateAndStart() to create and start a Fetcher. |
| -// |
| -// The Fetcher will call back the service by calling |
| -// OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is |
| -// not destructed before it completes fetching; if the Fetcher is destructed |
| -// before it completes fetching, the service will never be called back. The |
| -// Fetcher destructs itself after calling back the service when finishes |
| -// fetching. |
| -// |
| -// Requests that are waiting for the fetching results of this Fetcher can be |
| -// added to the Fetcher by calling |
| -// OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher completes |
| -// fetching. |
| -// |
| -// The waiting requests are taken as weak pointers and they can be deleted. The |
| -// waiting requests will be called back with fetching results if they are not |
| -// deleted |
| -// - when the Fetcher completes fetching, if the Fetcher is not destructed |
| -// before it completes fetching, or |
| -// - when the Fetcher is destructed if the Fetcher is destructed before it |
| -// completes fetching (in this case, the waiting requests will be called back |
| -// with error). |
| -class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer { |
| - public: |
| - // Creates a Fetcher and starts fetching an OAuth2 access token for |
| - // |refresh_token| and |scopes| in the request context obtained by |getter|. |
| - // The given |oauth2_token_service| will be informed when fetching is done. |
| - static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service, |
| - net::URLRequestContextGetter* getter, |
| - const std::string& chrome_client_id, |
| - const std::string& chrome_client_secret, |
| - const std::string& refresh_token, |
| - const OAuth2TokenService::ScopeSet& scopes, |
| - base::WeakPtr<RequestImpl> waiting_request); |
| - virtual ~Fetcher(); |
| - |
| - // Add a request that is waiting for the result of this Fetcher. |
| - void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request); |
| - |
| - void Cancel(); |
| - |
| - const OAuth2TokenService::ScopeSet& GetScopeSet() const; |
| - const std::string& GetRefreshToken() const; |
| - |
| - // The error result from this fetcher. |
| - const GoogleServiceAuthError& error() const { return error_; } |
| - |
| - protected: |
| - // OAuth2AccessTokenConsumer |
| - 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, |
| - net::URLRequestContextGetter* getter, |
| - const std::string& chrome_client_id, |
| - const std::string& chrome_client_secret, |
| - const std::string& refresh_token, |
| - 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); |
| - |
| - // |oauth2_token_service_| remains valid for the life of this Fetcher, since |
| - // this Fetcher is destructed in the dtor of the OAuth2TokenService or is |
| - // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess |
| - // (whichever comes first). |
| - OAuth2TokenService* const oauth2_token_service_; |
| - scoped_refptr<net::URLRequestContextGetter> getter_; |
| - const std::string refresh_token_; |
| - const OAuth2TokenService::ScopeSet scopes_; |
| - std::vector<base::WeakPtr<RequestImpl> > waiting_requests_; |
| - |
| - int retry_number_; |
| - base::OneShotTimer<OAuth2TokenService::Fetcher> retry_timer_; |
| - scoped_ptr<OAuth2AccessTokenFetcher> fetcher_; |
| - |
| - // Variables that store fetch results. |
| - // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle |
| - // destruction. |
| - GoogleServiceAuthError error_; |
| - std::string access_token_; |
| - base::Time expiration_date_; |
| - // OAuth2 client id and secret. |
| - std::string chrome_client_id_; |
| - std::string chrome_client_secret_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(Fetcher); |
| -}; |
| - |
| // static |
| OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart( |
| OAuth2TokenService* oauth2_token_service, |
| net::URLRequestContextGetter* getter, |
| - const std::string& chrome_client_id, |
| - const std::string& chrome_client_secret, |
| + const std::string& request_origin, |
| + const std::string& client_id, |
| + const std::string& client_secret, |
| const std::string& refresh_token, |
| const OAuth2TokenService::ScopeSet& scopes, |
| base::WeakPtr<RequestImpl> waiting_request) { |
| OAuth2TokenService::Fetcher* fetcher = new Fetcher( |
| oauth2_token_service, |
| getter, |
| - chrome_client_id, |
| - chrome_client_secret, |
| + request_origin, |
| + client_id, |
| + client_secret, |
| refresh_token, |
| scopes, |
| waiting_request); |
| @@ -166,8 +108,9 @@ OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart( |
| OAuth2TokenService::Fetcher::Fetcher( |
| OAuth2TokenService* oauth2_token_service, |
| net::URLRequestContextGetter* getter, |
| - const std::string& chrome_client_id, |
| - const std::string& chrome_client_secret, |
| + const std::string& request_origin, |
| + const std::string& client_id, |
| + const std::string& client_secret, |
| const std::string& refresh_token, |
| const OAuth2TokenService::ScopeSet& scopes, |
| base::WeakPtr<RequestImpl> waiting_request) |
| @@ -177,8 +120,9 @@ OAuth2TokenService::Fetcher::Fetcher( |
| scopes_(scopes), |
| retry_number_(0), |
| error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE), |
| - chrome_client_id_(chrome_client_id), |
| - chrome_client_secret_(chrome_client_secret) { |
| + request_origin_(request_origin), |
| + client_id_(client_id), |
| + client_secret_(client_secret) { |
| DCHECK(oauth2_token_service_); |
| DCHECK(getter_.get()); |
| DCHECK(refresh_token_.length()); |
| @@ -193,8 +137,8 @@ OAuth2TokenService::Fetcher::~Fetcher() { |
| void OAuth2TokenService::Fetcher::Start() { |
| fetcher_.reset(new OAuth2AccessTokenFetcher(this, getter_.get())); |
| - fetcher_->Start(chrome_client_id_, |
| - chrome_client_secret_, |
| + fetcher_->Start(client_id_, |
| + client_secret_, |
| refresh_token_, |
| std::vector<std::string>(scopes_.begin(), scopes_.end())); |
| retry_timer_.Stop(); |
| @@ -214,7 +158,9 @@ void OAuth2TokenService::Fetcher::OnGetTokenSuccess( |
| // we still inform all waiting Consumers of a successful token fetch below. |
| // This is intentional -- some consumers may need the token for cleanup |
| // tasks. https://chromiumcodereview.appspot.com/11312124/ |
| - oauth2_token_service_->RegisterCacheEntry(refresh_token_, |
| + oauth2_token_service_->RegisterCacheEntry(request_origin_, |
| + client_id_, |
| + refresh_token_, |
| scopes_, |
| access_token_, |
| expiration_date_); |
| @@ -283,6 +229,10 @@ void OAuth2TokenService::Fetcher::AddWaitingRequest( |
| 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(); |
| @@ -299,6 +249,14 @@ const std::string& OAuth2TokenService::Fetcher::GetRefreshToken() const { |
| return refresh_token_; |
| } |
| +const std::string& OAuth2TokenService::Fetcher::GetClientId() const { |
| + return client_id_; |
| +} |
| + |
| +const std::string& OAuth2TokenService::Fetcher::GetRequestOrigin() const { |
| + return request_origin_; |
| +} |
| + |
| OAuth2TokenService::Request::Request() { |
| } |
| @@ -339,6 +297,7 @@ scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( |
| OAuth2TokenService::Consumer* consumer) { |
| return StartRequestForClientWithContext( |
| GetRequestContext(), |
| + std::string(), |
| GaiaUrls::GetInstance()->oauth2_chrome_client_id(), |
| GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), |
| scopes, |
| @@ -347,12 +306,14 @@ scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( |
| scoped_ptr<OAuth2TokenService::Request> |
| OAuth2TokenService::StartRequestForClient( |
| + const std::string& request_origin, |
| const std::string& client_id, |
| const std::string& client_secret, |
| const OAuth2TokenService::ScopeSet& scopes, |
| OAuth2TokenService::Consumer* consumer) { |
| return StartRequestForClientWithContext( |
| GetRequestContext(), |
| + request_origin, |
| client_id, |
| client_secret, |
| scopes, |
| @@ -366,6 +327,7 @@ OAuth2TokenService::StartRequestWithContext( |
| Consumer* consumer) { |
| return StartRequestForClientWithContext( |
| getter, |
| + std::string(), |
| GaiaUrls::GetInstance()->oauth2_chrome_client_id(), |
| GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), |
| scopes, |
| @@ -375,6 +337,7 @@ OAuth2TokenService::StartRequestWithContext( |
| scoped_ptr<OAuth2TokenService::Request> |
| OAuth2TokenService::StartRequestForClientWithContext( |
| net::URLRequestContextGetter* getter, |
| + const std::string& request_origin, |
| const std::string& client_id, |
| const std::string& client_secret, |
| const ScopeSet& scopes, |
| @@ -395,13 +358,19 @@ OAuth2TokenService::StartRequestForClientWithContext( |
| return request.PassAs<Request>(); |
| } |
| - if (HasCacheEntry(scopes)) |
| - return StartCacheLookupRequest(scopes, consumer); |
| + ClientScopeSet client_scopes(request_origin, |
| + client_id, |
| + scopes); |
| + if (HasCacheEntry(client_scopes)) |
| + return StartCacheLookupRequest(client_scopes, consumer); |
| // If there is already a pending fetcher for |scopes| and |refresh_token|, |
| // simply register this |request| for those results rather than starting |
| // a new fetcher. |
| - FetchParameters fetch_parameters = std::make_pair(refresh_token, scopes); |
| + FetchParameters fetch_parameters = FetchParameters(request_origin, |
| + client_id, |
| + refresh_token, |
| + scopes); |
| std::map<FetchParameters, Fetcher*>::iterator iter = |
| pending_fetchers_.find(fetch_parameters); |
| if (iter != pending_fetchers_.end()) { |
| @@ -412,6 +381,7 @@ OAuth2TokenService::StartRequestForClientWithContext( |
| pending_fetchers_[fetch_parameters] = |
| Fetcher::CreateAndStart(this, |
| getter, |
| + request_origin, |
| client_id, |
| client_secret, |
| refresh_token, |
| @@ -422,10 +392,10 @@ OAuth2TokenService::StartRequestForClientWithContext( |
| scoped_ptr<OAuth2TokenService::Request> |
| OAuth2TokenService::StartCacheLookupRequest( |
| - const OAuth2TokenService::ScopeSet& scopes, |
| + const OAuth2TokenService::ClientScopeSet& client_scopes, |
| OAuth2TokenService::Consumer* consumer) { |
| - CHECK(HasCacheEntry(scopes)); |
| - const CacheEntry* cache_entry = GetCacheEntry(scopes); |
| + CHECK(HasCacheEntry(client_scopes)); |
| + const CacheEntry* cache_entry = GetCacheEntry(client_scopes); |
| scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); |
| base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| &RequestImpl::InformConsumer, |
| @@ -439,7 +409,11 @@ scoped_ptr<OAuth2TokenService::Request> |
| void OAuth2TokenService::InvalidateToken(const ScopeSet& scopes, |
| const std::string& invalid_token) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| - RemoveCacheEntry(scopes, invalid_token); |
| + RemoveCacheEntry( |
| + ClientScopeSet(std::string(), |
| + GaiaUrls::GetInstance()->oauth2_chrome_client_id(), |
| + scopes), |
| + invalid_token); |
| } |
| void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) { |
| @@ -476,23 +450,26 @@ void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) { |
| // Then by (2), |fetcher| is recorded in |pending_fetchers_|. |
| // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet. |
| std::map<FetchParameters, Fetcher*>::iterator iter = |
| - pending_fetchers_.find(std::make_pair( |
| - fetcher->GetRefreshToken(), fetcher->GetScopeSet())); |
| + pending_fetchers_.find(FetchParameters( |
| + fetcher->GetRequestOrigin(), |
| + fetcher->GetClientId(), |
| + fetcher->GetRefreshToken(), |
| + fetcher->GetScopeSet())); |
| DCHECK(iter != pending_fetchers_.end()); |
| DCHECK_EQ(fetcher, iter->second); |
| pending_fetchers_.erase(iter); |
| } |
| bool OAuth2TokenService::HasCacheEntry( |
| - const OAuth2TokenService::ScopeSet& scopes) { |
| - const CacheEntry* cache_entry = GetCacheEntry(scopes); |
| + const ClientScopeSet& client_scopes) { |
| + const CacheEntry* cache_entry = GetCacheEntry(client_scopes); |
| return cache_entry && cache_entry->access_token.length(); |
| } |
| const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry( |
| - const OAuth2TokenService::ScopeSet& scopes) { |
| + const ClientScopeSet& client_scopes) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| - TokenCache::iterator token_iterator = token_cache_.find(scopes); |
| + TokenCache::iterator token_iterator = token_cache_.find(client_scopes); |
| if (token_iterator == token_cache_.end()) |
| return NULL; |
| if (token_iterator->second.expiration_date <= base::Time::Now()) { |
| @@ -503,10 +480,10 @@ const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry( |
| } |
| bool OAuth2TokenService::RemoveCacheEntry( |
| - const OAuth2TokenService::ScopeSet& scopes, |
| + const ClientScopeSet& client_scopes, |
| const std::string& token_to_remove) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| - TokenCache::iterator token_iterator = token_cache_.find(scopes); |
| + TokenCache::iterator token_iterator = token_cache_.find(client_scopes); |
| if (token_iterator != token_cache_.end() && |
| token_iterator->second.access_token == token_to_remove) { |
| token_cache_.erase(token_iterator); |
| @@ -516,13 +493,17 @@ bool OAuth2TokenService::RemoveCacheEntry( |
| } |
| void OAuth2TokenService::RegisterCacheEntry( |
| + const std::string& request_origin, |
| + const std::string& client_id, |
| const std::string& refresh_token, |
| const OAuth2TokenService::ScopeSet& scopes, |
| const std::string& access_token, |
| const base::Time& expiration_date) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| - CacheEntry& token = token_cache_[scopes]; |
| + CacheEntry& token = token_cache_[ClientScopeSet(request_origin, |
| + client_id, |
| + scopes)]; |
| token.access_token = access_token; |
| token.expiration_date = expiration_date; |
| } |
| @@ -554,7 +535,7 @@ void OAuth2TokenService::CancelRequestsForToken( |
| pending_fetchers_.begin(); |
| iter != pending_fetchers_.end(); |
| ++iter) { |
| - if (iter->first.first == refresh_token) |
| + if (iter->first.refresh_token == refresh_token) |
| fetchers_to_cancel.push_back(iter->second); |
| } |
| CancelFetchers(fetchers_to_cancel); |