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 |