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
3 // found in the LICENSE file.
5 #include "mojo/services/network/url_loader_impl.h"
7 #include "base/memory/scoped_vector.h"
8 #include "base/message_loop/message_loop.h"
9 #include "mojo/common/common_type_converters.h"
10 #include "mojo/services/network/network_context.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/load_flags.h"
13 #include "net/base/upload_bytes_element_reader.h"
14 #include "net/base/upload_data_stream.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/url_request/redirect_info.h"
17 #include "net/url_request/url_request_context.h"
22 const uint32_t kMaxReadSize = 64 * 1024;
24 // Generates an URLResponsePtr from the response state of a net::URLRequest.
25 URLResponsePtr MakeURLResponse(const net::URLRequest* url_request) {
26 URLResponsePtr response(URLResponse::New());
27 response->url = String::From(url_request->url());
29 const net::HttpResponseHeaders* headers = url_request->response_headers();
31 response->status_code = headers->response_code();
32 response->status_line = headers->GetStatusLine();
34 std::vector<String> header_lines;
36 std::string name, value;
37 while (headers->EnumerateHeaderLines(&iter, &name, &value))
38 header_lines.push_back(name + ": " + value);
39 if (!header_lines.empty())
40 response->headers.Swap(&header_lines);
43 std::string mime_type;
44 url_request->GetMimeType(&mime_type);
45 response->mime_type = mime_type;
48 url_request->GetCharset(&charset);
49 response->charset = charset;
51 return response.Pass();
54 NetworkErrorPtr MakeNetworkError(int error_code) {
55 NetworkErrorPtr error = NetworkError::New();
56 error->code = error_code;
57 error->description = net::ErrorToString(error_code);
61 // Reads the request body upload data from a DataPipe.
62 class UploadDataPipeElementReader : public net::UploadElementReader {
64 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe)
65 : pipe_(pipe.Pass()), num_bytes_(0) {}
66 virtual ~UploadDataPipeElementReader() {}
68 // UploadElementReader overrides:
69 virtual int Init(const net::CompletionCallback& callback) OVERRIDE {
71 ReadDataRaw(pipe_.get(), NULL, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY);
74 virtual uint64 GetContentLength() const OVERRIDE {
77 virtual uint64 BytesRemaining() const OVERRIDE {
78 return num_bytes_ - offset_;
80 virtual bool IsInMemory() const OVERRIDE {
83 virtual int Read(net::IOBuffer* buf,
85 const net::CompletionCallback& callback) OVERRIDE {
87 std::min(static_cast<uint32_t>(BytesRemaining()),
88 static_cast<uint32_t>(buf_length));
90 ReadDataRaw(pipe_.get(), buf->data(), &bytes_read,
91 MOJO_READ_DATA_FLAG_NONE);
94 offset_ += bytes_read;
99 ScopedDataPipeConsumerHandle pipe_;
103 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader);
108 // Keeps track of a pending two-phase write on a DataPipeProducerHandle.
109 class URLLoaderImpl::PendingWriteToDataPipe :
110 public base::RefCountedThreadSafe<PendingWriteToDataPipe> {
112 explicit PendingWriteToDataPipe(ScopedDataPipeProducerHandle handle)
113 : handle_(handle.Pass()),
117 MojoResult BeginWrite(uint32_t* num_bytes) {
118 MojoResult result = BeginWriteDataRaw(handle_.get(), &buffer_, num_bytes,
119 MOJO_WRITE_DATA_FLAG_NONE);
120 if (*num_bytes > kMaxReadSize)
121 *num_bytes = kMaxReadSize;
126 ScopedDataPipeProducerHandle Complete(uint32_t num_bytes) {
127 EndWriteDataRaw(handle_.get(), num_bytes);
129 return handle_.Pass();
132 char* buffer() { return static_cast<char*>(buffer_); }
135 friend class base::RefCountedThreadSafe<PendingWriteToDataPipe>;
137 ~PendingWriteToDataPipe() {
138 if (handle_.is_valid())
139 EndWriteDataRaw(handle_.get(), 0);
142 ScopedDataPipeProducerHandle handle_;
145 DISALLOW_COPY_AND_ASSIGN(PendingWriteToDataPipe);
148 // Takes ownership of a pending two-phase write on a DataPipeProducerHandle,
149 // and makes its buffer available as a net::IOBuffer.
150 class URLLoaderImpl::DependentIOBuffer : public net::WrappedIOBuffer {
152 DependentIOBuffer(PendingWriteToDataPipe* pending_write)
153 : net::WrappedIOBuffer(pending_write->buffer()),
154 pending_write_(pending_write) {
157 virtual ~DependentIOBuffer() {}
158 scoped_refptr<PendingWriteToDataPipe> pending_write_;
161 URLLoaderImpl::URLLoaderImpl(NetworkContext* context)
163 response_body_buffer_size_(0),
164 auto_follow_redirects_(true),
165 weak_ptr_factory_(this) {
168 URLLoaderImpl::~URLLoaderImpl() {
171 void URLLoaderImpl::Start(URLRequestPtr request,
172 const Callback<void(URLResponsePtr)>& callback) {
174 SendError(net::ERR_UNEXPECTED, callback);
179 SendError(net::ERR_INVALID_ARGUMENT, callback);
183 url_request_ = context_->url_request_context()->CreateRequest(
185 net::DEFAULT_PRIORITY,
188 url_request_->set_method(request->method);
189 if (request->headers) {
190 net::HttpRequestHeaders headers;
191 for (size_t i = 0; i < request->headers.size(); ++i)
192 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>());
193 url_request_->SetExtraRequestHeaders(headers);
196 ScopedVector<net::UploadElementReader> element_readers;
197 for (size_t i = 0; i < request->body.size(); ++i) {
198 element_readers.push_back(
199 new UploadDataPipeElementReader(request->body[i].Pass()));
201 url_request_->set_upload(make_scoped_ptr(
202 new net::UploadDataStream(element_readers.Pass(), 0)));
204 if (request->bypass_cache)
205 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE);
207 callback_ = callback;
208 response_body_buffer_size_ = request->response_body_buffer_size;
209 auto_follow_redirects_ = request->auto_follow_redirects;
211 url_request_->Start();
214 void URLLoaderImpl::FollowRedirect(
215 const Callback<void(URLResponsePtr)>& callback) {
217 SendError(net::ERR_UNEXPECTED, callback);
221 if (auto_follow_redirects_) {
222 DLOG(ERROR) << "Spurious call to FollowRedirect";
223 SendError(net::ERR_UNEXPECTED, callback);
227 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
228 url_request_->FollowDeferredRedirect();
231 void URLLoaderImpl::QueryStatus(
232 const Callback<void(URLLoaderStatusPtr)>& callback) {
233 URLLoaderStatusPtr status(URLLoaderStatus::New());
235 status->is_loading = url_request_->is_pending();
236 if (!url_request_->status().is_success())
237 status->error = MakeNetworkError(url_request_->status().error());
239 status->is_loading = false;
241 // TODO(darin): Populate more status fields.
242 callback.Run(status.Pass());
245 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request,
246 const net::RedirectInfo& redirect_info,
247 bool* defer_redirect) {
248 DCHECK(url_request == url_request_.get());
249 DCHECK(url_request->status().is_success());
251 if (auto_follow_redirects_)
254 // Send the redirect response to the client, allowing them to inspect it and
255 // optionally follow the redirect.
256 *defer_redirect = true;
258 URLResponsePtr response = MakeURLResponse(url_request);
259 response->redirect_method = redirect_info.new_method;
260 response->redirect_url = String::From(redirect_info.new_url);
262 SendResponse(response.Pass());
265 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) {
266 DCHECK(url_request == url_request_.get());
268 if (!url_request->status().is_success()) {
269 SendError(url_request->status().error(), callback_);
270 callback_ = Callback<void(URLResponsePtr)>();
274 // TODO(darin): Add support for optional MIME sniffing.
277 // TODO(darin): Honor given buffer size.
279 URLResponsePtr response = MakeURLResponse(url_request);
280 response->body = data_pipe.consumer_handle.Pass();
281 response_body_stream_ = data_pipe.producer_handle.Pass();
283 SendResponse(response.Pass());
289 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request,
291 DCHECK(url_request == url_request_.get());
293 if (url_request->status().is_success()) {
294 DidRead(static_cast<uint32_t>(bytes_read), false);
296 pending_write_ = NULL; // This closes the data pipe.
300 void URLLoaderImpl::SendError(
302 const Callback<void(URLResponsePtr)>& callback) {
303 URLResponsePtr response(URLResponse::New());
305 response->url = String::From(url_request_->url());
306 response->error = MakeNetworkError(error_code);
307 callback.Run(response.Pass());
310 void URLLoaderImpl::SendResponse(URLResponsePtr response) {
311 Callback<void(URLResponsePtr)> callback;
312 std::swap(callback_, callback);
313 callback.Run(response.Pass());
316 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) {
317 // TODO(darin): Handle a bad |result| value.
321 void URLLoaderImpl::WaitToReadMore() {
322 handle_watcher_.Start(response_body_stream_.get(),
323 MOJO_HANDLE_SIGNAL_WRITABLE,
324 MOJO_DEADLINE_INDEFINITE,
325 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady,
326 weak_ptr_factory_.GetWeakPtr()));
329 void URLLoaderImpl::ReadMore() {
330 DCHECK(!pending_write_.get());
332 pending_write_ = new PendingWriteToDataPipe(response_body_stream_.Pass());
335 MojoResult result = pending_write_->BeginWrite(&num_bytes);
336 if (result == MOJO_RESULT_SHOULD_WAIT) {
337 // The pipe is full. We need to wait for it to have more space.
338 response_body_stream_ = pending_write_->Complete(num_bytes);
339 pending_write_ = NULL;
343 if (result != MOJO_RESULT_OK) {
344 // The response body stream is in a bad state. Bail.
345 // TODO(darin): How should this be communicated to our client?
348 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes);
350 scoped_refptr<net::IOBuffer> buf =
351 new DependentIOBuffer(pending_write_.get());
354 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read);
356 // Drop our reference to the buffer.
359 if (url_request_->status().is_io_pending()) {
360 // Wait for OnReadCompleted.
361 } else if (url_request_->status().is_success() && bytes_read > 0) {
362 DidRead(static_cast<uint32_t>(bytes_read), true);
364 pending_write_->Complete(0);
365 pending_write_ = NULL; // This closes the data pipe.
369 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) {
370 DCHECK(url_request_->status().is_success());
372 response_body_stream_ = pending_write_->Complete(num_bytes);
373 pending_write_ = NULL;
375 if (completed_synchronously) {
376 base::MessageLoop::current()->PostTask(
378 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr()));