1 // Copyright 2015 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 "net/proxy/proxy_resolver_factory_mojo.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "base/threading/thread_checker.h"
13 #include "mojo/common/common_type_converters.h"
14 #include "mojo/common/url_type_converters.h"
15 #include "net/base/load_states.h"
16 #include "net/base/net_errors.h"
17 #include "net/dns/mojo_host_resolver_impl.h"
18 #include "net/interfaces/host_resolver_service.mojom.h"
19 #include "net/interfaces/proxy_resolver_service.mojom.h"
20 #include "net/proxy/mojo_proxy_resolver_factory.h"
21 #include "net/proxy/mojo_proxy_type_converters.h"
22 #include "net/proxy/proxy_info.h"
23 #include "net/proxy/proxy_resolver.h"
24 #include "net/proxy/proxy_resolver_error_observer.h"
25 #include "net/proxy/proxy_resolver_script_data.h"
26 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
31 class ErrorObserverHolder
: public interfaces::ProxyResolverErrorObserver
{
34 scoped_ptr
<net::ProxyResolverErrorObserver
> error_observer
,
35 mojo::InterfaceRequest
<interfaces::ProxyResolverErrorObserver
> request
);
36 ~ErrorObserverHolder() override
;
38 void OnPacScriptError(int32_t line_number
,
39 const mojo::String
& error
) override
;
42 scoped_ptr
<net::ProxyResolverErrorObserver
> error_observer_
;
43 mojo::Binding
<interfaces::ProxyResolverErrorObserver
> binding_
;
45 DISALLOW_COPY_AND_ASSIGN(ErrorObserverHolder
);
48 ErrorObserverHolder::ErrorObserverHolder(
49 scoped_ptr
<net::ProxyResolverErrorObserver
> error_observer
,
50 mojo::InterfaceRequest
<interfaces::ProxyResolverErrorObserver
> request
)
51 : error_observer_(error_observer
.Pass()), binding_(this, request
.Pass()) {
54 ErrorObserverHolder::~ErrorObserverHolder() = default;
56 void ErrorObserverHolder::OnPacScriptError(int32_t line_number
,
57 const mojo::String
& error
) {
58 DCHECK(error_observer_
);
59 error_observer_
->OnPACScriptError(line_number
, error
.To
<base::string16
>());
62 // Implementation of ProxyResolver that connects to a Mojo service to evaluate
63 // PAC scripts. This implementation only knows about Mojo services, and
64 // therefore that service may live in or out of process.
66 // This implementation reports disconnections from the Mojo service (i.e. if the
67 // service is out-of-process and that process crashes) using the error code
68 // ERR_PAC_SCRIPT_TERMINATED.
69 class ProxyResolverMojo
: public ProxyResolver
{
71 // Constructs a ProxyResolverMojo that connects to a mojo proxy resolver
72 // implementation using |resolver_ptr|. The implementation uses
73 // |host_resolver| as the DNS resolver, using |host_resolver_binding| to
74 // communicate with it. When deleted, the closure contained within
75 // |on_delete_callback_runner| will be run.
76 // TODO(amistry): Add NetLog.
78 interfaces::ProxyResolverPtr resolver_ptr
,
79 scoped_ptr
<interfaces::HostResolver
> host_resolver
,
80 scoped_ptr
<mojo::Binding
<interfaces::HostResolver
>> host_resolver_binding
,
81 scoped_ptr
<base::ScopedClosureRunner
> on_delete_callback_runner
,
82 scoped_ptr
<ErrorObserverHolder
> error_observer
);
83 ~ProxyResolverMojo() override
;
85 // ProxyResolver implementation:
86 int GetProxyForURL(const GURL
& url
,
88 const net::CompletionCallback
& callback
,
89 RequestHandle
* request
,
90 const BoundNetLog
& net_log
) override
;
91 void CancelRequest(RequestHandle request
) override
;
92 LoadState
GetLoadState(RequestHandle request
) const override
;
97 // Mojo error handler.
98 void OnConnectionError();
100 void RemoveJob(Job
* job
);
102 // Connection to the Mojo proxy resolver.
103 interfaces::ProxyResolverPtr mojo_proxy_resolver_ptr_
;
105 // Mojo host resolver service and binding.
106 scoped_ptr
<interfaces::HostResolver
> mojo_host_resolver_
;
107 scoped_ptr
<mojo::Binding
<interfaces::HostResolver
>>
108 mojo_host_resolver_binding_
;
110 scoped_ptr
<ErrorObserverHolder
> error_observer_
;
112 std::set
<Job
*> pending_jobs_
;
114 base::ThreadChecker thread_checker_
;
116 scoped_ptr
<base::ScopedClosureRunner
> on_delete_callback_runner_
;
118 DISALLOW_COPY_AND_ASSIGN(ProxyResolverMojo
);
121 class ProxyResolverMojo::Job
: public interfaces::ProxyResolverRequestClient
{
123 Job(ProxyResolverMojo
* resolver
,
126 const CompletionCallback
& callback
);
129 // Cancels the job and prevents the callback from being run.
132 // Returns the LoadState of this job.
133 LoadState
load_state() { return LOAD_STATE_RESOLVING_PROXY_FOR_URL
; }
136 // Mojo error handler.
137 void OnConnectionError();
139 // Overridden from interfaces::ProxyResolverRequestClient:
142 mojo::Array
<interfaces::ProxyServerPtr
> proxy_servers
) override
;
144 ProxyResolverMojo
* resolver_
;
147 CompletionCallback callback_
;
149 base::ThreadChecker thread_checker_
;
150 mojo::Binding
<interfaces::ProxyResolverRequestClient
> binding_
;
153 ProxyResolverMojo::Job::Job(ProxyResolverMojo
* resolver
,
156 const CompletionCallback
& callback
)
157 : resolver_(resolver
),
162 binding_
.set_connection_error_handler(base::Bind(
163 &ProxyResolverMojo::Job::OnConnectionError
, base::Unretained(this)));
165 interfaces::ProxyResolverRequestClientPtr client_ptr
;
166 binding_
.Bind(mojo::GetProxy(&client_ptr
));
167 resolver_
->mojo_proxy_resolver_ptr_
->GetProxyForUrl(mojo::String::From(url_
),
171 ProxyResolverMojo::Job::~Job() {
172 DCHECK(thread_checker_
.CalledOnValidThread());
173 if (!callback_
.is_null())
174 callback_
.Run(ERR_PAC_SCRIPT_TERMINATED
);
177 void ProxyResolverMojo::Job::Cancel() {
178 DCHECK(thread_checker_
.CalledOnValidThread());
179 DCHECK(!callback_
.is_null());
183 void ProxyResolverMojo::Job::OnConnectionError() {
184 DCHECK(thread_checker_
.CalledOnValidThread());
185 DVLOG(1) << "ProxyResolverMojo::Job::OnConnectionError";
186 resolver_
->RemoveJob(this);
189 void ProxyResolverMojo::Job::ReportResult(
191 mojo::Array
<interfaces::ProxyServerPtr
> proxy_servers
) {
192 DCHECK(thread_checker_
.CalledOnValidThread());
193 DVLOG(1) << "ProxyResolverMojo::Job::ReportResult: " << error
;
196 *results_
= proxy_servers
.To
<ProxyInfo
>();
197 DVLOG(1) << "Servers: " << results_
->ToPacString();
200 CompletionCallback callback
= callback_
;
202 resolver_
->RemoveJob(this);
206 ProxyResolverMojo::ProxyResolverMojo(
207 interfaces::ProxyResolverPtr resolver_ptr
,
208 scoped_ptr
<interfaces::HostResolver
> host_resolver
,
209 scoped_ptr
<mojo::Binding
<interfaces::HostResolver
>> host_resolver_binding
,
210 scoped_ptr
<base::ScopedClosureRunner
> on_delete_callback_runner
,
211 scoped_ptr
<ErrorObserverHolder
> error_observer
)
212 : mojo_proxy_resolver_ptr_(resolver_ptr
.Pass()),
213 mojo_host_resolver_(host_resolver
.Pass()),
214 mojo_host_resolver_binding_(host_resolver_binding
.Pass()),
215 error_observer_(error_observer
.Pass()),
216 on_delete_callback_runner_(on_delete_callback_runner
.Pass()) {
217 mojo_proxy_resolver_ptr_
.set_connection_error_handler(base::Bind(
218 &ProxyResolverMojo::OnConnectionError
, base::Unretained(this)));
221 ProxyResolverMojo::~ProxyResolverMojo() {
222 DCHECK(thread_checker_
.CalledOnValidThread());
223 // All pending requests should have been cancelled.
224 DCHECK(pending_jobs_
.empty());
227 void ProxyResolverMojo::OnConnectionError() {
228 DCHECK(thread_checker_
.CalledOnValidThread());
229 DVLOG(1) << "ProxyResolverMojo::OnConnectionError";
231 // Disconnect from the Mojo proxy resolver service.
232 mojo_proxy_resolver_ptr_
.reset();
235 void ProxyResolverMojo::RemoveJob(Job
* job
) {
236 DCHECK(thread_checker_
.CalledOnValidThread());
237 size_t num_erased
= pending_jobs_
.erase(job
);
242 int ProxyResolverMojo::GetProxyForURL(const GURL
& url
,
244 const CompletionCallback
& callback
,
245 RequestHandle
* request
,
246 const BoundNetLog
& net_log
) {
247 DCHECK(thread_checker_
.CalledOnValidThread());
249 if (!mojo_proxy_resolver_ptr_
)
250 return ERR_PAC_SCRIPT_TERMINATED
;
252 Job
* job
= new Job(this, url
, results
, callback
);
253 bool inserted
= pending_jobs_
.insert(job
).second
;
257 return ERR_IO_PENDING
;
260 void ProxyResolverMojo::CancelRequest(RequestHandle request
) {
261 DCHECK(thread_checker_
.CalledOnValidThread());
262 Job
* job
= static_cast<Job
*>(request
);
268 LoadState
ProxyResolverMojo::GetLoadState(RequestHandle request
) const {
269 Job
* job
= static_cast<Job
*>(request
);
270 CHECK_EQ(1u, pending_jobs_
.count(job
));
271 return job
->load_state();
276 class ProxyResolverFactoryMojo::Job
277 : public interfaces::ProxyResolverFactoryRequestClient
,
278 public ProxyResolverFactory::Request
{
280 Job(ProxyResolverFactoryMojo
* factory
,
281 const scoped_refptr
<ProxyResolverScriptData
>& pac_script
,
282 scoped_ptr
<ProxyResolver
>* resolver
,
283 const CompletionCallback
& callback
)
288 host_resolver_(new MojoHostResolverImpl(factory_
->host_resolver_
)),
289 host_resolver_binding_(
290 new mojo::Binding
<interfaces::HostResolver
>(host_resolver_
.get())) {
291 interfaces::HostResolverPtr host_resolver_ptr
;
292 interfaces::ProxyResolverFactoryRequestClientPtr client_ptr
;
293 interfaces::ProxyResolverErrorObserverPtr error_observer_ptr
;
294 binding_
.Bind(mojo::GetProxy(&client_ptr
));
295 if (!factory_
->error_observer_factory_
.is_null()) {
296 scoped_ptr
<ProxyResolverErrorObserver
> error_observer
=
297 factory_
->error_observer_factory_
.Run();
298 if (error_observer
) {
299 error_observer_
.reset(new ErrorObserverHolder(
300 error_observer
.Pass(), mojo::GetProxy(&error_observer_ptr
)));
303 host_resolver_binding_
->Bind(mojo::GetProxy(&host_resolver_ptr
));
304 on_delete_callback_runner_
= factory_
->mojo_proxy_factory_
->CreateResolver(
305 mojo::String::From(pac_script
->utf16()), mojo::GetProxy(&resolver_ptr_
),
306 host_resolver_ptr
.Pass(), error_observer_ptr
.Pass(), client_ptr
.Pass());
307 resolver_ptr_
.set_connection_error_handler(
308 base::Bind(&ProxyResolverFactoryMojo::Job::OnConnectionError
,
309 base::Unretained(this)));
310 binding_
.set_connection_error_handler(
311 base::Bind(&ProxyResolverFactoryMojo::Job::OnConnectionError
,
312 base::Unretained(this)));
315 void OnConnectionError() { ReportResult(ERR_PAC_SCRIPT_TERMINATED
); }
318 void ReportResult(int32_t error
) override
{
319 resolver_ptr_
.set_connection_error_handler(mojo::Closure());
320 binding_
.set_connection_error_handler(mojo::Closure());
322 resolver_
->reset(new ProxyResolverMojo(
323 resolver_ptr_
.Pass(), host_resolver_
.Pass(),
324 host_resolver_binding_
.Pass(), on_delete_callback_runner_
.Pass(),
325 error_observer_
.Pass()));
327 on_delete_callback_runner_
.reset();
328 callback_
.Run(error
);
331 ProxyResolverFactoryMojo
* const factory_
;
332 scoped_ptr
<ProxyResolver
>* resolver_
;
333 const CompletionCallback callback_
;
334 interfaces::ProxyResolverPtr resolver_ptr_
;
335 mojo::Binding
<interfaces::ProxyResolverFactoryRequestClient
> binding_
;
336 scoped_ptr
<interfaces::HostResolver
> host_resolver_
;
337 scoped_ptr
<mojo::Binding
<interfaces::HostResolver
>> host_resolver_binding_
;
338 scoped_ptr
<base::ScopedClosureRunner
> on_delete_callback_runner_
;
339 scoped_ptr
<ErrorObserverHolder
> error_observer_
;
342 ProxyResolverFactoryMojo::ProxyResolverFactoryMojo(
343 MojoProxyResolverFactory
* mojo_proxy_factory
,
344 HostResolver
* host_resolver
,
345 const base::Callback
<scoped_ptr
<ProxyResolverErrorObserver
>()>&
346 error_observer_factory
)
347 : ProxyResolverFactory(true),
348 mojo_proxy_factory_(mojo_proxy_factory
),
349 host_resolver_(host_resolver
),
350 error_observer_factory_(error_observer_factory
) {
353 ProxyResolverFactoryMojo::~ProxyResolverFactoryMojo() = default;
355 int ProxyResolverFactoryMojo::CreateProxyResolver(
356 const scoped_refptr
<ProxyResolverScriptData
>& pac_script
,
357 scoped_ptr
<ProxyResolver
>* resolver
,
358 const CompletionCallback
& callback
,
359 scoped_ptr
<ProxyResolverFactory::Request
>* request
) {
362 if (pac_script
->type() != ProxyResolverScriptData::TYPE_SCRIPT_CONTENTS
||
363 pac_script
->utf16().empty()) {
364 return ERR_PAC_SCRIPT_FAILED
;
366 request
->reset(new Job(this, pac_script
, resolver
, callback
));
367 return ERR_IO_PENDING
;