Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / proxy / proxy_resolver_factory_mojo.cc
blob32c1203e19b0dade14ed4cdb1318ab7ed4d832b5
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"
7 #include <set>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "base/threading/thread_checker.h"
13 #include "base/values.h"
14 #include "mojo/common/common_type_converters.h"
15 #include "mojo/common/url_type_converters.h"
16 #include "net/base/load_states.h"
17 #include "net/base/net_errors.h"
18 #include "net/dns/mojo_host_resolver_impl.h"
19 #include "net/interfaces/host_resolver_service.mojom.h"
20 #include "net/interfaces/proxy_resolver_service.mojom.h"
21 #include "net/proxy/mojo_proxy_resolver_factory.h"
22 #include "net/proxy/mojo_proxy_type_converters.h"
23 #include "net/proxy/proxy_info.h"
24 #include "net/proxy/proxy_resolver.h"
25 #include "net/proxy/proxy_resolver_error_observer.h"
26 #include "net/proxy/proxy_resolver_script_data.h"
27 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
29 namespace net {
30 namespace {
32 scoped_ptr<base::Value> NetLogErrorCallback(
33 int line_number,
34 const base::string16* message,
35 NetLogCaptureMode /* capture_mode */) {
36 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
37 dict->SetInteger("line_number", line_number);
38 dict->SetString("message", *message);
39 return dict.Pass();
42 // A mixin that forwards logging to (Bound)NetLog and ProxyResolverErrorObserver
43 // and DNS requests to a MojoHostResolverImpl, which is implemented in terms of
44 // a HostResolver.
45 template <typename ClientInterface>
46 class ClientMixin : public ClientInterface {
47 public:
48 ClientMixin(HostResolver* host_resolver,
49 ProxyResolverErrorObserver* error_observer,
50 NetLog* net_log,
51 const BoundNetLog& bound_net_log)
52 : host_resolver_(host_resolver, bound_net_log),
53 error_observer_(error_observer),
54 net_log_(net_log),
55 bound_net_log_(bound_net_log) {}
57 // Overridden from ClientInterface:
58 void Alert(const mojo::String& message) override {
59 base::string16 message_str = message.To<base::string16>();
60 auto callback = NetLog::StringCallback("message", &message_str);
61 bound_net_log_.AddEvent(NetLog::TYPE_PAC_JAVASCRIPT_ALERT, callback);
62 if (net_log_)
63 net_log_->AddGlobalEntry(NetLog::TYPE_PAC_JAVASCRIPT_ALERT, callback);
66 void OnError(int32_t line_number, const mojo::String& message) override {
67 base::string16 message_str = message.To<base::string16>();
68 auto callback = base::Bind(&NetLogErrorCallback, line_number, &message_str);
69 bound_net_log_.AddEvent(NetLog::TYPE_PAC_JAVASCRIPT_ERROR, callback);
70 if (net_log_)
71 net_log_->AddGlobalEntry(NetLog::TYPE_PAC_JAVASCRIPT_ERROR, callback);
72 if (error_observer_)
73 error_observer_->OnPACScriptError(line_number, message_str);
76 void ResolveDns(interfaces::HostResolverRequestInfoPtr request_info,
77 interfaces::HostResolverRequestClientPtr client) override {
78 host_resolver_.Resolve(request_info.Pass(), client.Pass());
81 protected:
82 bool dns_request_in_progress() {
83 return host_resolver_.request_in_progress();
86 private:
87 MojoHostResolverImpl host_resolver_;
88 ProxyResolverErrorObserver* const error_observer_;
89 NetLog* const net_log_;
90 const BoundNetLog bound_net_log_;
93 // Implementation of ProxyResolver that connects to a Mojo service to evaluate
94 // PAC scripts. This implementation only knows about Mojo services, and
95 // therefore that service may live in or out of process.
97 // This implementation reports disconnections from the Mojo service (i.e. if the
98 // service is out-of-process and that process crashes) using the error code
99 // ERR_PAC_SCRIPT_TERMINATED.
100 class ProxyResolverMojo : public ProxyResolver {
101 public:
102 // Constructs a ProxyResolverMojo that connects to a mojo proxy resolver
103 // implementation using |resolver_ptr|. The implementation uses
104 // |host_resolver| as the DNS resolver, using |host_resolver_binding| to
105 // communicate with it. When deleted, the closure contained within
106 // |on_delete_callback_runner| will be run.
107 ProxyResolverMojo(
108 interfaces::ProxyResolverPtr resolver_ptr,
109 HostResolver* host_resolver,
110 scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner,
111 scoped_ptr<ProxyResolverErrorObserver> error_observer,
112 NetLog* net_log);
113 ~ProxyResolverMojo() override;
115 // ProxyResolver implementation:
116 int GetProxyForURL(const GURL& url,
117 ProxyInfo* results,
118 const net::CompletionCallback& callback,
119 RequestHandle* request,
120 const BoundNetLog& net_log) override;
121 void CancelRequest(RequestHandle request) override;
122 LoadState GetLoadState(RequestHandle request) const override;
124 private:
125 class Job;
127 // Mojo error handler.
128 void OnConnectionError();
130 void RemoveJob(Job* job);
132 // Connection to the Mojo proxy resolver.
133 interfaces::ProxyResolverPtr mojo_proxy_resolver_ptr_;
135 HostResolver* host_resolver_;
137 scoped_ptr<ProxyResolverErrorObserver> error_observer_;
139 NetLog* net_log_;
141 std::set<Job*> pending_jobs_;
143 base::ThreadChecker thread_checker_;
145 scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner_;
147 DISALLOW_COPY_AND_ASSIGN(ProxyResolverMojo);
150 class ProxyResolverMojo::Job
151 : public ClientMixin<interfaces::ProxyResolverRequestClient> {
152 public:
153 Job(ProxyResolverMojo* resolver,
154 const GURL& url,
155 ProxyInfo* results,
156 const CompletionCallback& callback,
157 const BoundNetLog& net_log);
158 ~Job() override;
160 // Cancels the job and prevents the callback from being run.
161 void Cancel();
163 // Returns the LoadState of this job.
164 LoadState GetLoadState();
166 private:
167 // Mojo error handler.
168 void OnConnectionError();
170 // Overridden from interfaces::ProxyResolverRequestClient:
171 void ReportResult(
172 int32_t error,
173 mojo::Array<interfaces::ProxyServerPtr> proxy_servers) override;
175 ProxyResolverMojo* resolver_;
176 const GURL url_;
177 ProxyInfo* results_;
178 CompletionCallback callback_;
180 base::ThreadChecker thread_checker_;
181 mojo::Binding<interfaces::ProxyResolverRequestClient> binding_;
184 ProxyResolverMojo::Job::Job(ProxyResolverMojo* resolver,
185 const GURL& url,
186 ProxyInfo* results,
187 const CompletionCallback& callback,
188 const BoundNetLog& net_log)
189 : ClientMixin<interfaces::ProxyResolverRequestClient>(
190 resolver->host_resolver_,
191 resolver->error_observer_.get(),
192 resolver->net_log_,
193 net_log),
194 resolver_(resolver),
195 url_(url),
196 results_(results),
197 callback_(callback),
198 binding_(this) {
199 binding_.set_connection_error_handler(base::Bind(
200 &ProxyResolverMojo::Job::OnConnectionError, base::Unretained(this)));
202 interfaces::ProxyResolverRequestClientPtr client_ptr;
203 binding_.Bind(mojo::GetProxy(&client_ptr));
204 resolver_->mojo_proxy_resolver_ptr_->GetProxyForUrl(mojo::String::From(url_),
205 client_ptr.Pass());
208 ProxyResolverMojo::Job::~Job() {
209 DCHECK(thread_checker_.CalledOnValidThread());
210 if (!callback_.is_null())
211 callback_.Run(ERR_PAC_SCRIPT_TERMINATED);
214 void ProxyResolverMojo::Job::Cancel() {
215 DCHECK(thread_checker_.CalledOnValidThread());
216 DCHECK(!callback_.is_null());
217 callback_.Reset();
220 LoadState ProxyResolverMojo::Job::GetLoadState() {
221 return dns_request_in_progress() ? LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
222 : LOAD_STATE_RESOLVING_PROXY_FOR_URL;
225 void ProxyResolverMojo::Job::OnConnectionError() {
226 DCHECK(thread_checker_.CalledOnValidThread());
227 DVLOG(1) << "ProxyResolverMojo::Job::OnConnectionError";
228 resolver_->RemoveJob(this);
231 void ProxyResolverMojo::Job::ReportResult(
232 int32_t error,
233 mojo::Array<interfaces::ProxyServerPtr> proxy_servers) {
234 DCHECK(thread_checker_.CalledOnValidThread());
235 DVLOG(1) << "ProxyResolverMojo::Job::ReportResult: " << error;
237 if (error == OK) {
238 *results_ = proxy_servers.To<ProxyInfo>();
239 DVLOG(1) << "Servers: " << results_->ToPacString();
242 CompletionCallback callback = callback_;
243 callback_.Reset();
244 resolver_->RemoveJob(this);
245 callback.Run(error);
248 ProxyResolverMojo::ProxyResolverMojo(
249 interfaces::ProxyResolverPtr resolver_ptr,
250 HostResolver* host_resolver,
251 scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner,
252 scoped_ptr<ProxyResolverErrorObserver> error_observer,
253 NetLog* net_log)
254 : mojo_proxy_resolver_ptr_(resolver_ptr.Pass()),
255 host_resolver_(host_resolver),
256 error_observer_(error_observer.Pass()),
257 net_log_(net_log),
258 on_delete_callback_runner_(on_delete_callback_runner.Pass()) {
259 mojo_proxy_resolver_ptr_.set_connection_error_handler(base::Bind(
260 &ProxyResolverMojo::OnConnectionError, base::Unretained(this)));
263 ProxyResolverMojo::~ProxyResolverMojo() {
264 DCHECK(thread_checker_.CalledOnValidThread());
265 // All pending requests should have been cancelled.
266 DCHECK(pending_jobs_.empty());
269 void ProxyResolverMojo::OnConnectionError() {
270 DCHECK(thread_checker_.CalledOnValidThread());
271 DVLOG(1) << "ProxyResolverMojo::OnConnectionError";
273 // Disconnect from the Mojo proxy resolver service.
274 mojo_proxy_resolver_ptr_.reset();
277 void ProxyResolverMojo::RemoveJob(Job* job) {
278 DCHECK(thread_checker_.CalledOnValidThread());
279 size_t num_erased = pending_jobs_.erase(job);
280 DCHECK(num_erased);
281 delete job;
284 int ProxyResolverMojo::GetProxyForURL(const GURL& url,
285 ProxyInfo* results,
286 const CompletionCallback& callback,
287 RequestHandle* request,
288 const BoundNetLog& net_log) {
289 DCHECK(thread_checker_.CalledOnValidThread());
291 if (!mojo_proxy_resolver_ptr_)
292 return ERR_PAC_SCRIPT_TERMINATED;
294 Job* job = new Job(this, url, results, callback, net_log);
295 bool inserted = pending_jobs_.insert(job).second;
296 DCHECK(inserted);
297 *request = job;
299 return ERR_IO_PENDING;
302 void ProxyResolverMojo::CancelRequest(RequestHandle request) {
303 DCHECK(thread_checker_.CalledOnValidThread());
304 Job* job = static_cast<Job*>(request);
305 DCHECK(job);
306 job->Cancel();
307 RemoveJob(job);
310 LoadState ProxyResolverMojo::GetLoadState(RequestHandle request) const {
311 Job* job = static_cast<Job*>(request);
312 CHECK_EQ(1u, pending_jobs_.count(job));
313 return job->GetLoadState();
316 } // namespace
318 // A Job to create a ProxyResolver instance.
320 // Note: a Job instance is not tied to a particular resolve request, and hence
321 // there is no per-request logging to be done (any netlog events are only sent
322 // globally) so this always uses an empty BoundNetLog.
323 class ProxyResolverFactoryMojo::Job
324 : public ClientMixin<interfaces::ProxyResolverFactoryRequestClient>,
325 public ProxyResolverFactory::Request {
326 public:
327 Job(ProxyResolverFactoryMojo* factory,
328 const scoped_refptr<ProxyResolverScriptData>& pac_script,
329 scoped_ptr<ProxyResolver>* resolver,
330 const CompletionCallback& callback,
331 scoped_ptr<ProxyResolverErrorObserver> error_observer)
332 : ClientMixin<interfaces::ProxyResolverFactoryRequestClient>(
333 factory->host_resolver_,
334 error_observer.get(),
335 factory->net_log_,
336 BoundNetLog()),
337 factory_(factory),
338 resolver_(resolver),
339 callback_(callback),
340 binding_(this),
341 error_observer_(error_observer.Pass()) {
342 interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
343 binding_.Bind(mojo::GetProxy(&client_ptr));
344 on_delete_callback_runner_ = factory_->mojo_proxy_factory_->CreateResolver(
345 mojo::String::From(pac_script->utf16()), mojo::GetProxy(&resolver_ptr_),
346 client_ptr.Pass());
347 resolver_ptr_.set_connection_error_handler(
348 base::Bind(&ProxyResolverFactoryMojo::Job::OnConnectionError,
349 base::Unretained(this)));
350 binding_.set_connection_error_handler(
351 base::Bind(&ProxyResolverFactoryMojo::Job::OnConnectionError,
352 base::Unretained(this)));
355 void OnConnectionError() { ReportResult(ERR_PAC_SCRIPT_TERMINATED); }
357 private:
358 void ReportResult(int32_t error) override {
359 resolver_ptr_.set_connection_error_handler(mojo::Closure());
360 binding_.set_connection_error_handler(mojo::Closure());
361 if (error == OK) {
362 resolver_->reset(
363 new ProxyResolverMojo(resolver_ptr_.Pass(), factory_->host_resolver_,
364 on_delete_callback_runner_.Pass(),
365 error_observer_.Pass(), factory_->net_log_));
367 on_delete_callback_runner_.reset();
368 callback_.Run(error);
371 ProxyResolverFactoryMojo* const factory_;
372 scoped_ptr<ProxyResolver>* resolver_;
373 const CompletionCallback callback_;
374 interfaces::ProxyResolverPtr resolver_ptr_;
375 mojo::Binding<interfaces::ProxyResolverFactoryRequestClient> binding_;
376 scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner_;
377 scoped_ptr<ProxyResolverErrorObserver> error_observer_;
380 ProxyResolverFactoryMojo::ProxyResolverFactoryMojo(
381 MojoProxyResolverFactory* mojo_proxy_factory,
382 HostResolver* host_resolver,
383 const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>&
384 error_observer_factory,
385 NetLog* net_log)
386 : ProxyResolverFactory(true),
387 mojo_proxy_factory_(mojo_proxy_factory),
388 host_resolver_(host_resolver),
389 error_observer_factory_(error_observer_factory),
390 net_log_(net_log) {
393 ProxyResolverFactoryMojo::~ProxyResolverFactoryMojo() = default;
395 int ProxyResolverFactoryMojo::CreateProxyResolver(
396 const scoped_refptr<ProxyResolverScriptData>& pac_script,
397 scoped_ptr<ProxyResolver>* resolver,
398 const CompletionCallback& callback,
399 scoped_ptr<ProxyResolverFactory::Request>* request) {
400 DCHECK(resolver);
401 DCHECK(request);
402 if (pac_script->type() != ProxyResolverScriptData::TYPE_SCRIPT_CONTENTS ||
403 pac_script->utf16().empty()) {
404 return ERR_PAC_SCRIPT_FAILED;
406 request->reset(new Job(this, pac_script, resolver, callback,
407 error_observer_factory_.is_null()
408 ? nullptr
409 : error_observer_factory_.Run()));
410 return ERR_IO_PENDING;
413 } // namespace net