| Index: mojo/services/network/url_loader_impl.cc
|
| diff --git a/mojo/services/network/url_loader_impl.cc b/mojo/services/network/url_loader_impl.cc
|
| deleted file mode 100644
|
| index b6db54e7550966d2ffb4b3c4fe9c8922caf0a684..0000000000000000000000000000000000000000
|
| --- a/mojo/services/network/url_loader_impl.cc
|
| +++ /dev/null
|
| @@ -1,426 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "mojo/services/network/url_loader_impl.h"
|
| -
|
| -#include <stddef.h>
|
| -#include <stdint.h>
|
| -
|
| -#include <utility>
|
| -#include <vector>
|
| -
|
| -#include "base/macros.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "mojo/common/common_type_converters.h"
|
| -#include "mojo/common/url_type_converters.h"
|
| -#include "mojo/services/network/net_adapters.h"
|
| -#include "mojo/services/network/network_context.h"
|
| -#include "net/base/elements_upload_data_stream.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/base/load_flags.h"
|
| -#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
|
| -#include "net/base/upload_bytes_element_reader.h"
|
| -#include "net/http/http_response_headers.h"
|
| -#include "net/url_request/redirect_info.h"
|
| -#include "net/url_request/url_request_context.h"
|
| -
|
| -namespace mojo {
|
| -namespace {
|
| -
|
| -GURL GetSiteForURL(const GURL& url) {
|
| - // If the url has a host, then determine the site.
|
| - if (url.has_host()) {
|
| - // Only keep the scheme and registered domain as given by GetOrigin. This
|
| - // may also include a port, which we need to drop.
|
| - GURL site = url.GetOrigin();
|
| -
|
| - // Remove port, if any.
|
| - if (site.has_port()) {
|
| - GURL::Replacements rep;
|
| - rep.ClearPort();
|
| - site = site.ReplaceComponents(rep);
|
| - }
|
| -
|
| - // If this URL has a registered domain, we only want to remember that part.
|
| - std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(
|
| - url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
|
| - if (!domain.empty()) {
|
| - GURL::Replacements rep;
|
| - rep.SetHostStr(domain);
|
| - site = site.ReplaceComponents(rep);
|
| - }
|
| - return site;
|
| - }
|
| -
|
| - // If there is no host but there is a scheme, return the scheme.
|
| - // This is useful for cases like file URLs.
|
| - if (url.has_scheme())
|
| - return GURL(url.scheme() + ":");
|
| -
|
| - // Otherwise the URL should be invalid; return an empty site.
|
| - DCHECK(!url.is_valid());
|
| - return GURL();
|
| -}
|
| -
|
| -// Generates an URLResponsePtr from the response state of a net::URLRequest.
|
| -URLResponsePtr MakeURLResponse(const net::URLRequest* url_request) {
|
| - URLResponsePtr response(URLResponse::New());
|
| - response->url = String::From(url_request->url());
|
| - response->site = GetSiteForURL(url_request->url()).spec();
|
| -
|
| - const net::HttpResponseHeaders* headers = url_request->response_headers();
|
| - if (headers) {
|
| - response->status_code = headers->response_code();
|
| - response->status_line = headers->GetStatusLine();
|
| -
|
| - response->headers = Array<HttpHeaderPtr>::New(0);
|
| - std::vector<String> header_lines;
|
| - size_t iter = 0;
|
| - std::string name, value;
|
| - while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
|
| - HttpHeaderPtr header = HttpHeader::New();
|
| - header->name = name;
|
| - header->value = value;
|
| - response->headers.push_back(std::move(header));
|
| - }
|
| - }
|
| -
|
| - std::string mime_type;
|
| - url_request->GetMimeType(&mime_type);
|
| - response->mime_type = mime_type;
|
| -
|
| - std::string charset;
|
| - url_request->GetCharset(&charset);
|
| - response->charset = charset;
|
| -
|
| - return response;
|
| -}
|
| -
|
| -// Reads the request body upload data from a DataPipe.
|
| -class UploadDataPipeElementReader : public net::UploadElementReader {
|
| - public:
|
| - UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe)
|
| - : pipe_(std::move(pipe)), num_bytes_(0) {}
|
| - ~UploadDataPipeElementReader() override {}
|
| -
|
| - // UploadElementReader overrides:
|
| - int Init(const net::CompletionCallback& callback) override {
|
| - offset_ = 0;
|
| - ReadDataRaw(pipe_.get(), nullptr, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY);
|
| - return net::OK;
|
| - }
|
| - uint64_t GetContentLength() const override { return num_bytes_; }
|
| - uint64_t BytesRemaining() const override { return num_bytes_ - offset_; }
|
| - bool IsInMemory() const override { return false; }
|
| - int Read(net::IOBuffer* buf,
|
| - int buf_length,
|
| - const net::CompletionCallback& callback) override {
|
| - uint32_t bytes_read =
|
| - std::min(static_cast<uint32_t>(BytesRemaining()),
|
| - static_cast<uint32_t>(buf_length));
|
| - if (bytes_read > 0) {
|
| - ReadDataRaw(pipe_.get(), buf->data(), &bytes_read,
|
| - MOJO_READ_DATA_FLAG_NONE);
|
| - }
|
| -
|
| - offset_ += bytes_read;
|
| - return bytes_read;
|
| - }
|
| -
|
| - private:
|
| - ScopedDataPipeConsumerHandle pipe_;
|
| - uint32_t num_bytes_;
|
| - uint32_t offset_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader);
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -URLLoaderImpl::URLLoaderImpl(NetworkContext* context,
|
| - InterfaceRequest<URLLoader> request,
|
| - scoped_ptr<mojo::MessageLoopRef> app_refcount)
|
| - : context_(context),
|
| - response_body_buffer_size_(0),
|
| - response_body_bytes_read_(0),
|
| - auto_follow_redirects_(true),
|
| - connected_(true),
|
| - binding_(this, std::move(request)),
|
| - app_refcount_(std::move(app_refcount)),
|
| - weak_ptr_factory_(this) {
|
| - binding_.set_connection_error_handler([this]() { OnConnectionError(); });
|
| - context_->RegisterURLLoader(this);
|
| -}
|
| -
|
| -URLLoaderImpl::~URLLoaderImpl() {
|
| - context_->DeregisterURLLoader(this);
|
| -}
|
| -
|
| -void URLLoaderImpl::Cleanup() {
|
| - // The associated network context is going away and we have to destroy
|
| - // net::URLRequest hold by this loader.
|
| - delete this;
|
| -}
|
| -
|
| -void URLLoaderImpl::Start(URLRequestPtr request,
|
| - const Callback<void(URLResponsePtr)>& callback) {
|
| - if (url_request_) {
|
| - SendError(net::ERR_UNEXPECTED, callback);
|
| - return;
|
| - }
|
| -
|
| - if (!request) {
|
| - SendError(net::ERR_INVALID_ARGUMENT, callback);
|
| - return;
|
| - }
|
| -
|
| - url_request_ = context_->url_request_context()->CreateRequest(
|
| - GURL(request->url.get()), net::DEFAULT_PRIORITY, this);
|
| - url_request_->set_method(request->method);
|
| - // TODO(jam): need to specify this policy.
|
| - url_request_->set_referrer_policy(
|
| - net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE);
|
| - if (request->headers) {
|
| - net::HttpRequestHeaders headers;
|
| - for (size_t i = 0; i < request->headers.size(); ++i) {
|
| - base::StringPiece header =
|
| - request->headers[i]->name.To<base::StringPiece>();
|
| - base::StringPiece value =
|
| - request->headers[i]->value.To<base::StringPiece>();
|
| - if (header == net::HttpRequestHeaders::kReferer) {
|
| - url_request_->SetReferrer(value.as_string());
|
| - } else {
|
| - headers.SetHeader(header, value);
|
| - }
|
| - }
|
| - url_request_->SetExtraRequestHeaders(headers);
|
| - }
|
| - if (request->body) {
|
| - std::vector<scoped_ptr<net::UploadElementReader>> element_readers;
|
| - for (size_t i = 0; i < request->body.size(); ++i) {
|
| - element_readers.push_back(make_scoped_ptr(
|
| - new UploadDataPipeElementReader(std::move(request->body[i]))));
|
| - }
|
| - url_request_->set_upload(make_scoped_ptr<net::UploadDataStream>(
|
| - new net::ElementsUploadDataStream(std::move(element_readers), 0)));
|
| - }
|
| - if (request->bypass_cache)
|
| - url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE);
|
| -
|
| - callback_ = callback;
|
| - response_body_buffer_size_ = request->response_body_buffer_size;
|
| - auto_follow_redirects_ = request->auto_follow_redirects;
|
| -
|
| - url_request_->Start();
|
| -}
|
| -
|
| -void URLLoaderImpl::FollowRedirect(
|
| - const Callback<void(URLResponsePtr)>& callback) {
|
| - if (!url_request_) {
|
| - SendError(net::ERR_UNEXPECTED, callback);
|
| - return;
|
| - }
|
| -
|
| - if (auto_follow_redirects_) {
|
| - DLOG(ERROR) << "Spurious call to FollowRedirect";
|
| - SendError(net::ERR_UNEXPECTED, callback);
|
| - return;
|
| - }
|
| -
|
| - // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
|
| - url_request_->FollowDeferredRedirect();
|
| - callback_ = callback;
|
| -}
|
| -
|
| -void URLLoaderImpl::QueryStatus(
|
| - const Callback<void(URLLoaderStatusPtr)>& callback) {
|
| - URLLoaderStatusPtr status(URLLoaderStatus::New());
|
| - status->bytes_read = response_body_bytes_read_;
|
| - if (url_request_) {
|
| - status->is_loading = url_request_->is_pending();
|
| - if (!url_request_->status().is_success())
|
| - status->error = MakeNetworkError(url_request_->status().error());
|
| - if (url_request_->response_info().headers) {
|
| - status->content_length =
|
| - url_request_->response_info().headers->GetContentLength();
|
| - }
|
| - } else {
|
| - status->is_loading = false;
|
| - }
|
| - // TODO(darin): Populate more status fields.
|
| - callback.Run(std::move(status));
|
| -}
|
| -
|
| -void URLLoaderImpl::OnConnectionError() {
|
| - connected_ = false;
|
| - DeleteIfNeeded();
|
| -}
|
| -
|
| -void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request,
|
| - const net::RedirectInfo& redirect_info,
|
| - bool* defer_redirect) {
|
| - DCHECK(url_request == url_request_.get());
|
| - DCHECK(url_request->status().is_success());
|
| -
|
| - if (auto_follow_redirects_)
|
| - return;
|
| -
|
| - // Send the redirect response to the client, allowing them to inspect it and
|
| - // optionally follow the redirect.
|
| - *defer_redirect = true;
|
| -
|
| - URLResponsePtr response = MakeURLResponse(url_request);
|
| - response->redirect_method = redirect_info.new_method;
|
| - response->redirect_url = String::From(redirect_info.new_url);
|
| - response->redirect_referrer = redirect_info.new_referrer;
|
| -
|
| - SendResponse(std::move(response));
|
| -
|
| - DeleteIfNeeded();
|
| -}
|
| -
|
| -void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) {
|
| - DCHECK(url_request == url_request_.get());
|
| -
|
| - if (!url_request->status().is_success()) {
|
| - SendError(url_request->status().error(), callback_);
|
| - callback_ = Callback<void(URLResponsePtr)>();
|
| - DeleteIfNeeded();
|
| - return;
|
| - }
|
| -
|
| - // TODO(darin): Add support for optional MIME sniffing.
|
| -
|
| - DataPipe data_pipe;
|
| - // TODO(darin): Honor given buffer size.
|
| -
|
| - URLResponsePtr response = MakeURLResponse(url_request);
|
| - response->body = std::move(data_pipe.consumer_handle);
|
| - response_body_stream_ = std::move(data_pipe.producer_handle);
|
| - ListenForPeerClosed();
|
| -
|
| - SendResponse(std::move(response));
|
| -
|
| - // Start reading...
|
| - ReadMore();
|
| -}
|
| -
|
| -void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request,
|
| - int bytes_read) {
|
| - DCHECK(url_request == url_request_.get());
|
| -
|
| - if (url_request->status().is_success()) {
|
| - DidRead(static_cast<uint32_t>(bytes_read), false);
|
| - } else {
|
| - handle_watcher_.Stop();
|
| - pending_write_ = nullptr; // This closes the data pipe.
|
| - DeleteIfNeeded();
|
| - return;
|
| - }
|
| -}
|
| -
|
| -void URLLoaderImpl::SendError(
|
| - int error_code,
|
| - const Callback<void(URLResponsePtr)>& callback) {
|
| - URLResponsePtr response(URLResponse::New());
|
| - if (url_request_)
|
| - response->url = String::From(url_request_->url());
|
| - response->error = MakeNetworkError(error_code);
|
| - callback.Run(std::move(response));
|
| -}
|
| -
|
| -void URLLoaderImpl::SendResponse(URLResponsePtr response) {
|
| - Callback<void(URLResponsePtr)> callback;
|
| - std::swap(callback_, callback);
|
| - callback.Run(std::move(response));
|
| -}
|
| -
|
| -void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) {
|
| - // TODO(darin): Handle a bad |result| value.
|
| -
|
| - // Continue watching the handle in case the peer is closed.
|
| - ListenForPeerClosed();
|
| - ReadMore();
|
| -}
|
| -
|
| -void URLLoaderImpl::OnResponseBodyStreamClosed(MojoResult result) {
|
| - url_request_.reset();
|
| - response_body_stream_.reset();
|
| - pending_write_ = nullptr;
|
| - DeleteIfNeeded();
|
| -}
|
| -
|
| -void URLLoaderImpl::ReadMore() {
|
| - DCHECK(!pending_write_.get());
|
| -
|
| - uint32_t num_bytes;
|
| - MojoResult result = NetToMojoPendingBuffer::BeginWrite(
|
| - &response_body_stream_, &pending_write_, &num_bytes);
|
| -
|
| - if (result == MOJO_RESULT_SHOULD_WAIT) {
|
| - // The pipe is full. We need to wait for it to have more space.
|
| - handle_watcher_.Start(response_body_stream_.get(),
|
| - MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE,
|
| - base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady,
|
| - base::Unretained(this)));
|
| - return;
|
| - } else if (result != MOJO_RESULT_OK) {
|
| - // The response body stream is in a bad state. Bail.
|
| - // TODO(darin): How should this be communicated to our client?
|
| - handle_watcher_.Stop();
|
| - response_body_stream_.reset();
|
| - DeleteIfNeeded();
|
| - return;
|
| - }
|
| - CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes);
|
| -
|
| - scoped_refptr<net::IOBuffer> buf(new NetToMojoIOBuffer(pending_write_.get()));
|
| -
|
| - int bytes_read;
|
| - url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read);
|
| - if (url_request_->status().is_io_pending()) {
|
| - // Wait for OnReadCompleted.
|
| - } else if (url_request_->status().is_success() && bytes_read > 0) {
|
| - DidRead(static_cast<uint32_t>(bytes_read), true);
|
| - } else {
|
| - handle_watcher_.Stop();
|
| - pending_write_->Complete(0);
|
| - pending_write_ = nullptr; // This closes the data pipe.
|
| - DeleteIfNeeded();
|
| - return;
|
| - }
|
| -}
|
| -
|
| -void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) {
|
| - DCHECK(url_request_->status().is_success());
|
| -
|
| - response_body_bytes_read_ += num_bytes;
|
| - response_body_stream_ = pending_write_->Complete(num_bytes);
|
| - pending_write_ = nullptr;
|
| -
|
| - if (completed_synchronously) {
|
| - base::MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr()));
|
| - } else {
|
| - ReadMore();
|
| - }
|
| -}
|
| -
|
| -void URLLoaderImpl::DeleteIfNeeded() {
|
| - bool has_data_pipe = pending_write_.get() || response_body_stream_.is_valid();
|
| - if (!connected_ && !has_data_pipe)
|
| - delete this;
|
| -}
|
| -
|
| -void URLLoaderImpl::ListenForPeerClosed() {
|
| - handle_watcher_.Start(response_body_stream_.get(),
|
| - MOJO_HANDLE_SIGNAL_PEER_CLOSED,
|
| - MOJO_DEADLINE_INDEFINITE,
|
| - base::Bind(&URLLoaderImpl::OnResponseBodyStreamClosed,
|
| - base::Unretained(this)));
|
| -}
|
| -
|
| -} // namespace mojo
|
|
|