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/memory/scoped_vector.h" | 7 #include "base/memory/scoped_vector.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
9 #include "mojo/common/common_type_converters.h" | 9 #include "mojo/common/common_type_converters.h" |
10 #include "mojo/services/network/net_adapters.h" | 10 #include "mojo/services/network/net_adapters.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 URLResponsePtr MakeURLResponse(const net::URLRequest* url_request) { | 24 URLResponsePtr MakeURLResponse(const net::URLRequest* url_request) { |
25 URLResponsePtr response(URLResponse::New()); | 25 URLResponsePtr response(URLResponse::New()); |
26 response->url = String::From(url_request->url()); | 26 response->url = String::From(url_request->url()); |
27 | 27 |
28 const net::HttpResponseHeaders* headers = url_request->response_headers(); | 28 const net::HttpResponseHeaders* headers = url_request->response_headers(); |
29 if (headers) { | 29 if (headers) { |
30 response->status_code = headers->response_code(); | 30 response->status_code = headers->response_code(); |
31 response->status_line = headers->GetStatusLine(); | 31 response->status_line = headers->GetStatusLine(); |
32 | 32 |
33 std::vector<String> header_lines; | 33 std::vector<String> header_lines; |
34 void* iter = NULL; | 34 void* iter = nullptr; |
35 std::string name, value; | 35 std::string name, value; |
36 while (headers->EnumerateHeaderLines(&iter, &name, &value)) | 36 while (headers->EnumerateHeaderLines(&iter, &name, &value)) |
37 header_lines.push_back(name + ": " + value); | 37 header_lines.push_back(name + ": " + value); |
38 if (!header_lines.empty()) | 38 if (!header_lines.empty()) |
39 response->headers.Swap(&header_lines); | 39 response->headers.Swap(&header_lines); |
40 } | 40 } |
41 | 41 |
42 std::string mime_type; | 42 std::string mime_type; |
43 url_request->GetMimeType(&mime_type); | 43 url_request->GetMimeType(&mime_type); |
44 response->mime_type = mime_type; | 44 response->mime_type = mime_type; |
45 | 45 |
46 std::string charset; | 46 std::string charset; |
47 url_request->GetCharset(&charset); | 47 url_request->GetCharset(&charset); |
48 response->charset = charset; | 48 response->charset = charset; |
49 | 49 |
50 return response.Pass(); | 50 return response.Pass(); |
51 } | 51 } |
52 | 52 |
53 // Reads the request body upload data from a DataPipe. | 53 // Reads the request body upload data from a DataPipe. |
54 class UploadDataPipeElementReader : public net::UploadElementReader { | 54 class UploadDataPipeElementReader : public net::UploadElementReader { |
55 public: | 55 public: |
56 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe) | 56 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe) |
57 : pipe_(pipe.Pass()), num_bytes_(0) {} | 57 : pipe_(pipe.Pass()), num_bytes_(0) {} |
58 ~UploadDataPipeElementReader() override {} | 58 ~UploadDataPipeElementReader() override {} |
59 | 59 |
60 // UploadElementReader overrides: | 60 // UploadElementReader overrides: |
61 int Init(const net::CompletionCallback& callback) override { | 61 int Init(const net::CompletionCallback& callback) override { |
62 offset_ = 0; | 62 offset_ = 0; |
63 ReadDataRaw(pipe_.get(), NULL, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY); | 63 ReadDataRaw(pipe_.get(), nullptr, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY); |
64 return net::OK; | 64 return net::OK; |
65 } | 65 } |
66 uint64 GetContentLength() const override { return num_bytes_; } | 66 uint64 GetContentLength() const override { return num_bytes_; } |
67 uint64 BytesRemaining() const override { return num_bytes_ - offset_; } | 67 uint64 BytesRemaining() const override { return num_bytes_ - offset_; } |
68 bool IsInMemory() const override { return false; } | 68 bool IsInMemory() const override { return false; } |
69 int Read(net::IOBuffer* buf, | 69 int Read(net::IOBuffer* buf, |
70 int buf_length, | 70 int buf_length, |
71 const net::CompletionCallback& callback) override { | 71 const net::CompletionCallback& callback) override { |
72 uint32_t bytes_read = | 72 uint32_t bytes_read = |
73 std::min(static_cast<uint32_t>(BytesRemaining()), | 73 std::min(static_cast<uint32_t>(BytesRemaining()), |
(...skipping 10 matching lines...) Expand all Loading... |
84 private: | 84 private: |
85 ScopedDataPipeConsumerHandle pipe_; | 85 ScopedDataPipeConsumerHandle pipe_; |
86 uint32_t num_bytes_; | 86 uint32_t num_bytes_; |
87 uint32_t offset_; | 87 uint32_t offset_; |
88 | 88 |
89 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader); | 89 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader); |
90 }; | 90 }; |
91 | 91 |
92 } // namespace | 92 } // namespace |
93 | 93 |
94 URLLoaderImpl::URLLoaderImpl(NetworkContext* context) | 94 URLLoaderImpl::URLLoaderImpl(NetworkContext* context, |
| 95 InterfaceRequest<URLLoader> request) |
95 : context_(context), | 96 : context_(context), |
96 response_body_buffer_size_(0), | 97 response_body_buffer_size_(0), |
97 auto_follow_redirects_(true), | 98 auto_follow_redirects_(true), |
| 99 connected_(true), |
| 100 binding_(this, request.Pass()), |
98 weak_ptr_factory_(this) { | 101 weak_ptr_factory_(this) { |
| 102 binding_.set_error_handler(this); |
99 } | 103 } |
100 | 104 |
101 URLLoaderImpl::~URLLoaderImpl() { | 105 URLLoaderImpl::~URLLoaderImpl() { |
102 } | 106 } |
103 | 107 |
104 void URLLoaderImpl::Start(URLRequestPtr request, | 108 void URLLoaderImpl::Start(URLRequestPtr request, |
105 const Callback<void(URLResponsePtr)>& callback) { | 109 const Callback<void(URLResponsePtr)>& callback) { |
106 if (url_request_) { | 110 if (url_request_) { |
107 SendError(net::ERR_UNEXPECTED, callback); | 111 SendError(net::ERR_UNEXPECTED, callback); |
108 return; | 112 return; |
109 } | 113 } |
110 | 114 |
111 if (!request) { | 115 if (!request) { |
112 SendError(net::ERR_INVALID_ARGUMENT, callback); | 116 SendError(net::ERR_INVALID_ARGUMENT, callback); |
113 return; | 117 return; |
114 } | 118 } |
115 | 119 |
116 url_request_ = context_->url_request_context()->CreateRequest( | 120 url_request_ = context_->url_request_context()->CreateRequest( |
117 GURL(request->url), | 121 GURL(request->url), net::DEFAULT_PRIORITY, this, nullptr); |
118 net::DEFAULT_PRIORITY, | |
119 this, | |
120 NULL); | |
121 url_request_->set_method(request->method); | 122 url_request_->set_method(request->method); |
122 if (request->headers) { | 123 if (request->headers) { |
123 net::HttpRequestHeaders headers; | 124 net::HttpRequestHeaders headers; |
124 for (size_t i = 0; i < request->headers.size(); ++i) | 125 for (size_t i = 0; i < request->headers.size(); ++i) |
125 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>()); | 126 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>()); |
126 url_request_->SetExtraRequestHeaders(headers); | 127 url_request_->SetExtraRequestHeaders(headers); |
127 } | 128 } |
128 if (request->body) { | 129 if (request->body) { |
129 ScopedVector<net::UploadElementReader> element_readers; | 130 ScopedVector<net::UploadElementReader> element_readers; |
130 for (size_t i = 0; i < request->body.size(); ++i) { | 131 for (size_t i = 0; i < request->body.size(); ++i) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 status->is_loading = url_request_->is_pending(); | 169 status->is_loading = url_request_->is_pending(); |
169 if (!url_request_->status().is_success()) | 170 if (!url_request_->status().is_success()) |
170 status->error = MakeNetworkError(url_request_->status().error()); | 171 status->error = MakeNetworkError(url_request_->status().error()); |
171 } else { | 172 } else { |
172 status->is_loading = false; | 173 status->is_loading = false; |
173 } | 174 } |
174 // TODO(darin): Populate more status fields. | 175 // TODO(darin): Populate more status fields. |
175 callback.Run(status.Pass()); | 176 callback.Run(status.Pass()); |
176 } | 177 } |
177 | 178 |
| 179 void URLLoaderImpl::OnConnectionError() { |
| 180 connected_ = false; |
| 181 DeleteIfNeeded(); |
| 182 } |
| 183 |
178 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, | 184 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, |
179 const net::RedirectInfo& redirect_info, | 185 const net::RedirectInfo& redirect_info, |
180 bool* defer_redirect) { | 186 bool* defer_redirect) { |
181 DCHECK(url_request == url_request_.get()); | 187 DCHECK(url_request == url_request_.get()); |
182 DCHECK(url_request->status().is_success()); | 188 DCHECK(url_request->status().is_success()); |
183 | 189 |
184 if (auto_follow_redirects_) | 190 if (auto_follow_redirects_) |
185 return; | 191 return; |
186 | 192 |
187 // Send the redirect response to the client, allowing them to inspect it and | 193 // Send the redirect response to the client, allowing them to inspect it and |
188 // optionally follow the redirect. | 194 // optionally follow the redirect. |
189 *defer_redirect = true; | 195 *defer_redirect = true; |
190 | 196 |
191 URLResponsePtr response = MakeURLResponse(url_request); | 197 URLResponsePtr response = MakeURLResponse(url_request); |
192 response->redirect_method = redirect_info.new_method; | 198 response->redirect_method = redirect_info.new_method; |
193 response->redirect_url = String::From(redirect_info.new_url); | 199 response->redirect_url = String::From(redirect_info.new_url); |
194 | 200 |
195 SendResponse(response.Pass()); | 201 SendResponse(response.Pass()); |
| 202 |
| 203 DeleteIfNeeded(); |
196 } | 204 } |
197 | 205 |
198 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { | 206 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { |
199 DCHECK(url_request == url_request_.get()); | 207 DCHECK(url_request == url_request_.get()); |
200 | 208 |
201 if (!url_request->status().is_success()) { | 209 if (!url_request->status().is_success()) { |
202 SendError(url_request->status().error(), callback_); | 210 SendError(url_request->status().error(), callback_); |
203 callback_ = Callback<void(URLResponsePtr)>(); | 211 callback_ = Callback<void(URLResponsePtr)>(); |
| 212 DeleteIfNeeded(); |
204 return; | 213 return; |
205 } | 214 } |
206 | 215 |
207 // TODO(darin): Add support for optional MIME sniffing. | 216 // TODO(darin): Add support for optional MIME sniffing. |
208 | 217 |
209 DataPipe data_pipe; | 218 DataPipe data_pipe; |
210 // TODO(darin): Honor given buffer size. | 219 // TODO(darin): Honor given buffer size. |
211 | 220 |
212 URLResponsePtr response = MakeURLResponse(url_request); | 221 URLResponsePtr response = MakeURLResponse(url_request); |
213 response->body = data_pipe.consumer_handle.Pass(); | 222 response->body = data_pipe.consumer_handle.Pass(); |
214 response_body_stream_ = data_pipe.producer_handle.Pass(); | 223 response_body_stream_ = data_pipe.producer_handle.Pass(); |
| 224 ListenForPeerClosed(); |
215 | 225 |
216 SendResponse(response.Pass()); | 226 SendResponse(response.Pass()); |
217 | 227 |
218 // Start reading... | 228 // Start reading... |
219 ReadMore(); | 229 ReadMore(); |
220 } | 230 } |
221 | 231 |
222 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, | 232 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, |
223 int bytes_read) { | 233 int bytes_read) { |
224 DCHECK(url_request == url_request_.get()); | 234 DCHECK(url_request == url_request_.get()); |
225 | 235 |
226 if (url_request->status().is_success()) { | 236 if (url_request->status().is_success()) { |
227 DidRead(static_cast<uint32_t>(bytes_read), false); | 237 DidRead(static_cast<uint32_t>(bytes_read), false); |
228 } else { | 238 } else { |
229 pending_write_ = NULL; // This closes the data pipe. | 239 handle_watcher_.Stop(); |
| 240 pending_write_ = nullptr; // This closes the data pipe. |
| 241 DeleteIfNeeded(); |
| 242 return; |
230 } | 243 } |
231 } | 244 } |
232 | 245 |
233 void URLLoaderImpl::SendError( | 246 void URLLoaderImpl::SendError( |
234 int error_code, | 247 int error_code, |
235 const Callback<void(URLResponsePtr)>& callback) { | 248 const Callback<void(URLResponsePtr)>& callback) { |
236 URLResponsePtr response(URLResponse::New()); | 249 URLResponsePtr response(URLResponse::New()); |
237 if (url_request_) | 250 if (url_request_) |
238 response->url = String::From(url_request_->url()); | 251 response->url = String::From(url_request_->url()); |
239 response->error = MakeNetworkError(error_code); | 252 response->error = MakeNetworkError(error_code); |
240 callback.Run(response.Pass()); | 253 callback.Run(response.Pass()); |
241 } | 254 } |
242 | 255 |
243 void URLLoaderImpl::SendResponse(URLResponsePtr response) { | 256 void URLLoaderImpl::SendResponse(URLResponsePtr response) { |
244 Callback<void(URLResponsePtr)> callback; | 257 Callback<void(URLResponsePtr)> callback; |
245 std::swap(callback_, callback); | 258 std::swap(callback_, callback); |
246 callback.Run(response.Pass()); | 259 callback.Run(response.Pass()); |
247 } | 260 } |
248 | 261 |
249 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { | 262 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { |
250 // TODO(darin): Handle a bad |result| value. | 263 // TODO(darin): Handle a bad |result| value. |
| 264 |
| 265 // Continue watching the handle in case the peer is closed. |
| 266 ListenForPeerClosed(); |
251 ReadMore(); | 267 ReadMore(); |
252 } | 268 } |
253 | 269 |
| 270 void URLLoaderImpl::OnResponseBodyStreamClosed(MojoResult result) { |
| 271 response_body_stream_.reset(); |
| 272 pending_write_ = nullptr; |
| 273 DeleteIfNeeded(); |
| 274 } |
| 275 |
254 void URLLoaderImpl::ReadMore() { | 276 void URLLoaderImpl::ReadMore() { |
255 DCHECK(!pending_write_.get()); | 277 DCHECK(!pending_write_.get()); |
256 | 278 |
257 uint32_t num_bytes; | 279 uint32_t num_bytes; |
258 MojoResult result = NetToMojoPendingBuffer::BeginWrite( | 280 MojoResult result = NetToMojoPendingBuffer::BeginWrite( |
259 &response_body_stream_, &pending_write_, &num_bytes); | 281 &response_body_stream_, &pending_write_, &num_bytes); |
260 | 282 |
261 if (result == MOJO_RESULT_SHOULD_WAIT) { | 283 if (result == MOJO_RESULT_SHOULD_WAIT) { |
262 // The pipe is full. We need to wait for it to have more space. | 284 // The pipe is full. We need to wait for it to have more space. |
263 handle_watcher_.Start(response_body_stream_.get(), | 285 handle_watcher_.Start(response_body_stream_.get(), |
264 MOJO_HANDLE_SIGNAL_WRITABLE, | 286 MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE, |
265 MOJO_DEADLINE_INDEFINITE, | |
266 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady, | 287 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady, |
267 weak_ptr_factory_.GetWeakPtr())); | 288 base::Unretained(this))); |
268 return; | 289 return; |
269 } else if (result != MOJO_RESULT_OK) { | 290 } else if (result != MOJO_RESULT_OK) { |
270 // The response body stream is in a bad state. Bail. | 291 // The response body stream is in a bad state. Bail. |
271 // TODO(darin): How should this be communicated to our client? | 292 // TODO(darin): How should this be communicated to our client? |
| 293 handle_watcher_.Stop(); |
| 294 response_body_stream_.reset(); |
| 295 DeleteIfNeeded(); |
272 return; | 296 return; |
273 } | 297 } |
274 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes); | 298 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes); |
275 | 299 |
276 scoped_refptr<net::IOBuffer> buf(new NetToMojoIOBuffer(pending_write_.get())); | 300 scoped_refptr<net::IOBuffer> buf(new NetToMojoIOBuffer(pending_write_.get())); |
277 | 301 |
278 int bytes_read; | 302 int bytes_read; |
279 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read); | 303 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read); |
280 if (url_request_->status().is_io_pending()) { | 304 if (url_request_->status().is_io_pending()) { |
281 // Wait for OnReadCompleted. | 305 // Wait for OnReadCompleted. |
282 } else if (url_request_->status().is_success() && bytes_read > 0) { | 306 } else if (url_request_->status().is_success() && bytes_read > 0) { |
283 DidRead(static_cast<uint32_t>(bytes_read), true); | 307 DidRead(static_cast<uint32_t>(bytes_read), true); |
284 } else { | 308 } else { |
| 309 handle_watcher_.Stop(); |
285 pending_write_->Complete(0); | 310 pending_write_->Complete(0); |
286 pending_write_ = NULL; // This closes the data pipe. | 311 pending_write_ = nullptr; // This closes the data pipe. |
| 312 DeleteIfNeeded(); |
| 313 return; |
287 } | 314 } |
288 } | 315 } |
289 | 316 |
290 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) { | 317 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) { |
291 DCHECK(url_request_->status().is_success()); | 318 DCHECK(url_request_->status().is_success()); |
292 | 319 |
293 response_body_stream_ = pending_write_->Complete(num_bytes); | 320 response_body_stream_ = pending_write_->Complete(num_bytes); |
294 pending_write_ = NULL; | 321 pending_write_ = nullptr; |
295 | 322 |
296 if (completed_synchronously) { | 323 if (completed_synchronously) { |
297 base::MessageLoop::current()->PostTask( | 324 base::MessageLoop::current()->PostTask( |
298 FROM_HERE, | 325 FROM_HERE, |
299 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr())); | 326 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr())); |
300 } else { | 327 } else { |
301 ReadMore(); | 328 ReadMore(); |
302 } | 329 } |
303 } | 330 } |
304 | 331 |
| 332 void URLLoaderImpl::DeleteIfNeeded() { |
| 333 bool has_data_pipe = pending_write_.get() || response_body_stream_.is_valid(); |
| 334 if (!connected_ && !has_data_pipe) |
| 335 delete this; |
| 336 } |
| 337 |
| 338 void URLLoaderImpl::ListenForPeerClosed() { |
| 339 handle_watcher_.Start(response_body_stream_.get(), |
| 340 MOJO_HANDLE_SIGNAL_PEER_CLOSED, |
| 341 MOJO_DEADLINE_INDEFINITE, |
| 342 base::Bind(&URLLoaderImpl::OnResponseBodyStreamClosed, |
| 343 base::Unretained(this))); |
| 344 } |
| 345 |
305 } // namespace mojo | 346 } // namespace mojo |
OLD | NEW |