Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / mojo / services / network / url_loader_impl.cc
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.
4
5 #include "mojo/services/network/url_loader_impl.h"
6
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"
18
19 namespace mojo {
20 namespace {
21
22 const uint32_t kMaxReadSize = 64 * 1024;
23
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());
28
29   const net::HttpResponseHeaders* headers = url_request->response_headers();
30   if (headers) {
31     response->status_code = headers->response_code();
32     response->status_line = headers->GetStatusLine();
33
34     std::vector<String> header_lines;
35     void* iter = NULL;
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);
41   }
42
43   std::string mime_type;
44   url_request->GetMimeType(&mime_type);
45   response->mime_type = mime_type;
46
47   std::string charset;
48   url_request->GetCharset(&charset);
49   response->charset = charset;
50
51   return response.Pass();
52 }
53
54 NetworkErrorPtr MakeNetworkError(int error_code) {
55   NetworkErrorPtr error = NetworkError::New();
56   error->code = error_code;
57   error->description = net::ErrorToString(error_code);
58   return error.Pass();
59 }
60
61 // Reads the request body upload data from a DataPipe.
62 class UploadDataPipeElementReader : public net::UploadElementReader {
63  public:
64   UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe)
65       : pipe_(pipe.Pass()), num_bytes_(0) {}
66   virtual ~UploadDataPipeElementReader() {}
67
68   // UploadElementReader overrides:
69   virtual int Init(const net::CompletionCallback& callback) OVERRIDE {
70     offset_ = 0;
71     ReadDataRaw(pipe_.get(), NULL, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY);
72     return net::OK;
73   }
74   virtual uint64 GetContentLength() const OVERRIDE {
75     return num_bytes_;
76   }
77   virtual uint64 BytesRemaining() const OVERRIDE {
78     return num_bytes_ - offset_;
79   }
80   virtual bool IsInMemory() const OVERRIDE {
81     return false;
82   }
83   virtual int Read(net::IOBuffer* buf,
84                    int buf_length,
85                    const net::CompletionCallback& callback) OVERRIDE {
86     uint32_t bytes_read =
87         std::min(static_cast<uint32_t>(BytesRemaining()),
88                  static_cast<uint32_t>(buf_length));
89     if (bytes_read > 0) {
90       ReadDataRaw(pipe_.get(), buf->data(), &bytes_read,
91                   MOJO_READ_DATA_FLAG_NONE);
92     }
93
94     offset_ += bytes_read;
95     return bytes_read;
96   }
97
98  private:
99   ScopedDataPipeConsumerHandle pipe_;
100   uint32_t num_bytes_;
101   uint32_t offset_;
102
103   DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader);
104 };
105
106 }  // namespace
107
108 // Keeps track of a pending two-phase write on a DataPipeProducerHandle.
109 class URLLoaderImpl::PendingWriteToDataPipe :
110     public base::RefCountedThreadSafe<PendingWriteToDataPipe> {
111  public:
112   explicit PendingWriteToDataPipe(ScopedDataPipeProducerHandle handle)
113       : handle_(handle.Pass()),
114         buffer_(NULL) {
115   }
116
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;
122
123     return result;
124   }
125
126   ScopedDataPipeProducerHandle Complete(uint32_t num_bytes) {
127     EndWriteDataRaw(handle_.get(), num_bytes);
128     buffer_ = NULL;
129     return handle_.Pass();
130   }
131
132   char* buffer() { return static_cast<char*>(buffer_); }
133
134  private:
135   friend class base::RefCountedThreadSafe<PendingWriteToDataPipe>;
136
137   ~PendingWriteToDataPipe() {
138     if (handle_.is_valid())
139       EndWriteDataRaw(handle_.get(), 0);
140   }
141
142   ScopedDataPipeProducerHandle handle_;
143   void* buffer_;
144
145   DISALLOW_COPY_AND_ASSIGN(PendingWriteToDataPipe);
146 };
147
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 {
151  public:
152   DependentIOBuffer(PendingWriteToDataPipe* pending_write)
153       : net::WrappedIOBuffer(pending_write->buffer()),
154         pending_write_(pending_write) {
155   }
156  private:
157   virtual ~DependentIOBuffer() {}
158   scoped_refptr<PendingWriteToDataPipe> pending_write_;
159 };
160
161 URLLoaderImpl::URLLoaderImpl(NetworkContext* context)
162     : context_(context),
163       response_body_buffer_size_(0),
164       auto_follow_redirects_(true),
165       weak_ptr_factory_(this) {
166 }
167
168 URLLoaderImpl::~URLLoaderImpl() {
169 }
170
171 void URLLoaderImpl::Start(URLRequestPtr request,
172                           const Callback<void(URLResponsePtr)>& callback) {
173   if (url_request_) {
174     SendError(net::ERR_UNEXPECTED, callback);
175     return;
176   }
177
178   if (!request) {
179     SendError(net::ERR_INVALID_ARGUMENT, callback);
180     return;
181   }
182
183   url_request_ = context_->url_request_context()->CreateRequest(
184       GURL(request->url),
185       net::DEFAULT_PRIORITY,
186       this,
187       NULL);
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);
194   }
195   if (request->body) {
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()));
200     }
201     url_request_->set_upload(make_scoped_ptr(
202         new net::UploadDataStream(element_readers.Pass(), 0)));
203   }
204   if (request->bypass_cache)
205     url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE);
206
207   callback_ = callback;
208   response_body_buffer_size_ = request->response_body_buffer_size;
209   auto_follow_redirects_ = request->auto_follow_redirects;
210
211   url_request_->Start();
212 }
213
214 void URLLoaderImpl::FollowRedirect(
215     const Callback<void(URLResponsePtr)>& callback) {
216   if (!url_request_) {
217     SendError(net::ERR_UNEXPECTED, callback);
218     return;
219   }
220
221   if (auto_follow_redirects_) {
222     DLOG(ERROR) << "Spurious call to FollowRedirect";
223     SendError(net::ERR_UNEXPECTED, callback);
224     return;
225   }
226
227   // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
228   url_request_->FollowDeferredRedirect();
229 }
230
231 void URLLoaderImpl::QueryStatus(
232     const Callback<void(URLLoaderStatusPtr)>& callback) {
233   URLLoaderStatusPtr status(URLLoaderStatus::New());
234   if (url_request_) {
235     status->is_loading = url_request_->is_pending();
236     if (!url_request_->status().is_success())
237       status->error = MakeNetworkError(url_request_->status().error());
238   } else {
239     status->is_loading = false;
240   }
241   // TODO(darin): Populate more status fields.
242   callback.Run(status.Pass());
243 }
244
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());
250
251   if (auto_follow_redirects_)
252     return;
253
254   // Send the redirect response to the client, allowing them to inspect it and
255   // optionally follow the redirect.
256   *defer_redirect = true;
257
258   URLResponsePtr response = MakeURLResponse(url_request);
259   response->redirect_method = redirect_info.new_method;
260   response->redirect_url = String::From(redirect_info.new_url);
261
262   SendResponse(response.Pass());
263 }
264
265 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) {
266   DCHECK(url_request == url_request_.get());
267
268   if (!url_request->status().is_success()) {
269     SendError(url_request->status().error(), callback_);
270     callback_ = Callback<void(URLResponsePtr)>();
271     return;
272   }
273
274   // TODO(darin): Add support for optional MIME sniffing.
275
276   DataPipe data_pipe;
277   // TODO(darin): Honor given buffer size.
278
279   URLResponsePtr response = MakeURLResponse(url_request);
280   response->body = data_pipe.consumer_handle.Pass();
281   response_body_stream_ = data_pipe.producer_handle.Pass();
282
283   SendResponse(response.Pass());
284
285   // Start reading...
286   ReadMore();
287 }
288
289 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request,
290                                     int bytes_read) {
291   DCHECK(url_request == url_request_.get());
292
293   if (url_request->status().is_success()) {
294     DidRead(static_cast<uint32_t>(bytes_read), false);
295   } else {
296     pending_write_ = NULL;  // This closes the data pipe.
297   }
298 }
299
300 void URLLoaderImpl::SendError(
301     int error_code,
302     const Callback<void(URLResponsePtr)>& callback) {
303   URLResponsePtr response(URLResponse::New());
304   if (url_request_)
305     response->url = String::From(url_request_->url());
306   response->error = MakeNetworkError(error_code);
307   callback.Run(response.Pass());
308 }
309
310 void URLLoaderImpl::SendResponse(URLResponsePtr response) {
311   Callback<void(URLResponsePtr)> callback;
312   std::swap(callback_, callback);
313   callback.Run(response.Pass());
314 }
315
316 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) {
317   // TODO(darin): Handle a bad |result| value.
318   ReadMore();
319 }
320
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()));
327 }
328
329 void URLLoaderImpl::ReadMore() {
330   DCHECK(!pending_write_.get());
331
332   pending_write_ = new PendingWriteToDataPipe(response_body_stream_.Pass());
333
334   uint32_t num_bytes;
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;
340     WaitToReadMore();
341     return;
342   }
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?
346     return;
347   }
348   CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes);
349
350   scoped_refptr<net::IOBuffer> buf =
351       new DependentIOBuffer(pending_write_.get());
352
353   int bytes_read;
354   url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read);
355
356   // Drop our reference to the buffer.
357   buf = NULL;
358
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);
363   } else {
364     pending_write_->Complete(0);
365     pending_write_ = NULL;  // This closes the data pipe.
366   }
367 }
368
369 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) {
370   DCHECK(url_request_->status().is_success());
371
372   response_body_stream_ = pending_write_->Complete(num_bytes);
373   pending_write_ = NULL;
374
375   if (completed_synchronously) {
376     base::MessageLoop::current()->PostTask(
377         FROM_HERE,
378         base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr()));
379   } else {
380     ReadMore();
381   }
382 }
383
384 }  // namespace mojo