Index: chrome/browser/sync/profile_sync_auth_provider.cc |
diff --git a/chrome/browser/sync/profile_sync_auth_provider.cc b/chrome/browser/sync/profile_sync_auth_provider.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2a38966a182cdce6732efe4011c3165a20a0a64e |
--- /dev/null |
+++ b/chrome/browser/sync/profile_sync_auth_provider.cc |
@@ -0,0 +1,137 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/sync/profile_sync_auth_provider.h" |
+ |
+#include "base/bind.h" |
+#include "base/location.h" |
+#include "base/message_loop/message_loop_proxy.h" |
+#include "base/single_thread_task_runner.h" |
+#include "components/signin/core/browser/profile_oauth2_token_service.h" |
+#include "google_apis/gaia/gaia_constants.h" |
+ |
+// This is thin proxy class for forwarding calls between sync and UI threads. |
+// The main purpose is to hide the fact that ProfileSyncAuthProvider and |
+// SyncThreadProxy have independent lifetimes. If ProfileSyncAuthProvider is |
+// destroyed first calls to RequestAccessToken will never complete. This is fine |
+// since sync thread is not blocked and is in the process of shutdown anyway. |
+class ProfileSyncAuthProvider::SyncThreadProxy |
+ : public syncer::SyncAuthProvider, |
+ public base::NonThreadSafe { |
+ public: |
+ SyncThreadProxy( |
+ base::WeakPtr<ProfileSyncAuthProvider> provider_impl, |
+ scoped_refptr<base::SingleThreadTaskRunner> provider_task_runner); |
+ |
+ // syncer::SyncAuthProvider implementation. |
+ virtual void RequestAccessToken( |
+ const RequestTokenCallback& callback) OVERRIDE; |
+ virtual void InvalidateAccessToken(const std::string& token) OVERRIDE; |
+ |
+ private: |
+ base::WeakPtr<ProfileSyncAuthProvider> provider_impl_; |
+ scoped_refptr<base::SingleThreadTaskRunner> provider_task_runner_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SyncThreadProxy); |
+}; |
+ |
+ProfileSyncAuthProvider::SyncThreadProxy::SyncThreadProxy( |
+ base::WeakPtr<ProfileSyncAuthProvider> provider_impl, |
+ scoped_refptr<base::SingleThreadTaskRunner> provider_task_runner) |
+ : provider_impl_(provider_impl), |
+ provider_task_runner_(provider_task_runner) { |
+ // SyncThreadProxy is created on UI thread but used on sync thread. |
+ // Detach NonThreadSafe from UI thread so that it can reattach on first |
tim (not reviewing)
2014/04/30 20:52:41
finish sentence.
pavely
2014/04/30 21:16:56
Done.
|
+ DetachFromThread(); |
+} |
+ |
+void ProfileSyncAuthProvider::SyncThreadProxy::RequestAccessToken( |
+ const RequestTokenCallback& callback) { |
+ DCHECK(CalledOnValidThread()); |
+ provider_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&ProfileSyncAuthProvider::RequestAccessToken, |
+ provider_impl_, |
+ callback, |
+ base::MessageLoopProxy::current())); |
+} |
+ |
+void ProfileSyncAuthProvider::SyncThreadProxy::InvalidateAccessToken( |
+ const std::string& token) { |
+ DCHECK(CalledOnValidThread()); |
+ provider_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&ProfileSyncAuthProvider::InvalidateAccessToken, |
+ provider_impl_, |
+ token)); |
+} |
+ |
+ProfileSyncAuthProvider::ProfileSyncAuthProvider( |
+ ProfileOAuth2TokenService* token_service, |
+ const std::string& account_id, |
+ const std::string& scope) |
+ : OAuth2TokenService::Consumer("sync_auth_provider"), |
+ token_service_(token_service), |
+ account_id_(account_id), |
+ weak_factory_(this) { |
+ oauth2_scope_.insert(scope); |
+} |
+ |
+ProfileSyncAuthProvider::~ProfileSyncAuthProvider() { |
+ DCHECK(CalledOnValidThread()); |
+} |
+ |
+void ProfileSyncAuthProvider::RequestAccessToken( |
+ const syncer::SyncAuthProvider::RequestTokenCallback& callback, |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) { |
+ DCHECK(CalledOnValidThread()); |
+ if (access_token_request_ != NULL) { |
+ // If there is already pending request report it as cancelled. |
+ GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); |
+ RespondToTokenRequest(error, std::string()); |
+ } |
+ request_token_callback_ = callback; |
+ callback_task_runner_ = task_runner; |
+ access_token_request_ = |
+ token_service_->StartRequest(account_id_, oauth2_scope_, this); |
+} |
+ |
+void ProfileSyncAuthProvider::OnGetTokenSuccess( |
+ const OAuth2TokenService::Request* request, |
+ const std::string& access_token, |
+ const base::Time& expiration_time) { |
+ DCHECK_EQ(access_token_request_, request); |
+ RespondToTokenRequest(GoogleServiceAuthError::AuthErrorNone(), access_token); |
+} |
+ |
+void ProfileSyncAuthProvider::OnGetTokenFailure( |
+ const OAuth2TokenService::Request* request, |
+ const GoogleServiceAuthError& error) { |
+ DCHECK_EQ(access_token_request_, request); |
+ RespondToTokenRequest(error, std::string()); |
+} |
+ |
+void ProfileSyncAuthProvider::RespondToTokenRequest( |
+ const GoogleServiceAuthError& error, |
+ const std::string& token) { |
+ DCHECK(CalledOnValidThread()); |
+ callback_task_runner_->PostTask( |
tim (not reviewing)
2014/04/30 20:52:41
It's possible this response hits the client (SCM)
pavely
2014/04/30 21:16:56
The model I'm trying to follow is: For each Reques
|
+ FROM_HERE, base::Bind(request_token_callback_, error, token)); |
+ access_token_request_.reset(); |
+ request_token_callback_.Reset(); |
+ callback_task_runner_ = NULL; |
+} |
+ |
+void ProfileSyncAuthProvider::InvalidateAccessToken(const std::string& token) { |
+ DCHECK(CalledOnValidThread()); |
+ token_service_->InvalidateToken(account_id_, oauth2_scope_, token); |
+} |
+ |
+scoped_ptr<syncer::SyncAuthProvider> |
+ProfileSyncAuthProvider::CreateProviderForSyncThread() { |
+ DCHECK(CalledOnValidThread()); |
+ scoped_ptr<syncer::SyncAuthProvider> auth_provider(new SyncThreadProxy( |
+ weak_factory_.GetWeakPtr(), base::MessageLoopProxy::current())); |
+ return auth_provider.Pass(); |
+} |