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 "mojo/services/network/url_loader_impl.h" | 5 #include "mojo/services/network/url_loader_impl.h" |
6 | 6 |
7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
8 #include "mojo/common/common_type_converters.h" | 8 #include "mojo/common/common_type_converters.h" |
9 #include "mojo/services/network/network_context.h" | 9 #include "mojo/services/network/network_context.h" |
10 #include "net/base/io_buffer.h" | 10 #include "net/base/io_buffer.h" |
(...skipping 28 matching lines...) Expand all Loading... |
39 url_request->GetMimeType(&mime_type); | 39 url_request->GetMimeType(&mime_type); |
40 response->mime_type = mime_type; | 40 response->mime_type = mime_type; |
41 | 41 |
42 std::string charset; | 42 std::string charset; |
43 url_request->GetCharset(&charset); | 43 url_request->GetCharset(&charset); |
44 response->charset = charset; | 44 response->charset = charset; |
45 | 45 |
46 return response.Pass(); | 46 return response.Pass(); |
47 } | 47 } |
48 | 48 |
| 49 NetworkErrorPtr MakeNetworkError(int error_code) { |
| 50 NetworkErrorPtr error = NetworkError::New(); |
| 51 error->code = error_code; |
| 52 error->description = net::ErrorToString(error_code); |
| 53 return error.Pass(); |
| 54 } |
| 55 |
49 } // namespace | 56 } // namespace |
50 | 57 |
51 // Keeps track of a pending two-phase write on a DataPipeProducerHandle. | 58 // Keeps track of a pending two-phase write on a DataPipeProducerHandle. |
52 class URLLoaderImpl::PendingWriteToDataPipe : | 59 class URLLoaderImpl::PendingWriteToDataPipe : |
53 public base::RefCountedThreadSafe<PendingWriteToDataPipe> { | 60 public base::RefCountedThreadSafe<PendingWriteToDataPipe> { |
54 public: | 61 public: |
55 explicit PendingWriteToDataPipe(ScopedDataPipeProducerHandle handle) | 62 explicit PendingWriteToDataPipe(ScopedDataPipeProducerHandle handle) |
56 : handle_(handle.Pass()), | 63 : handle_(handle.Pass()), |
57 buffer_(NULL) { | 64 buffer_(NULL) { |
58 } | 65 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 : net::WrappedIOBuffer(pending_write->buffer()), | 103 : net::WrappedIOBuffer(pending_write->buffer()), |
97 pending_write_(pending_write) { | 104 pending_write_(pending_write) { |
98 } | 105 } |
99 private: | 106 private: |
100 virtual ~DependentIOBuffer() {} | 107 virtual ~DependentIOBuffer() {} |
101 scoped_refptr<PendingWriteToDataPipe> pending_write_; | 108 scoped_refptr<PendingWriteToDataPipe> pending_write_; |
102 }; | 109 }; |
103 | 110 |
104 URLLoaderImpl::URLLoaderImpl(NetworkContext* context) | 111 URLLoaderImpl::URLLoaderImpl(NetworkContext* context) |
105 : context_(context), | 112 : context_(context), |
| 113 response_body_buffer_size_(0), |
106 auto_follow_redirects_(true), | 114 auto_follow_redirects_(true), |
107 weak_ptr_factory_(this) { | 115 weak_ptr_factory_(this) { |
108 } | 116 } |
109 | 117 |
110 URLLoaderImpl::~URLLoaderImpl() { | 118 URLLoaderImpl::~URLLoaderImpl() { |
111 } | 119 } |
112 | 120 |
113 void URLLoaderImpl::OnConnectionError() { | 121 void URLLoaderImpl::OnConnectionError() { |
114 delete this; | 122 delete this; |
115 } | 123 } |
116 | 124 |
117 void URLLoaderImpl::Start(URLRequestPtr request, | 125 void URLLoaderImpl::Start(URLRequestPtr request, |
118 ScopedDataPipeProducerHandle response_body_stream) { | 126 const Callback<void(URLResponsePtr)>& callback) { |
119 // Do not allow starting another request. | |
120 if (url_request_) { | 127 if (url_request_) { |
121 SendError(net::ERR_UNEXPECTED); | 128 SendError(net::ERR_UNEXPECTED, callback); |
122 url_request_.reset(); | |
123 response_body_stream_.reset(); | |
124 return; | 129 return; |
125 } | 130 } |
126 | 131 |
127 if (!request) { | 132 if (!request) { |
128 SendError(net::ERR_INVALID_ARGUMENT); | 133 SendError(net::ERR_INVALID_ARGUMENT, callback); |
129 return; | 134 return; |
130 } | 135 } |
131 | 136 |
132 response_body_stream_ = response_body_stream.Pass(); | |
133 | |
134 GURL url(request->url); | |
135 url_request_.reset( | 137 url_request_.reset( |
136 new net::URLRequest(url, | 138 new net::URLRequest(GURL(request->url), |
137 net::DEFAULT_PRIORITY, | 139 net::DEFAULT_PRIORITY, |
138 this, | 140 this, |
139 context_->url_request_context())); | 141 context_->url_request_context())); |
140 url_request_->set_method(request->method); | 142 url_request_->set_method(request->method); |
141 if (request->headers) { | 143 if (request->headers) { |
142 net::HttpRequestHeaders headers; | 144 net::HttpRequestHeaders headers; |
143 for (size_t i = 0; i < request->headers.size(); ++i) | 145 for (size_t i = 0; i < request->headers.size(); ++i) |
144 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>()); | 146 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>()); |
145 url_request_->SetExtraRequestHeaders(headers); | 147 url_request_->SetExtraRequestHeaders(headers); |
146 } | 148 } |
147 if (request->bypass_cache) | 149 if (request->bypass_cache) |
148 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE); | 150 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE); |
149 // TODO(darin): Handle request body. | 151 // TODO(darin): Handle request body. |
150 | 152 |
| 153 callback_ = callback; |
| 154 response_body_buffer_size_ = request->response_body_buffer_size; |
151 auto_follow_redirects_ = request->auto_follow_redirects; | 155 auto_follow_redirects_ = request->auto_follow_redirects; |
152 | 156 |
153 url_request_->Start(); | 157 url_request_->Start(); |
154 } | 158 } |
155 | 159 |
156 void URLLoaderImpl::FollowRedirect() { | 160 void URLLoaderImpl::FollowRedirect( |
| 161 const Callback<void(URLResponsePtr)>& callback) { |
| 162 if (!url_request_) { |
| 163 SendError(net::ERR_UNEXPECTED, callback); |
| 164 return; |
| 165 } |
| 166 |
157 if (auto_follow_redirects_) { | 167 if (auto_follow_redirects_) { |
158 DLOG(ERROR) << "Spurious call to FollowRedirect"; | 168 DLOG(ERROR) << "Spurious call to FollowRedirect"; |
| 169 SendError(net::ERR_UNEXPECTED, callback); |
| 170 return; |
| 171 } |
| 172 |
| 173 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect. |
| 174 url_request_->FollowDeferredRedirect(); |
| 175 } |
| 176 |
| 177 void URLLoaderImpl::QueryStatus( |
| 178 const Callback<void(URLLoaderStatusPtr)>& callback) { |
| 179 URLLoaderStatusPtr status(URLLoaderStatus::New()); |
| 180 if (url_request_) { |
| 181 status->is_loading = url_request_->is_pending(); |
| 182 if (!url_request_->status().is_success()) |
| 183 status->error = MakeNetworkError(url_request_->status().error()); |
159 } else { | 184 } else { |
160 if (url_request_) | 185 status->is_loading = false; |
161 url_request_->FollowDeferredRedirect(); | |
162 } | 186 } |
| 187 // TODO(darin): Populate more status fields. |
| 188 callback.Run(status.Pass()); |
163 } | 189 } |
164 | 190 |
165 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, | 191 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, |
166 const GURL& new_url, | 192 const GURL& new_url, |
167 bool* defer_redirect) { | 193 bool* defer_redirect) { |
168 DCHECK(url_request == url_request_.get()); | 194 DCHECK(url_request == url_request_.get()); |
169 DCHECK(url_request->status().is_success()); | 195 DCHECK(url_request->status().is_success()); |
170 | 196 |
| 197 if (auto_follow_redirects_) |
| 198 return; |
| 199 |
| 200 // Send the redirect response to the client, allowing them to inspect it and |
| 201 // optionally follow the redirect. |
| 202 *defer_redirect = true; |
| 203 |
171 URLResponsePtr response = MakeURLResponse(url_request); | 204 URLResponsePtr response = MakeURLResponse(url_request); |
172 std::string redirect_method = | 205 response->redirect_method = |
173 net::URLRequest::ComputeMethodForRedirect(url_request->method(), | 206 net::URLRequest::ComputeMethodForRedirect(url_request->method(), |
174 response->status_code); | 207 response->status_code); |
175 client()->OnReceivedRedirect( | 208 response->redirect_url = new_url.spec(); |
176 response.Pass(), new_url.spec(), redirect_method); | |
177 | 209 |
178 *defer_redirect = !auto_follow_redirects_; | 210 SendResponse(response.Pass()); |
179 } | 211 } |
180 | 212 |
181 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { | 213 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { |
182 DCHECK(url_request == url_request_.get()); | 214 DCHECK(url_request == url_request_.get()); |
183 | 215 |
184 if (!url_request->status().is_success()) { | 216 if (!url_request->status().is_success()) { |
185 SendError(url_request->status().error()); | 217 SendError(url_request->status().error(), callback_); |
| 218 callback_ = Callback<void(URLResponsePtr)>(); |
186 return; | 219 return; |
187 } | 220 } |
188 | 221 |
189 // TODO(darin): Add support for optional MIME sniffing. | 222 // TODO(darin): Add support for optional MIME sniffing. |
190 | 223 |
191 client()->OnReceivedResponse(MakeURLResponse(url_request)); | 224 DataPipe data_pipe; |
| 225 // TODO(darin): Honor given buffer size. |
| 226 |
| 227 URLResponsePtr response = MakeURLResponse(url_request); |
| 228 response->body = data_pipe.consumer_handle.Pass(); |
| 229 response_body_stream_ = data_pipe.producer_handle.Pass(); |
| 230 |
| 231 SendResponse(response.Pass()); |
192 | 232 |
193 // Start reading... | 233 // Start reading... |
194 ReadMore(); | 234 ReadMore(); |
195 } | 235 } |
196 | 236 |
197 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, | 237 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, |
198 int bytes_read) { | 238 int bytes_read) { |
| 239 DCHECK(url_request == url_request_.get()); |
| 240 |
199 if (url_request->status().is_success()) { | 241 if (url_request->status().is_success()) { |
200 DidRead(static_cast<uint32_t>(bytes_read), false); | 242 DidRead(static_cast<uint32_t>(bytes_read), false); |
201 } else { | 243 } else { |
202 pending_write_ = NULL; // This closes the data pipe. | 244 pending_write_ = NULL; // This closes the data pipe. |
203 // TODO(darin): Perhaps we should communicate this error to our client. | |
204 } | 245 } |
205 } | 246 } |
206 | 247 |
207 void URLLoaderImpl::SendError(int error_code) { | 248 void URLLoaderImpl::SendError( |
208 NetworkErrorPtr error(NetworkError::New()); | 249 int error_code, |
209 error->code = error_code; | 250 const Callback<void(URLResponsePtr)>& callback) { |
210 error->description = net::ErrorToString(error_code); | 251 URLResponsePtr response(URLResponse::New()); |
211 client()->OnReceivedError(error.Pass()); | 252 if (url_request_) |
| 253 response->url = url_request_->url().spec(); |
| 254 response->error = MakeNetworkError(error_code); |
| 255 callback.Run(response.Pass()); |
| 256 } |
| 257 |
| 258 void URLLoaderImpl::SendResponse(URLResponsePtr response) { |
| 259 Callback<void(URLResponsePtr)> callback; |
| 260 std::swap(callback_, callback); |
| 261 callback.Run(response.Pass()); |
212 } | 262 } |
213 | 263 |
214 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { | 264 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { |
215 // TODO(darin): Handle a bad |result| value. | 265 // TODO(darin): Handle a bad |result| value. |
216 ReadMore(); | 266 ReadMore(); |
217 } | 267 } |
218 | 268 |
219 void URLLoaderImpl::WaitToReadMore() { | 269 void URLLoaderImpl::WaitToReadMore() { |
220 handle_watcher_.Start(response_body_stream_.get(), | 270 handle_watcher_.Start(response_body_stream_.get(), |
221 MOJO_HANDLE_SIGNAL_WRITABLE, | 271 MOJO_HANDLE_SIGNAL_WRITABLE, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 // Drop our reference to the buffer. | 303 // Drop our reference to the buffer. |
254 buf = NULL; | 304 buf = NULL; |
255 | 305 |
256 if (url_request_->status().is_io_pending()) { | 306 if (url_request_->status().is_io_pending()) { |
257 // Wait for OnReadCompleted. | 307 // Wait for OnReadCompleted. |
258 } else if (url_request_->status().is_success() && bytes_read > 0) { | 308 } else if (url_request_->status().is_success() && bytes_read > 0) { |
259 DidRead(static_cast<uint32_t>(bytes_read), true); | 309 DidRead(static_cast<uint32_t>(bytes_read), true); |
260 } else { | 310 } else { |
261 pending_write_->Complete(0); | 311 pending_write_->Complete(0); |
262 pending_write_ = NULL; // This closes the data pipe. | 312 pending_write_ = NULL; // This closes the data pipe. |
263 if (bytes_read == 0) { | |
264 client()->OnReceivedEndOfResponseBody(); | |
265 } else { | |
266 DCHECK(!url_request_->status().is_success()); | |
267 SendError(url_request_->status().error()); | |
268 } | |
269 } | 313 } |
270 } | 314 } |
271 | 315 |
272 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) { | 316 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) { |
273 DCHECK(url_request_->status().is_success()); | 317 DCHECK(url_request_->status().is_success()); |
274 | 318 |
275 response_body_stream_ = pending_write_->Complete(num_bytes); | 319 response_body_stream_ = pending_write_->Complete(num_bytes); |
276 pending_write_ = NULL; | 320 pending_write_ = NULL; |
277 | 321 |
278 if (completed_synchronously) { | 322 if (completed_synchronously) { |
279 base::MessageLoop::current()->PostTask( | 323 base::MessageLoop::current()->PostTask( |
280 FROM_HERE, | 324 FROM_HERE, |
281 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr())); | 325 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr())); |
282 } else { | 326 } else { |
283 ReadMore(); | 327 ReadMore(); |
284 } | 328 } |
285 } | 329 } |
286 | 330 |
287 } // namespace mojo | 331 } // namespace mojo |
OLD | NEW |