Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / mojo / services / network / url_loader_impl.cc
blob467cc3fa30e562c427ef525dfba9fdc4555f8741
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/common/url_type_converters.h"
11 #include "mojo/services/network/net_adapters.h"
12 #include "mojo/services/network/network_context.h"
13 #include "net/base/elements_upload_data_stream.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/load_flags.h"
16 #include "net/base/upload_bytes_element_reader.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/url_request/redirect_info.h"
19 #include "net/url_request/url_request_context.h"
21 namespace mojo {
22 namespace {
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();
30 if (headers) {
31 response->status_code = headers->response_code();
32 response->status_line = headers->GetStatusLine();
34 std::vector<String> header_lines;
35 void* iter = nullptr;
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;
47 std::string charset;
48 url_request->GetCharset(&charset);
49 response->charset = charset;
51 return response.Pass();
54 // Reads the request body upload data from a DataPipe.
55 class UploadDataPipeElementReader : public net::UploadElementReader {
56 public:
57 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe)
58 : pipe_(pipe.Pass()), num_bytes_(0) {}
59 ~UploadDataPipeElementReader() override {}
61 // UploadElementReader overrides:
62 int Init(const net::CompletionCallback& callback) override {
63 offset_ = 0;
64 ReadDataRaw(pipe_.get(), nullptr, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY);
65 return net::OK;
67 uint64 GetContentLength() const override { return num_bytes_; }
68 uint64 BytesRemaining() const override { return num_bytes_ - offset_; }
69 bool IsInMemory() const override { return false; }
70 int Read(net::IOBuffer* buf,
71 int buf_length,
72 const net::CompletionCallback& callback) override {
73 uint32_t bytes_read =
74 std::min(static_cast<uint32_t>(BytesRemaining()),
75 static_cast<uint32_t>(buf_length));
76 if (bytes_read > 0) {
77 ReadDataRaw(pipe_.get(), buf->data(), &bytes_read,
78 MOJO_READ_DATA_FLAG_NONE);
81 offset_ += bytes_read;
82 return bytes_read;
85 private:
86 ScopedDataPipeConsumerHandle pipe_;
87 uint32_t num_bytes_;
88 uint32_t offset_;
90 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader);
93 } // namespace
95 URLLoaderImpl::URLLoaderImpl(NetworkContext* context,
96 InterfaceRequest<URLLoader> request)
97 : context_(context),
98 response_body_buffer_size_(0),
99 auto_follow_redirects_(true),
100 connected_(true),
101 binding_(this, request.Pass()),
102 weak_ptr_factory_(this) {
103 binding_.set_error_handler(this);
104 context_->RegisterURLLoader(this);
107 URLLoaderImpl::~URLLoaderImpl() {
108 context_->DeregisterURLLoader(this);
111 void URLLoaderImpl::Cleanup() {
112 // The associated network context is going away and we have to destroy
113 // net::URLRequest hold by this loader.
114 delete this;
117 void URLLoaderImpl::Start(URLRequestPtr request,
118 const Callback<void(URLResponsePtr)>& callback) {
119 if (url_request_) {
120 SendError(net::ERR_UNEXPECTED, callback);
121 return;
124 if (!request) {
125 SendError(net::ERR_INVALID_ARGUMENT, callback);
126 return;
129 url_request_ = context_->url_request_context()->CreateRequest(
130 GURL(request->url), net::DEFAULT_PRIORITY, this);
131 url_request_->set_method(request->method);
132 url_request_->SetReferrer(request->referrer);
133 // TODO(jam): need to specify this policy.
134 url_request_->set_referrer_policy(
135 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE);
136 if (request->headers) {
137 net::HttpRequestHeaders headers;
138 for (size_t i = 0; i < request->headers.size(); ++i)
139 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>());
140 url_request_->SetExtraRequestHeaders(headers);
142 if (request->body) {
143 ScopedVector<net::UploadElementReader> element_readers;
144 for (size_t i = 0; i < request->body.size(); ++i) {
145 element_readers.push_back(
146 new UploadDataPipeElementReader(request->body[i].Pass()));
148 url_request_->set_upload(make_scoped_ptr<net::UploadDataStream>(
149 new net::ElementsUploadDataStream(element_readers.Pass(), 0)));
151 if (request->bypass_cache)
152 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE);
154 callback_ = callback;
155 response_body_buffer_size_ = request->response_body_buffer_size;
156 auto_follow_redirects_ = request->auto_follow_redirects;
158 url_request_->Start();
161 void URLLoaderImpl::FollowRedirect(
162 const Callback<void(URLResponsePtr)>& callback) {
163 if (!url_request_) {
164 SendError(net::ERR_UNEXPECTED, callback);
165 return;
168 if (auto_follow_redirects_) {
169 DLOG(ERROR) << "Spurious call to FollowRedirect";
170 SendError(net::ERR_UNEXPECTED, callback);
171 return;
174 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
175 url_request_->FollowDeferredRedirect();
176 callback_ = callback;
179 void URLLoaderImpl::QueryStatus(
180 const Callback<void(URLLoaderStatusPtr)>& callback) {
181 URLLoaderStatusPtr status(URLLoaderStatus::New());
182 if (url_request_) {
183 status->is_loading = url_request_->is_pending();
184 if (!url_request_->status().is_success())
185 status->error = MakeNetworkError(url_request_->status().error());
186 } else {
187 status->is_loading = false;
189 // TODO(darin): Populate more status fields.
190 callback.Run(status.Pass());
193 void URLLoaderImpl::OnConnectionError() {
194 connected_ = false;
195 DeleteIfNeeded();
198 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request,
199 const net::RedirectInfo& redirect_info,
200 bool* defer_redirect) {
201 DCHECK(url_request == url_request_.get());
202 DCHECK(url_request->status().is_success());
204 if (auto_follow_redirects_)
205 return;
207 // Send the redirect response to the client, allowing them to inspect it and
208 // optionally follow the redirect.
209 *defer_redirect = true;
211 URLResponsePtr response = MakeURLResponse(url_request);
212 response->redirect_method = redirect_info.new_method;
213 response->redirect_url = String::From(redirect_info.new_url);
214 response->redirect_referrer = redirect_info.new_referrer;
216 SendResponse(response.Pass());
218 DeleteIfNeeded();
221 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) {
222 DCHECK(url_request == url_request_.get());
224 if (!url_request->status().is_success()) {
225 SendError(url_request->status().error(), callback_);
226 callback_ = Callback<void(URLResponsePtr)>();
227 DeleteIfNeeded();
228 return;
231 // TODO(darin): Add support for optional MIME sniffing.
233 DataPipe data_pipe;
234 // TODO(darin): Honor given buffer size.
236 URLResponsePtr response = MakeURLResponse(url_request);
237 response->body = data_pipe.consumer_handle.Pass();
238 response_body_stream_ = data_pipe.producer_handle.Pass();
239 ListenForPeerClosed();
241 SendResponse(response.Pass());
243 // Start reading...
244 ReadMore();
247 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request,
248 int bytes_read) {
249 DCHECK(url_request == url_request_.get());
251 if (url_request->status().is_success()) {
252 DidRead(static_cast<uint32_t>(bytes_read), false);
253 } else {
254 handle_watcher_.Stop();
255 pending_write_ = nullptr; // This closes the data pipe.
256 DeleteIfNeeded();
257 return;
261 void URLLoaderImpl::SendError(
262 int error_code,
263 const Callback<void(URLResponsePtr)>& callback) {
264 URLResponsePtr response(URLResponse::New());
265 if (url_request_)
266 response->url = String::From(url_request_->url());
267 response->error = MakeNetworkError(error_code);
268 callback.Run(response.Pass());
271 void URLLoaderImpl::SendResponse(URLResponsePtr response) {
272 Callback<void(URLResponsePtr)> callback;
273 std::swap(callback_, callback);
274 callback.Run(response.Pass());
277 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) {
278 // TODO(darin): Handle a bad |result| value.
280 // Continue watching the handle in case the peer is closed.
281 ListenForPeerClosed();
282 ReadMore();
285 void URLLoaderImpl::OnResponseBodyStreamClosed(MojoResult result) {
286 url_request_.reset();
287 response_body_stream_.reset();
288 pending_write_ = nullptr;
289 DeleteIfNeeded();
292 void URLLoaderImpl::ReadMore() {
293 DCHECK(!pending_write_.get());
295 uint32_t num_bytes;
296 MojoResult result = NetToMojoPendingBuffer::BeginWrite(
297 &response_body_stream_, &pending_write_, &num_bytes);
299 if (result == MOJO_RESULT_SHOULD_WAIT) {
300 // The pipe is full. We need to wait for it to have more space.
301 handle_watcher_.Start(response_body_stream_.get(),
302 MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE,
303 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady,
304 base::Unretained(this)));
305 return;
306 } else if (result != MOJO_RESULT_OK) {
307 // The response body stream is in a bad state. Bail.
308 // TODO(darin): How should this be communicated to our client?
309 handle_watcher_.Stop();
310 response_body_stream_.reset();
311 DeleteIfNeeded();
312 return;
314 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes);
316 scoped_refptr<net::IOBuffer> buf(new NetToMojoIOBuffer(pending_write_.get()));
318 int bytes_read;
319 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read);
320 if (url_request_->status().is_io_pending()) {
321 // Wait for OnReadCompleted.
322 } else if (url_request_->status().is_success() && bytes_read > 0) {
323 DidRead(static_cast<uint32_t>(bytes_read), true);
324 } else {
325 handle_watcher_.Stop();
326 pending_write_->Complete(0);
327 pending_write_ = nullptr; // This closes the data pipe.
328 DeleteIfNeeded();
329 return;
333 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) {
334 DCHECK(url_request_->status().is_success());
336 response_body_stream_ = pending_write_->Complete(num_bytes);
337 pending_write_ = nullptr;
339 if (completed_synchronously) {
340 base::MessageLoop::current()->PostTask(
341 FROM_HERE,
342 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr()));
343 } else {
344 ReadMore();
348 void URLLoaderImpl::DeleteIfNeeded() {
349 bool has_data_pipe = pending_write_.get() || response_body_stream_.is_valid();
350 if (!connected_ && !has_data_pipe)
351 delete this;
354 void URLLoaderImpl::ListenForPeerClosed() {
355 handle_watcher_.Start(response_body_stream_.get(),
356 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
357 MOJO_DEADLINE_INDEFINITE,
358 base::Bind(&URLLoaderImpl::OnResponseBodyStreamClosed,
359 base::Unretained(this)));
362 } // namespace mojo