OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "google_apis/gaia/oauth2_token_service_proxy.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/containers/scoped_ptr_hash_map.h" |
| 9 #include "base/message_loop/message_loop.h" |
| 10 #include "base/threading/non_thread_safe.h" |
| 11 #include "google_apis/gaia/google_service_auth_error.h" |
| 12 |
| 13 namespace { |
| 14 |
| 15 // Retains an OAuth2TokenService::Request and proxies calls to |
| 16 // OAuth2TokenService::Consumer methods to |callback| on the |
| 17 // |callback_task_runner| thread. |
| 18 class RequestContext : public OAuth2TokenService::Consumer, |
| 19 public base::NonThreadSafe { |
| 20 public: |
| 21 // |requester_id| is a string that describes the service requesting the token. |
| 22 // |
| 23 // |callback_task_runner| is the thread that |callback| lives on. |
| 24 // |
| 25 // |callback| will be invoked when the request has completed. |
| 26 // |
| 27 // |request_done_closure| is a closure used by RequestContext to signal that |
| 28 // its job is all done and can be destroyed. This closure will be posted to |
| 29 // the same thread on which RequestContext is constructed. |
| 30 RequestContext( |
| 31 const std::string& requester_id, |
| 32 const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner, |
| 33 const OAuth2TokenServiceProxy::RequestTokenCallback& callback, |
| 34 const base::Closure& request_done_closure); |
| 35 |
| 36 virtual ~RequestContext(); |
| 37 |
| 38 // OAuth2TokenService::Consumer implementation. |
| 39 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request, |
| 40 const std::string& access_token, |
| 41 const base::Time& expiration_time) OVERRIDE; |
| 42 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request, |
| 43 const GoogleServiceAuthError& error) OVERRIDE; |
| 44 |
| 45 void SetRequest(scoped_ptr<OAuth2TokenService::Request> request); |
| 46 |
| 47 private: |
| 48 scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; |
| 49 OAuth2TokenServiceProxy::RequestTokenCallback callback_; |
| 50 base::Closure request_done_closure_; |
| 51 scoped_ptr<OAuth2TokenService::Request> request_; |
| 52 }; |
| 53 |
| 54 RequestContext::RequestContext( |
| 55 const std::string& requester_id, |
| 56 const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner, |
| 57 const OAuth2TokenServiceProxy::RequestTokenCallback& callback, |
| 58 const base::Closure& request_done_closure) |
| 59 : OAuth2TokenService::Consumer(requester_id), |
| 60 callback_task_runner_(callback_task_runner), |
| 61 callback_(callback), |
| 62 request_done_closure_(request_done_closure) { |
| 63 DCHECK(CalledOnValidThread()); |
| 64 DCHECK(callback_task_runner_); |
| 65 } |
| 66 |
| 67 RequestContext::~RequestContext() { |
| 68 DCHECK(CalledOnValidThread()); |
| 69 } |
| 70 |
| 71 void RequestContext::OnGetTokenSuccess( |
| 72 const OAuth2TokenService::Request* request, |
| 73 const std::string& access_token, |
| 74 const base::Time& expiration_time) { |
| 75 DCHECK(CalledOnValidThread()); |
| 76 callback_task_runner_->PostTask( |
| 77 FROM_HERE, |
| 78 base::Bind(callback_, |
| 79 GoogleServiceAuthError::AuthErrorNone(), |
| 80 access_token, |
| 81 expiration_time)); |
| 82 base::MessageLoop::current()->PostTask(FROM_HERE, request_done_closure_); |
| 83 } |
| 84 |
| 85 void RequestContext::OnGetTokenFailure( |
| 86 const OAuth2TokenService::Request* request, |
| 87 const GoogleServiceAuthError& error) { |
| 88 const std::string access_token; |
| 89 const base::Time expiration_time; |
| 90 DCHECK(CalledOnValidThread()); |
| 91 callback_task_runner_->PostTask( |
| 92 FROM_HERE, base::Bind(callback_, error, access_token, expiration_time)); |
| 93 base::MessageLoop::current()->PostTask(FROM_HERE, request_done_closure_); |
| 94 } |
| 95 |
| 96 void RequestContext::SetRequest( |
| 97 scoped_ptr<OAuth2TokenService::Request> request) { |
| 98 DCHECK(CalledOnValidThread()); |
| 99 request_ = request.Pass(); |
| 100 } |
| 101 |
| 102 } // namespace |
| 103 |
| 104 // Core lives on the same thread as the OAuth2TokenService and retains |
| 105 // OAuth2TokenService::Request objects returned by StartRequest. |
| 106 class OAuth2TokenServiceProxy::Core |
| 107 : public base::RefCountedThreadSafe<OAuth2TokenServiceProxy::Core>, |
| 108 public base::NonThreadSafe { |
| 109 public: |
| 110 Core(OAuth2TokenService* token_service); |
| 111 |
| 112 virtual void RequestToken( |
| 113 const std::string& account_id, |
| 114 const OAuth2TokenService::ScopeSet& scopes, |
| 115 const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner, |
| 116 const RequestTokenCallback& callback, |
| 117 const std::string& requester_id); |
| 118 |
| 119 virtual void InvalidateToken(const std::string& account_id, |
| 120 const OAuth2TokenService::ScopeSet& scopes, |
| 121 const std::string& access_token); |
| 122 |
| 123 private: |
| 124 friend class base::RefCountedThreadSafe<OAuth2TokenServiceProxy::Core>; |
| 125 virtual ~Core(); |
| 126 void RemoveRequest(int64 request_id); |
| 127 |
| 128 OAuth2TokenService* token_service_; |
| 129 // Used to identify RequestContexts in the request_context_map_. When |
| 130 // completed, RequestContexts can be removed from the map by their id. |
| 131 int64 next_id_; |
| 132 base::ScopedPtrHashMap<int64, RequestContext> request_context_map_; |
| 133 }; |
| 134 |
| 135 OAuth2TokenServiceProxy::Core::Core(OAuth2TokenService* token_service) |
| 136 : token_service_(token_service), next_id_(0) { |
| 137 DCHECK(token_service_); |
| 138 DetachFromThread(); |
| 139 } |
| 140 |
| 141 OAuth2TokenServiceProxy::Core::~Core() { |
| 142 DCHECK(CalledOnValidThread()); |
| 143 } |
| 144 |
| 145 void OAuth2TokenServiceProxy::Core::RemoveRequest(int64 request_id) { |
| 146 request_context_map_.erase(request_id); |
| 147 } |
| 148 |
| 149 void OAuth2TokenServiceProxy::Core::RequestToken( |
| 150 const std::string& account_id, |
| 151 const OAuth2TokenService::ScopeSet& scopes, |
| 152 const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner, |
| 153 const RequestTokenCallback& callback, |
| 154 const std::string& requester_id) { |
| 155 DCHECK(CalledOnValidThread()); |
| 156 |
| 157 // Create a Closure that can be used to remove the RequestContext we are about |
| 158 // to create. |
| 159 int64 request_id = next_id_++; |
| 160 base::Closure request_done_closure = base::Bind( |
| 161 &OAuth2TokenServiceProxy::Core::RemoveRequest, this, request_id); |
| 162 |
| 163 // Create a RequestContext that will retain a Request and adapt the Consumer |
| 164 // interface to the user's callback. |
| 165 scoped_ptr<RequestContext> request_context(new RequestContext( |
| 166 requester_id, callback_task_runner, callback, request_done_closure)); |
| 167 |
| 168 // Start a Request. |
| 169 scoped_ptr<OAuth2TokenService::Request> request = |
| 170 token_service_->StartRequest(account_id, scopes, request_context.get()); |
| 171 |
| 172 // Then stash it. |
| 173 request_context->SetRequest(request.Pass()); |
| 174 request_context_map_.set(request_id, request_context.Pass()); |
| 175 } |
| 176 |
| 177 void OAuth2TokenServiceProxy::Core::InvalidateToken( |
| 178 const std::string& account_id, |
| 179 const OAuth2TokenService::ScopeSet& scopes, |
| 180 const std::string& access_token) { |
| 181 DCHECK(CalledOnValidThread()); |
| 182 token_service_->InvalidateToken(account_id, scopes, access_token); |
| 183 } |
| 184 |
| 185 OAuth2TokenServiceProxy::OAuth2TokenServiceProxy( |
| 186 const scoped_refptr<base::SequencedTaskRunner>& token_service_task_runner, |
| 187 OAuth2TokenService* token_service) |
| 188 : core_task_runner_(token_service_task_runner), |
| 189 core_(new Core(token_service)) { |
| 190 DCHECK(CalledOnValidThread()); |
| 191 DCHECK(core_task_runner_); |
| 192 } |
| 193 |
| 194 OAuth2TokenServiceProxy::~OAuth2TokenServiceProxy() { |
| 195 DCHECK(CalledOnValidThread()); |
| 196 // core_ lives on the core_task_runner_ thread so we need to ensure it is |
| 197 // destroyed there. |
| 198 core_->AddRef(); |
| 199 core_task_runner_->ReleaseSoon(FROM_HERE, core_.get()); |
| 200 core_ = NULL; |
| 201 } |
| 202 |
| 203 void OAuth2TokenServiceProxy::RequestToken( |
| 204 const std::string& account_id, |
| 205 const OAuth2TokenService::ScopeSet& scopes, |
| 206 const RequestTokenCallback& callback, |
| 207 const std::string& requester_id) { |
| 208 DCHECK(CalledOnValidThread()); |
| 209 core_task_runner_->PostTask( |
| 210 FROM_HERE, |
| 211 base::Bind(&OAuth2TokenServiceProxy::Core::RequestToken, |
| 212 core_, |
| 213 account_id, |
| 214 scopes, |
| 215 base::MessageLoopProxy::current(), |
| 216 callback, |
| 217 requester_id)); |
| 218 } |
| 219 |
| 220 void OAuth2TokenServiceProxy::InvalidateToken( |
| 221 const std::string& account_id, |
| 222 const OAuth2TokenService::ScopeSet& scopes, |
| 223 const std::string& access_token) { |
| 224 DCHECK(CalledOnValidThread()); |
| 225 core_task_runner_->PostTask( |
| 226 FROM_HERE, |
| 227 base::Bind(&OAuth2TokenServiceProxy::Core::InvalidateToken, |
| 228 core_, |
| 229 account_id, |
| 230 scopes, |
| 231 access_token)); |
| 232 } |
OLD | NEW |