Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: mojo/services/network/url_loader_impl.cc

Issue 1873463003: Remove mojo network service. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <stddef.h>
8 #include <stdint.h>
9
10 #include <utility>
11 #include <vector>
12
13 #include "base/macros.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "mojo/common/common_type_converters.h"
17 #include "mojo/common/url_type_converters.h"
18 #include "mojo/services/network/net_adapters.h"
19 #include "mojo/services/network/network_context.h"
20 #include "net/base/elements_upload_data_stream.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/load_flags.h"
23 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
24 #include "net/base/upload_bytes_element_reader.h"
25 #include "net/http/http_response_headers.h"
26 #include "net/url_request/redirect_info.h"
27 #include "net/url_request/url_request_context.h"
28
29 namespace mojo {
30 namespace {
31
32 GURL GetSiteForURL(const GURL& url) {
33 // If the url has a host, then determine the site.
34 if (url.has_host()) {
35 // Only keep the scheme and registered domain as given by GetOrigin. This
36 // may also include a port, which we need to drop.
37 GURL site = url.GetOrigin();
38
39 // Remove port, if any.
40 if (site.has_port()) {
41 GURL::Replacements rep;
42 rep.ClearPort();
43 site = site.ReplaceComponents(rep);
44 }
45
46 // If this URL has a registered domain, we only want to remember that part.
47 std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(
48 url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
49 if (!domain.empty()) {
50 GURL::Replacements rep;
51 rep.SetHostStr(domain);
52 site = site.ReplaceComponents(rep);
53 }
54 return site;
55 }
56
57 // If there is no host but there is a scheme, return the scheme.
58 // This is useful for cases like file URLs.
59 if (url.has_scheme())
60 return GURL(url.scheme() + ":");
61
62 // Otherwise the URL should be invalid; return an empty site.
63 DCHECK(!url.is_valid());
64 return GURL();
65 }
66
67 // Generates an URLResponsePtr from the response state of a net::URLRequest.
68 URLResponsePtr MakeURLResponse(const net::URLRequest* url_request) {
69 URLResponsePtr response(URLResponse::New());
70 response->url = String::From(url_request->url());
71 response->site = GetSiteForURL(url_request->url()).spec();
72
73 const net::HttpResponseHeaders* headers = url_request->response_headers();
74 if (headers) {
75 response->status_code = headers->response_code();
76 response->status_line = headers->GetStatusLine();
77
78 response->headers = Array<HttpHeaderPtr>::New(0);
79 std::vector<String> header_lines;
80 size_t iter = 0;
81 std::string name, value;
82 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
83 HttpHeaderPtr header = HttpHeader::New();
84 header->name = name;
85 header->value = value;
86 response->headers.push_back(std::move(header));
87 }
88 }
89
90 std::string mime_type;
91 url_request->GetMimeType(&mime_type);
92 response->mime_type = mime_type;
93
94 std::string charset;
95 url_request->GetCharset(&charset);
96 response->charset = charset;
97
98 return response;
99 }
100
101 // Reads the request body upload data from a DataPipe.
102 class UploadDataPipeElementReader : public net::UploadElementReader {
103 public:
104 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe)
105 : pipe_(std::move(pipe)), num_bytes_(0) {}
106 ~UploadDataPipeElementReader() override {}
107
108 // UploadElementReader overrides:
109 int Init(const net::CompletionCallback& callback) override {
110 offset_ = 0;
111 ReadDataRaw(pipe_.get(), nullptr, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY);
112 return net::OK;
113 }
114 uint64_t GetContentLength() const override { return num_bytes_; }
115 uint64_t BytesRemaining() const override { return num_bytes_ - offset_; }
116 bool IsInMemory() const override { return false; }
117 int Read(net::IOBuffer* buf,
118 int buf_length,
119 const net::CompletionCallback& callback) override {
120 uint32_t bytes_read =
121 std::min(static_cast<uint32_t>(BytesRemaining()),
122 static_cast<uint32_t>(buf_length));
123 if (bytes_read > 0) {
124 ReadDataRaw(pipe_.get(), buf->data(), &bytes_read,
125 MOJO_READ_DATA_FLAG_NONE);
126 }
127
128 offset_ += bytes_read;
129 return bytes_read;
130 }
131
132 private:
133 ScopedDataPipeConsumerHandle pipe_;
134 uint32_t num_bytes_;
135 uint32_t offset_;
136
137 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader);
138 };
139
140 } // namespace
141
142 URLLoaderImpl::URLLoaderImpl(NetworkContext* context,
143 InterfaceRequest<URLLoader> request,
144 scoped_ptr<mojo::MessageLoopRef> app_refcount)
145 : context_(context),
146 response_body_buffer_size_(0),
147 response_body_bytes_read_(0),
148 auto_follow_redirects_(true),
149 connected_(true),
150 binding_(this, std::move(request)),
151 app_refcount_(std::move(app_refcount)),
152 weak_ptr_factory_(this) {
153 binding_.set_connection_error_handler([this]() { OnConnectionError(); });
154 context_->RegisterURLLoader(this);
155 }
156
157 URLLoaderImpl::~URLLoaderImpl() {
158 context_->DeregisterURLLoader(this);
159 }
160
161 void URLLoaderImpl::Cleanup() {
162 // The associated network context is going away and we have to destroy
163 // net::URLRequest hold by this loader.
164 delete this;
165 }
166
167 void URLLoaderImpl::Start(URLRequestPtr request,
168 const Callback<void(URLResponsePtr)>& callback) {
169 if (url_request_) {
170 SendError(net::ERR_UNEXPECTED, callback);
171 return;
172 }
173
174 if (!request) {
175 SendError(net::ERR_INVALID_ARGUMENT, callback);
176 return;
177 }
178
179 url_request_ = context_->url_request_context()->CreateRequest(
180 GURL(request->url.get()), net::DEFAULT_PRIORITY, this);
181 url_request_->set_method(request->method);
182 // TODO(jam): need to specify this policy.
183 url_request_->set_referrer_policy(
184 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE);
185 if (request->headers) {
186 net::HttpRequestHeaders headers;
187 for (size_t i = 0; i < request->headers.size(); ++i) {
188 base::StringPiece header =
189 request->headers[i]->name.To<base::StringPiece>();
190 base::StringPiece value =
191 request->headers[i]->value.To<base::StringPiece>();
192 if (header == net::HttpRequestHeaders::kReferer) {
193 url_request_->SetReferrer(value.as_string());
194 } else {
195 headers.SetHeader(header, value);
196 }
197 }
198 url_request_->SetExtraRequestHeaders(headers);
199 }
200 if (request->body) {
201 std::vector<scoped_ptr<net::UploadElementReader>> element_readers;
202 for (size_t i = 0; i < request->body.size(); ++i) {
203 element_readers.push_back(make_scoped_ptr(
204 new UploadDataPipeElementReader(std::move(request->body[i]))));
205 }
206 url_request_->set_upload(make_scoped_ptr<net::UploadDataStream>(
207 new net::ElementsUploadDataStream(std::move(element_readers), 0)));
208 }
209 if (request->bypass_cache)
210 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE);
211
212 callback_ = callback;
213 response_body_buffer_size_ = request->response_body_buffer_size;
214 auto_follow_redirects_ = request->auto_follow_redirects;
215
216 url_request_->Start();
217 }
218
219 void URLLoaderImpl::FollowRedirect(
220 const Callback<void(URLResponsePtr)>& callback) {
221 if (!url_request_) {
222 SendError(net::ERR_UNEXPECTED, callback);
223 return;
224 }
225
226 if (auto_follow_redirects_) {
227 DLOG(ERROR) << "Spurious call to FollowRedirect";
228 SendError(net::ERR_UNEXPECTED, callback);
229 return;
230 }
231
232 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
233 url_request_->FollowDeferredRedirect();
234 callback_ = callback;
235 }
236
237 void URLLoaderImpl::QueryStatus(
238 const Callback<void(URLLoaderStatusPtr)>& callback) {
239 URLLoaderStatusPtr status(URLLoaderStatus::New());
240 status->bytes_read = response_body_bytes_read_;
241 if (url_request_) {
242 status->is_loading = url_request_->is_pending();
243 if (!url_request_->status().is_success())
244 status->error = MakeNetworkError(url_request_->status().error());
245 if (url_request_->response_info().headers) {
246 status->content_length =
247 url_request_->response_info().headers->GetContentLength();
248 }
249 } else {
250 status->is_loading = false;
251 }
252 // TODO(darin): Populate more status fields.
253 callback.Run(std::move(status));
254 }
255
256 void URLLoaderImpl::OnConnectionError() {
257 connected_ = false;
258 DeleteIfNeeded();
259 }
260
261 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request,
262 const net::RedirectInfo& redirect_info,
263 bool* defer_redirect) {
264 DCHECK(url_request == url_request_.get());
265 DCHECK(url_request->status().is_success());
266
267 if (auto_follow_redirects_)
268 return;
269
270 // Send the redirect response to the client, allowing them to inspect it and
271 // optionally follow the redirect.
272 *defer_redirect = true;
273
274 URLResponsePtr response = MakeURLResponse(url_request);
275 response->redirect_method = redirect_info.new_method;
276 response->redirect_url = String::From(redirect_info.new_url);
277 response->redirect_referrer = redirect_info.new_referrer;
278
279 SendResponse(std::move(response));
280
281 DeleteIfNeeded();
282 }
283
284 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) {
285 DCHECK(url_request == url_request_.get());
286
287 if (!url_request->status().is_success()) {
288 SendError(url_request->status().error(), callback_);
289 callback_ = Callback<void(URLResponsePtr)>();
290 DeleteIfNeeded();
291 return;
292 }
293
294 // TODO(darin): Add support for optional MIME sniffing.
295
296 DataPipe data_pipe;
297 // TODO(darin): Honor given buffer size.
298
299 URLResponsePtr response = MakeURLResponse(url_request);
300 response->body = std::move(data_pipe.consumer_handle);
301 response_body_stream_ = std::move(data_pipe.producer_handle);
302 ListenForPeerClosed();
303
304 SendResponse(std::move(response));
305
306 // Start reading...
307 ReadMore();
308 }
309
310 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request,
311 int bytes_read) {
312 DCHECK(url_request == url_request_.get());
313
314 if (url_request->status().is_success()) {
315 DidRead(static_cast<uint32_t>(bytes_read), false);
316 } else {
317 handle_watcher_.Stop();
318 pending_write_ = nullptr; // This closes the data pipe.
319 DeleteIfNeeded();
320 return;
321 }
322 }
323
324 void URLLoaderImpl::SendError(
325 int error_code,
326 const Callback<void(URLResponsePtr)>& callback) {
327 URLResponsePtr response(URLResponse::New());
328 if (url_request_)
329 response->url = String::From(url_request_->url());
330 response->error = MakeNetworkError(error_code);
331 callback.Run(std::move(response));
332 }
333
334 void URLLoaderImpl::SendResponse(URLResponsePtr response) {
335 Callback<void(URLResponsePtr)> callback;
336 std::swap(callback_, callback);
337 callback.Run(std::move(response));
338 }
339
340 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) {
341 // TODO(darin): Handle a bad |result| value.
342
343 // Continue watching the handle in case the peer is closed.
344 ListenForPeerClosed();
345 ReadMore();
346 }
347
348 void URLLoaderImpl::OnResponseBodyStreamClosed(MojoResult result) {
349 url_request_.reset();
350 response_body_stream_.reset();
351 pending_write_ = nullptr;
352 DeleteIfNeeded();
353 }
354
355 void URLLoaderImpl::ReadMore() {
356 DCHECK(!pending_write_.get());
357
358 uint32_t num_bytes;
359 MojoResult result = NetToMojoPendingBuffer::BeginWrite(
360 &response_body_stream_, &pending_write_, &num_bytes);
361
362 if (result == MOJO_RESULT_SHOULD_WAIT) {
363 // The pipe is full. We need to wait for it to have more space.
364 handle_watcher_.Start(response_body_stream_.get(),
365 MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE,
366 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady,
367 base::Unretained(this)));
368 return;
369 } else if (result != MOJO_RESULT_OK) {
370 // The response body stream is in a bad state. Bail.
371 // TODO(darin): How should this be communicated to our client?
372 handle_watcher_.Stop();
373 response_body_stream_.reset();
374 DeleteIfNeeded();
375 return;
376 }
377 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes);
378
379 scoped_refptr<net::IOBuffer> buf(new NetToMojoIOBuffer(pending_write_.get()));
380
381 int bytes_read;
382 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read);
383 if (url_request_->status().is_io_pending()) {
384 // Wait for OnReadCompleted.
385 } else if (url_request_->status().is_success() && bytes_read > 0) {
386 DidRead(static_cast<uint32_t>(bytes_read), true);
387 } else {
388 handle_watcher_.Stop();
389 pending_write_->Complete(0);
390 pending_write_ = nullptr; // This closes the data pipe.
391 DeleteIfNeeded();
392 return;
393 }
394 }
395
396 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) {
397 DCHECK(url_request_->status().is_success());
398
399 response_body_bytes_read_ += num_bytes;
400 response_body_stream_ = pending_write_->Complete(num_bytes);
401 pending_write_ = nullptr;
402
403 if (completed_synchronously) {
404 base::MessageLoop::current()->PostTask(
405 FROM_HERE,
406 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr()));
407 } else {
408 ReadMore();
409 }
410 }
411
412 void URLLoaderImpl::DeleteIfNeeded() {
413 bool has_data_pipe = pending_write_.get() || response_body_stream_.is_valid();
414 if (!connected_ && !has_data_pipe)
415 delete this;
416 }
417
418 void URLLoaderImpl::ListenForPeerClosed() {
419 handle_watcher_.Start(response_body_stream_.get(),
420 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
421 MOJO_DEADLINE_INDEFINITE,
422 base::Bind(&URLLoaderImpl::OnResponseBodyStreamClosed,
423 base::Unretained(this)));
424 }
425
426 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/services/network/url_loader_impl.h ('k') | mojo/services/network/url_loader_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698