blob: 4a95aa727a7afa588a293bce1d6d8d0d4b785942 [file] [log] [blame]
// Copyright 2015 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 "net/proxy/mojo_proxy_resolver_factory_impl.h"
#include <string>
#include "base/stl_util.h"
#include "net/base/net_errors.h"
#include "net/dns/host_resolver_mojo.h"
#include "net/proxy/mojo_proxy_resolver_impl.h"
#include "net/proxy/proxy_resolver_error_observer_mojo.h"
#include "net/proxy/proxy_resolver_factory.h"
#include "net/proxy/proxy_resolver_v8.h"
#include "net/proxy/proxy_resolver_v8_tracing.h"
#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
namespace net {
namespace {
scoped_ptr<ProxyResolverErrorObserver> ReturnErrorObserver(
scoped_ptr<ProxyResolverErrorObserver> error_observer) {
return error_observer;
}
scoped_ptr<ProxyResolverFactory> CreateDefaultProxyResolver(
HostResolver* host_resolver,
scoped_ptr<ProxyResolverErrorObserver> error_observer,
const ProxyResolver::LoadStateChangedCallback& callback) {
return make_scoped_ptr(new ProxyResolverFactoryV8Tracing(
host_resolver, nullptr, callback,
base::Bind(&ReturnErrorObserver, base::Passed(&error_observer))));
}
class LoadStateChangeForwarder
: public base::RefCounted<LoadStateChangeForwarder> {
public:
LoadStateChangeForwarder() = default;
void OnLoadStateChanged(ProxyResolver::RequestHandle request_handle,
LoadState load_state) const {
if (!callback_.is_null())
callback_.Run(request_handle, load_state);
}
void set_load_state_changed_callback(
const ProxyResolver::LoadStateChangedCallback& callback) {
callback_ = callback;
}
private:
friend class base::RefCounted<LoadStateChangeForwarder>;
~LoadStateChangeForwarder() = default;
ProxyResolver::LoadStateChangedCallback callback_;
DISALLOW_COPY_AND_ASSIGN(LoadStateChangeForwarder);
};
// A class to manage the lifetime of a MojoProxyResolverImpl and a
// HostResolverMojo. An instance will remain while the message pipes for both
// mojo connections remain open.
class MojoProxyResolverHolder : public mojo::ErrorHandler {
public:
MojoProxyResolverHolder(
scoped_ptr<HostResolverMojo> host_resolver,
scoped_ptr<ProxyResolver> proxy_resolver_impl,
const scoped_refptr<LoadStateChangeForwarder>&
load_state_change_forwarder,
mojo::InterfaceRequest<interfaces::ProxyResolver> request);
private:
// mojo::ErrorHandler override.
void OnConnectionError() override;
scoped_ptr<HostResolverMojo> host_resolver_;
MojoProxyResolverImpl mojo_proxy_resolver_;
mojo::Binding<interfaces::ProxyResolver> binding_;
DISALLOW_COPY_AND_ASSIGN(MojoProxyResolverHolder);
};
MojoProxyResolverHolder::MojoProxyResolverHolder(
scoped_ptr<HostResolverMojo> host_resolver,
scoped_ptr<ProxyResolver> proxy_resolver_impl,
const scoped_refptr<LoadStateChangeForwarder>& load_state_change_forwarder,
mojo::InterfaceRequest<interfaces::ProxyResolver> request)
: host_resolver_(host_resolver.Pass()),
mojo_proxy_resolver_(
proxy_resolver_impl.Pass(),
base::Bind(&LoadStateChangeForwarder::set_load_state_changed_callback,
load_state_change_forwarder)),
binding_(&mojo_proxy_resolver_, request.Pass()) {
binding_.set_error_handler(this);
host_resolver_->set_disconnect_callback(base::Bind(
&MojoProxyResolverHolder::OnConnectionError, base::Unretained(this)));
}
void MojoProxyResolverHolder::OnConnectionError() {
delete this;
}
} // namespace
class MojoProxyResolverFactoryImpl::Job : public mojo::ErrorHandler {
public:
Job(MojoProxyResolverFactoryImpl* parent,
const scoped_refptr<ProxyResolverScriptData>& pac_script,
const MojoProxyResolverFactoryImpl::Factory& proxy_resolver_factory,
mojo::InterfaceRequest<interfaces::ProxyResolver> request,
interfaces::HostResolverPtr host_resolver,
interfaces::ProxyResolverErrorObserverPtr error_observer,
interfaces::ProxyResolverFactoryRequestClientPtr client);
~Job() override;
private:
// mojo::ErrorHandler override.
void OnConnectionError() override;
void OnProxyResolverCreated(int error);
MojoProxyResolverFactoryImpl* const parent_;
scoped_ptr<HostResolverMojo> host_resolver_;
scoped_refptr<LoadStateChangeForwarder> load_state_change_forwarder_;
scoped_ptr<ProxyResolver> proxy_resolver_impl_;
mojo::InterfaceRequest<interfaces::ProxyResolver> proxy_request_;
scoped_ptr<net::ProxyResolverFactory> factory_;
scoped_ptr<net::ProxyResolverFactory::Request> request_;
interfaces::ProxyResolverFactoryRequestClientPtr client_ptr_;
DISALLOW_COPY_AND_ASSIGN(Job);
};
MojoProxyResolverFactoryImpl::Job::Job(
MojoProxyResolverFactoryImpl* factory,
const scoped_refptr<ProxyResolverScriptData>& pac_script,
const MojoProxyResolverFactoryImpl::Factory& proxy_resolver_factory,
mojo::InterfaceRequest<interfaces::ProxyResolver> request,
interfaces::HostResolverPtr host_resolver,
interfaces::ProxyResolverErrorObserverPtr error_observer,
interfaces::ProxyResolverFactoryRequestClientPtr client)
: parent_(factory),
host_resolver_(new HostResolverMojo(
host_resolver.Pass(),
base::Bind(&MojoProxyResolverFactoryImpl::Job::OnConnectionError,
base::Unretained(this)))),
load_state_change_forwarder_(new LoadStateChangeForwarder),
proxy_request_(request.Pass()),
factory_(proxy_resolver_factory.Run(
host_resolver_.get(),
ProxyResolverErrorObserverMojo::Create(error_observer.Pass()),
base::Bind(&LoadStateChangeForwarder::OnLoadStateChanged,
load_state_change_forwarder_))),
client_ptr_(client.Pass()) {
client_ptr_.set_error_handler(this);
factory_->CreateProxyResolver(
pac_script, &proxy_resolver_impl_,
base::Bind(&MojoProxyResolverFactoryImpl::Job::OnProxyResolverCreated,
base::Unretained(this)),
&request_);
}
MojoProxyResolverFactoryImpl::Job::~Job() = default;
void MojoProxyResolverFactoryImpl::Job::OnConnectionError() {
client_ptr_->ReportResult(ERR_PAC_SCRIPT_TERMINATED);
parent_->RemoveJob(this);
}
void MojoProxyResolverFactoryImpl::Job::OnProxyResolverCreated(int error) {
if (error == OK) {
// The MojoProxyResolverHolder will delete itself if either
// |host_resolver_| or |proxy_request_| encounters a connection error.
new MojoProxyResolverHolder(
host_resolver_.Pass(), proxy_resolver_impl_.Pass(),
load_state_change_forwarder_, proxy_request_.Pass());
}
client_ptr_->ReportResult(error);
parent_->RemoveJob(this);
}
MojoProxyResolverFactoryImpl::MojoProxyResolverFactoryImpl(
const MojoProxyResolverFactoryImpl::Factory& proxy_resolver_factory,
mojo::InterfaceRequest<interfaces::ProxyResolverFactory> request)
: proxy_resolver_impl_factory_(proxy_resolver_factory),
binding_(this, request.Pass()) {
}
MojoProxyResolverFactoryImpl::MojoProxyResolverFactoryImpl(
mojo::InterfaceRequest<interfaces::ProxyResolverFactory> request)
: MojoProxyResolverFactoryImpl(base::Bind(&CreateDefaultProxyResolver),
request.Pass()) {
}
MojoProxyResolverFactoryImpl::~MojoProxyResolverFactoryImpl() {
STLDeleteElements(&jobs_);
}
void MojoProxyResolverFactoryImpl::CreateResolver(
const mojo::String& pac_script,
mojo::InterfaceRequest<interfaces::ProxyResolver> request,
interfaces::HostResolverPtr host_resolver,
interfaces::ProxyResolverErrorObserverPtr error_observer,
interfaces::ProxyResolverFactoryRequestClientPtr client) {
// The Job will call RemoveJob on |this| when either the create request
// finishes or |request| or |client| encounters a connection error.
jobs_.insert(new Job(
this, ProxyResolverScriptData::FromUTF8(pac_script.To<std::string>()),
proxy_resolver_impl_factory_, request.Pass(), host_resolver.Pass(),
error_observer.Pass(), client.Pass()));
}
void MojoProxyResolverFactoryImpl::RemoveJob(Job* job) {
size_t erased = jobs_.erase(job);
DCHECK_EQ(1u, erased);
delete job;
}
} // namespace net