Include Mojo SDK/EDK via fully-qualified paths in Chromium code.
[chromium-blink-merge.git] / mojo / services / network / url_loader_impl.cc
blobccaf4e51c7a156def0bdaf8fcf829801303d55d1
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/net_adapters.h"
11 #include "mojo/services/network/network_context.h"
12 #include "net/base/elements_upload_data_stream.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/load_flags.h"
15 #include "net/base/upload_bytes_element_reader.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/redirect_info.h"
18 #include "net/url_request/url_request_context.h"
20 namespace mojo {
21 namespace {
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());
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();
33 std::vector<String> header_lines;
34 void* iter = nullptr;
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);
42 std::string mime_type;
43 url_request->GetMimeType(&mime_type);
44 response->mime_type = mime_type;
46 std::string charset;
47 url_request->GetCharset(&charset);
48 response->charset = charset;
50 return response.Pass();
53 // Reads the request body upload data from a DataPipe.
54 class UploadDataPipeElementReader : public net::UploadElementReader {
55 public:
56 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe)
57 : pipe_(pipe.Pass()), num_bytes_(0) {}
58 ~UploadDataPipeElementReader() override {}
60 // UploadElementReader overrides:
61 int Init(const net::CompletionCallback& callback) override {
62 offset_ = 0;
63 ReadDataRaw(pipe_.get(), nullptr, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY);
64 return net::OK;
66 uint64 GetContentLength() const override { return num_bytes_; }
67 uint64 BytesRemaining() const override { return num_bytes_ - offset_; }
68 bool IsInMemory() const override { return false; }
69 int Read(net::IOBuffer* buf,
70 int buf_length,
71 const net::CompletionCallback& callback) override {
72 uint32_t bytes_read =
73 std::min(static_cast<uint32_t>(BytesRemaining()),
74 static_cast<uint32_t>(buf_length));
75 if (bytes_read > 0) {
76 ReadDataRaw(pipe_.get(), buf->data(), &bytes_read,
77 MOJO_READ_DATA_FLAG_NONE);
80 offset_ += bytes_read;
81 return bytes_read;
84 private:
85 ScopedDataPipeConsumerHandle pipe_;
86 uint32_t num_bytes_;
87 uint32_t offset_;
89 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader);
92 } // namespace
94 URLLoaderImpl::URLLoaderImpl(NetworkContext* context,
95 InterfaceRequest<URLLoader> request)
96 : context_(context),
97 response_body_buffer_size_(0),
98 auto_follow_redirects_(true),
99 connected_(true),
100 binding_(this, request.Pass()),
101 weak_ptr_factory_(this) {
102 binding_.set_error_handler(this);
105 URLLoaderImpl::~URLLoaderImpl() {
108 void URLLoaderImpl::Start(URLRequestPtr request,
109 const Callback<void(URLResponsePtr)>& callback) {
110 if (url_request_) {
111 SendError(net::ERR_UNEXPECTED, callback);
112 return;
115 if (!request) {
116 SendError(net::ERR_INVALID_ARGUMENT, callback);
117 return;
120 url_request_ = context_->url_request_context()->CreateRequest(
121 GURL(request->url), net::DEFAULT_PRIORITY, this, nullptr);
122 url_request_->set_method(request->method);
123 if (request->headers) {
124 net::HttpRequestHeaders headers;
125 for (size_t i = 0; i < request->headers.size(); ++i)
126 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>());
127 url_request_->SetExtraRequestHeaders(headers);
129 if (request->body) {
130 ScopedVector<net::UploadElementReader> element_readers;
131 for (size_t i = 0; i < request->body.size(); ++i) {
132 element_readers.push_back(
133 new UploadDataPipeElementReader(request->body[i].Pass()));
135 url_request_->set_upload(make_scoped_ptr<net::UploadDataStream>(
136 new net::ElementsUploadDataStream(element_readers.Pass(), 0)));
138 if (request->bypass_cache)
139 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE);
141 callback_ = callback;
142 response_body_buffer_size_ = request->response_body_buffer_size;
143 auto_follow_redirects_ = request->auto_follow_redirects;
145 url_request_->Start();
148 void URLLoaderImpl::FollowRedirect(
149 const Callback<void(URLResponsePtr)>& callback) {
150 if (!url_request_) {
151 SendError(net::ERR_UNEXPECTED, callback);
152 return;
155 if (auto_follow_redirects_) {
156 DLOG(ERROR) << "Spurious call to FollowRedirect";
157 SendError(net::ERR_UNEXPECTED, callback);
158 return;
161 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
162 url_request_->FollowDeferredRedirect();
165 void URLLoaderImpl::QueryStatus(
166 const Callback<void(URLLoaderStatusPtr)>& callback) {
167 URLLoaderStatusPtr status(URLLoaderStatus::New());
168 if (url_request_) {
169 status->is_loading = url_request_->is_pending();
170 if (!url_request_->status().is_success())
171 status->error = MakeNetworkError(url_request_->status().error());
172 } else {
173 status->is_loading = false;
175 // TODO(darin): Populate more status fields.
176 callback.Run(status.Pass());
179 void URLLoaderImpl::OnConnectionError() {
180 connected_ = false;
181 DeleteIfNeeded();
184 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request,
185 const net::RedirectInfo& redirect_info,
186 bool* defer_redirect) {
187 DCHECK(url_request == url_request_.get());
188 DCHECK(url_request->status().is_success());
190 if (auto_follow_redirects_)
191 return;
193 // Send the redirect response to the client, allowing them to inspect it and
194 // optionally follow the redirect.
195 *defer_redirect = true;
197 URLResponsePtr response = MakeURLResponse(url_request);
198 response->redirect_method = redirect_info.new_method;
199 response->redirect_url = String::From(redirect_info.new_url);
201 SendResponse(response.Pass());
203 DeleteIfNeeded();
206 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) {
207 DCHECK(url_request == url_request_.get());
209 if (!url_request->status().is_success()) {
210 SendError(url_request->status().error(), callback_);
211 callback_ = Callback<void(URLResponsePtr)>();
212 DeleteIfNeeded();
213 return;
216 // TODO(darin): Add support for optional MIME sniffing.
218 DataPipe data_pipe;
219 // TODO(darin): Honor given buffer size.
221 URLResponsePtr response = MakeURLResponse(url_request);
222 response->body = data_pipe.consumer_handle.Pass();
223 response_body_stream_ = data_pipe.producer_handle.Pass();
224 ListenForPeerClosed();
226 SendResponse(response.Pass());
228 // Start reading...
229 ReadMore();
232 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request,
233 int bytes_read) {
234 DCHECK(url_request == url_request_.get());
236 if (url_request->status().is_success()) {
237 DidRead(static_cast<uint32_t>(bytes_read), false);
238 } else {
239 handle_watcher_.Stop();
240 pending_write_ = nullptr; // This closes the data pipe.
241 DeleteIfNeeded();
242 return;
246 void URLLoaderImpl::SendError(
247 int error_code,
248 const Callback<void(URLResponsePtr)>& callback) {
249 URLResponsePtr response(URLResponse::New());
250 if (url_request_)
251 response->url = String::From(url_request_->url());
252 response->error = MakeNetworkError(error_code);
253 callback.Run(response.Pass());
256 void URLLoaderImpl::SendResponse(URLResponsePtr response) {
257 Callback<void(URLResponsePtr)> callback;
258 std::swap(callback_, callback);
259 callback.Run(response.Pass());
262 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) {
263 // TODO(darin): Handle a bad |result| value.
265 // Continue watching the handle in case the peer is closed.
266 ListenForPeerClosed();
267 ReadMore();
270 void URLLoaderImpl::OnResponseBodyStreamClosed(MojoResult result) {
271 response_body_stream_.reset();
272 pending_write_ = nullptr;
273 DeleteIfNeeded();
276 void URLLoaderImpl::ReadMore() {
277 DCHECK(!pending_write_.get());
279 uint32_t num_bytes;
280 MojoResult result = NetToMojoPendingBuffer::BeginWrite(
281 &response_body_stream_, &pending_write_, &num_bytes);
283 if (result == MOJO_RESULT_SHOULD_WAIT) {
284 // The pipe is full. We need to wait for it to have more space.
285 handle_watcher_.Start(response_body_stream_.get(),
286 MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE,
287 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady,
288 base::Unretained(this)));
289 return;
290 } else if (result != MOJO_RESULT_OK) {
291 // The response body stream is in a bad state. Bail.
292 // TODO(darin): How should this be communicated to our client?
293 handle_watcher_.Stop();
294 response_body_stream_.reset();
295 DeleteIfNeeded();
296 return;
298 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes);
300 scoped_refptr<net::IOBuffer> buf(new NetToMojoIOBuffer(pending_write_.get()));
302 int bytes_read;
303 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read);
304 if (url_request_->status().is_io_pending()) {
305 // Wait for OnReadCompleted.
306 } else if (url_request_->status().is_success() && bytes_read > 0) {
307 DidRead(static_cast<uint32_t>(bytes_read), true);
308 } else {
309 handle_watcher_.Stop();
310 pending_write_->Complete(0);
311 pending_write_ = nullptr; // This closes the data pipe.
312 DeleteIfNeeded();
313 return;
317 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) {
318 DCHECK(url_request_->status().is_success());
320 response_body_stream_ = pending_write_->Complete(num_bytes);
321 pending_write_ = nullptr;
323 if (completed_synchronously) {
324 base::MessageLoop::current()->PostTask(
325 FROM_HERE,
326 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr()));
327 } else {
328 ReadMore();
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;
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)));
346 } // namespace mojo