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