| 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 |