| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "services/authenticating_url_loader/authenticating_url_loader_impl.h" | 5 #include "services/authenticating_url_loader/authenticating_url_loader_intercept
or.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "mojo/services/network/public/interfaces/network_service.mojom.h" | 9 #include "mojo/services/network/public/interfaces/network_service.mojom.h" |
| 10 | 10 |
| 11 namespace mojo { | 11 namespace mojo { |
| 12 | 12 |
| 13 AuthenticatingURLLoaderImpl::AuthenticatingURLLoaderImpl( | 13 AuthenticatingURLLoaderInterceptor::AuthenticatingURLLoaderInterceptor( |
| 14 InterfaceRequest<AuthenticatingURLLoader> request, | 14 mojo::InterfaceRequest<URLLoaderInterceptor> request, |
| 15 AuthenticatingURLLoaderFactoryImpl* factory) | 15 AuthenticatingURLLoaderInterceptorFactory* factory) |
| 16 : binding_(this, request.Pass()), | 16 : binding_(this, request.Pass()), |
| 17 factory_(factory), | 17 factory_(factory), |
| 18 request_authorization_state_(REQUEST_INITIAL) { | 18 request_authorization_state_(REQUEST_INITIAL) { |
| 19 binding_.set_error_handler(this); | 19 binding_.set_error_handler(this); |
| 20 } | 20 } |
| 21 | 21 |
| 22 AuthenticatingURLLoaderImpl::~AuthenticatingURLLoaderImpl() { | 22 AuthenticatingURLLoaderInterceptor::~AuthenticatingURLLoaderInterceptor() { |
| 23 } | 23 } |
| 24 | 24 |
| 25 void AuthenticatingURLLoaderImpl::Start( | 25 void AuthenticatingURLLoaderInterceptor::InterceptRequest( |
| 26 URLRequestPtr request, | 26 mojo::URLRequestPtr request, |
| 27 const Callback<void(URLResponsePtr)>& callback) { | 27 const InterceptRequestCallback& callback) { |
| 28 // TODO(blundell): If we need to handle requests with bodies, we'll need to | 28 // TODO(blundell): If we need to handle requests with bodies, we'll need to |
| 29 // do something here. | 29 // do something here. |
| 30 if (request->body) { | 30 if (request->body) { |
| 31 LOG(ERROR) | 31 LOG(ERROR) << "Cannot pass a request to AuthenticatingURLLoaderInterceptor" |
| 32 << "Cannot pass a request to AuthenticatingURLLoader that has a body"; | 32 "that has a body"; |
| 33 callback.Run(nullptr); | 33 callback.Run(nullptr); |
| 34 return; | 34 return; |
| 35 } | 35 } |
| 36 pending_interception_callback_ = callback; |
| 36 url_ = GURL(request->url); | 37 url_ = GURL(request->url); |
| 37 auto_follow_redirects_ = request->auto_follow_redirects; | 38 auto_follow_redirects_ = request->auto_follow_redirects; |
| 39 request->auto_follow_redirects = false; |
| 38 bypass_cache_ = request->bypass_cache; | 40 bypass_cache_ = request->bypass_cache; |
| 39 headers_ = request->headers.Clone(); | 41 headers_ = request->headers.Clone(); |
| 40 pending_request_callback_ = callback; | 42 |
| 41 std::string token = factory_->GetCachedToken(url_); | 43 std::string token = factory_->GetCachedToken(url_); |
| 42 if (token != "") { | 44 if (token != "") { |
| 43 auto auth_header = HttpHeader::New(); | 45 auto auth_header = HttpHeader::New(); |
| 44 auth_header->name = "Authorization"; | 46 auth_header->name = "Authorization"; |
| 45 auth_header->value = "Bearer " + token; | 47 auth_header->value = "Bearer " + token; |
| 46 request->headers.push_back(auth_header.Pass()); | 48 request->headers.push_back(auth_header.Pass()); |
| 47 } | 49 } |
| 48 StartNetworkRequest(request.Pass()); | 50 |
| 51 StartRequest(request.Pass()); |
| 49 } | 52 } |
| 50 | 53 |
| 51 void AuthenticatingURLLoaderImpl::FollowRedirect( | 54 void AuthenticatingURLLoaderInterceptor::InterceptFollowRedirect( |
| 52 const Callback<void(URLResponsePtr)>& callback) { | 55 const InterceptResponseCallback& callback) { |
| 53 mojo::String error; | 56 mojo::String error; |
| 54 | 57 |
| 55 if (!url_.is_valid() || !url_loader_) { | 58 if (!url_.is_valid()) { |
| 56 error = "No redirect to follow"; | 59 error = "No redirect to follow"; |
| 57 } | 60 } |
| 58 | 61 |
| 59 if (auto_follow_redirects_) { | 62 if (auto_follow_redirects_) { |
| 60 error = | 63 error = |
| 61 "FollowRedirect() should not be " | 64 "InterceptFollowRedirect() should not be " |
| 62 "called when auto_follow_redirects has been set"; | 65 "called when auto_follow_redirects has been set"; |
| 63 } | 66 } |
| 64 | 67 |
| 65 if (request_authorization_state_ != REQUEST_INITIAL) { | 68 if (request_authorization_state_ != REQUEST_INITIAL) { |
| 66 error = "Not in the right state to follow a redirect"; | 69 error = "Not in the right state to follow a redirect"; |
| 67 } | 70 } |
| 68 | 71 |
| 69 if (!error.is_null()) { | 72 if (!error.is_null()) { |
| 70 LOG(ERROR) << "AuthenticatingURLLoader: " << error; | 73 LOG(ERROR) << "AuthenticatingURLLoaderInterceptor: " << error; |
| 71 callback.Run(nullptr); | 74 callback.Run(nullptr); |
| 72 return; | 75 return; |
| 73 } | 76 } |
| 74 | 77 |
| 75 pending_request_callback_ = callback; | 78 // If there is no cached token, have the URLLoader follow the redirect |
| 76 FollowRedirectInternal(); | 79 // itself. |
| 77 } | 80 std::string token = factory_->GetCachedToken(url_); |
| 78 | 81 if (token == "") { |
| 79 void AuthenticatingURLLoaderImpl::StartNetworkRequest(URLRequestPtr request) { | 82 callback.Run(nullptr); |
| 80 factory_->network_service()->CreateURLLoader(mojo::GetProxy(&url_loader_)); | |
| 81 url_loader_->Start(request.Pass(), | |
| 82 base::Bind(&AuthenticatingURLLoaderImpl::OnLoadComplete, | |
| 83 base::Unretained(this))); | |
| 84 } | |
| 85 | |
| 86 void AuthenticatingURLLoaderImpl::OnConnectionError() { | |
| 87 factory_->OnURLLoaderError(this); | |
| 88 // The factory deleted this object. | |
| 89 } | |
| 90 | |
| 91 void AuthenticatingURLLoaderImpl::OnLoadComplete(URLResponsePtr response) { | |
| 92 if (response->redirect_url) { | |
| 93 url_ = GURL(response->redirect_url); | |
| 94 request_authorization_state_ = REQUEST_INITIAL; | |
| 95 | |
| 96 if (auto_follow_redirects_) { | |
| 97 FollowRedirectInternal(); | |
| 98 } else { | |
| 99 // NOTE: We do not reset |url_loader_| here as it will be needed if the | |
| 100 // client calls |FollowRedirect()|. | |
| 101 pending_request_callback_.Run(response.Pass()); | |
| 102 } | |
| 103 return; | 83 return; |
| 104 } | 84 } |
| 105 | 85 |
| 106 url_loader_.reset(); | 86 pending_interception_callback_ = callback; |
| 87 StartRequest(BuildRequest(token)); |
| 88 } |
| 107 | 89 |
| 108 if (response->status_code != 401 || | 90 void AuthenticatingURLLoaderInterceptor::InterceptResponse( |
| 91 mojo::URLResponsePtr response, |
| 92 const InterceptResponseCallback& callback) { |
| 93 pending_interception_callback_ = callback; |
| 94 pending_response_ = response.Pass(); |
| 95 |
| 96 if (pending_response_->status_code != 401 || |
| 109 request_authorization_state_ == REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN) { | 97 request_authorization_state_ == REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN) { |
| 110 pending_request_callback_.Run(response.Pass()); | 98 if (pending_response_->redirect_url) { |
| 99 url_ = GURL(pending_response_->redirect_url); |
| 100 request_authorization_state_ = REQUEST_INITIAL; |
| 101 if (auto_follow_redirects_) { |
| 102 // If there is no cached token, have the URLLoader follow the |
| 103 // redirect itself. |
| 104 std::string token = factory_->GetCachedToken(url_); |
| 105 if (token == "") |
| 106 pending_interception_callback_.Run(nullptr); |
| 107 else |
| 108 StartRequest(BuildRequest(token)); |
| 109 return; |
| 110 } |
| 111 } |
| 112 |
| 113 URLLoaderInterceptorResponsePtr interceptor_response = |
| 114 URLLoaderInterceptorResponse::New(); |
| 115 interceptor_response->response = pending_response_.Pass(); |
| 116 pending_interception_callback_.Run(interceptor_response.Pass()); |
| 111 return; | 117 return; |
| 112 } | 118 } |
| 113 | 119 |
| 114 pending_response_ = response.Pass(); | |
| 115 | |
| 116 DCHECK(request_authorization_state_ == REQUEST_INITIAL || | 120 DCHECK(request_authorization_state_ == REQUEST_INITIAL || |
| 117 request_authorization_state_ == | 121 request_authorization_state_ == |
| 118 REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN); | 122 REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN); |
| 119 if (request_authorization_state_ == REQUEST_INITIAL) { | 123 if (request_authorization_state_ == REQUEST_INITIAL) { |
| 120 request_authorization_state_ = REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN; | 124 request_authorization_state_ = REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN; |
| 121 } else { | 125 } else { |
| 122 request_authorization_state_ = REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN; | 126 request_authorization_state_ = REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN; |
| 123 } | 127 } |
| 124 factory_->RetrieveToken( | 128 factory_->RetrieveToken( |
| 125 url_, base::Bind(&AuthenticatingURLLoaderImpl::OnOAuth2TokenReceived, | 129 url_, |
| 126 base::Unretained(this))); | 130 base::Bind(&AuthenticatingURLLoaderInterceptor::OnOAuth2TokenReceived, |
| 127 return; | 131 base::Unretained(this))); |
| 128 } | 132 } |
| 129 | 133 |
| 130 void AuthenticatingURLLoaderImpl::FollowRedirectInternal() { | 134 void AuthenticatingURLLoaderInterceptor::OnConnectionError() { |
| 131 DCHECK(url_.is_valid()); | 135 factory_->OnInterceptorError(this); |
| 132 DCHECK(url_loader_); | 136 // The factory deleted this object. |
| 133 DCHECK(request_authorization_state_ == REQUEST_INITIAL); | |
| 134 | |
| 135 url_loader_->FollowRedirect(base::Bind( | |
| 136 &AuthenticatingURLLoaderImpl::OnLoadComplete, base::Unretained(this))); | |
| 137 } | 137 } |
| 138 | 138 |
| 139 void AuthenticatingURLLoaderImpl::OnOAuth2TokenReceived(std::string token) { | 139 URLRequestPtr AuthenticatingURLLoaderInterceptor::BuildRequest( |
| 140 if (token.empty()) { | 140 std::string token) { |
| 141 LOG(ERROR) << "Error while getting token"; | |
| 142 pending_request_callback_.Run(pending_response_.Pass()); | |
| 143 return; | |
| 144 } | |
| 145 | |
| 146 auto auth_header = HttpHeader::New(); | |
| 147 auth_header->name = "Authorization"; | |
| 148 auth_header->value = "Bearer " + token; | |
| 149 Array<HttpHeaderPtr> headers; | 141 Array<HttpHeaderPtr> headers; |
| 150 if (headers_) | 142 if (headers_) |
| 151 headers = headers_.Clone(); | 143 headers = headers_.Clone(); |
| 152 headers.push_back(auth_header.Pass()); | 144 |
| 145 if (token == "") |
| 146 token = factory_->GetCachedToken(url_); |
| 147 |
| 148 if (token != "") { |
| 149 auto auth_header = HttpHeader::New(); |
| 150 auth_header->name = "Authorization"; |
| 151 auth_header->value = "Bearer " + token; |
| 152 headers.push_back(auth_header.Pass()); |
| 153 } |
| 153 | 154 |
| 154 URLRequestPtr request(mojo::URLRequest::New()); | 155 URLRequestPtr request(mojo::URLRequest::New()); |
| 155 request->url = url_.spec(); | 156 request->url = url_.spec(); |
| 156 request->auto_follow_redirects = false; | 157 request->auto_follow_redirects = false; |
| 157 request->bypass_cache = bypass_cache_; | 158 request->bypass_cache = bypass_cache_; |
| 158 request->headers = headers.Pass(); | 159 request->headers = headers.Pass(); |
| 159 | 160 |
| 160 StartNetworkRequest(request.Pass()); | 161 return request.Pass(); |
| 162 } |
| 163 |
| 164 void AuthenticatingURLLoaderInterceptor::StartRequest( |
| 165 mojo::URLRequestPtr request) { |
| 166 URLLoaderInterceptorResponsePtr interceptor_response = |
| 167 URLLoaderInterceptorResponse::New(); |
| 168 interceptor_response->request = request.Pass(); |
| 169 pending_interception_callback_.Run(interceptor_response.Pass()); |
| 170 } |
| 171 |
| 172 void AuthenticatingURLLoaderInterceptor::OnOAuth2TokenReceived( |
| 173 std::string token) { |
| 174 URLLoaderInterceptorResponsePtr interceptor_response = |
| 175 URLLoaderInterceptorResponse::New(); |
| 176 |
| 177 if (token.empty()) { |
| 178 LOG(ERROR) << "Error while getting token"; |
| 179 interceptor_response->response = pending_response_.Pass(); |
| 180 } else { |
| 181 interceptor_response->request = BuildRequest(token); |
| 182 } |
| 183 |
| 184 pending_interception_callback_.Run(interceptor_response.Pass()); |
| 161 } | 185 } |
| 162 | 186 |
| 163 } // namespace mojo | 187 } // namespace mojo |
| OLD | NEW |