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_mojo.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10 #include "mojo/common/common_type_converters.h"
11 #include "mojo/common/url_type_converters.h"
12 #include "net/base/net_errors.h"
13 #include "net/dns/mojo_host_resolver_impl.h"
14 #include "net/proxy/mojo_proxy_resolver_factory.h"
15 #include "net/proxy/mojo_proxy_type_converters.h"
16 #include "net/proxy/proxy_info.h"
17 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
18 #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
22 class ProxyResolverMojo::Job
: public interfaces::ProxyResolverRequestClient
,
23 public mojo::ErrorHandler
{
25 Job(ProxyResolverMojo
* resolver
,
28 const CompletionCallback
& callback
);
31 // Cancels the job and prevents the callback from being run.
34 // Returns the LoadState of this job.
35 LoadState
load_state() { return load_state_
; }
38 // Overridden from mojo::ErrorHandler:
39 void OnConnectionError() override
;
41 // Overridden from interfaces::ProxyResolverRequestClient:
44 mojo::Array
<interfaces::ProxyServerPtr
> proxy_servers
) override
;
45 void LoadStateChanged(int32_t load_state
) override
;
47 ProxyResolverMojo
* resolver_
;
50 CompletionCallback callback_
;
51 LoadState load_state_
= LOAD_STATE_RESOLVING_PROXY_FOR_URL
;
53 base::ThreadChecker thread_checker_
;
54 mojo::Binding
<interfaces::ProxyResolverRequestClient
> binding_
;
57 ProxyResolverMojo::Job::Job(ProxyResolverMojo
* resolver
,
60 const CompletionCallback
& callback
)
61 : resolver_(resolver
),
66 binding_
.set_error_handler(this);
68 interfaces::ProxyResolverRequestClientPtr client_ptr
;
69 binding_
.Bind(mojo::GetProxy(&client_ptr
));
70 resolver_
->mojo_proxy_resolver_ptr_
->GetProxyForUrl(mojo::String::From(url_
),
74 ProxyResolverMojo::Job::~Job() {
75 DCHECK(thread_checker_
.CalledOnValidThread());
76 if (!callback_
.is_null())
77 callback_
.Run(ERR_PAC_SCRIPT_TERMINATED
);
80 void ProxyResolverMojo::Job::Cancel() {
81 DCHECK(thread_checker_
.CalledOnValidThread());
82 DCHECK(!callback_
.is_null());
86 void ProxyResolverMojo::Job::OnConnectionError() {
87 DCHECK(thread_checker_
.CalledOnValidThread());
88 DVLOG(1) << "ProxyResolverMojo::Job::OnConnectionError";
89 resolver_
->RemoveJob(this);
92 void ProxyResolverMojo::Job::ReportResult(
94 mojo::Array
<interfaces::ProxyServerPtr
> proxy_servers
) {
95 DCHECK(thread_checker_
.CalledOnValidThread());
96 DVLOG(1) << "ProxyResolverMojo::Job::ReportResult: " << error
;
99 *results_
= proxy_servers
.To
<ProxyInfo
>();
100 DVLOG(1) << "Servers: " << results_
->ToPacString();
103 CompletionCallback callback
= callback_
;
105 resolver_
->RemoveJob(this);
109 void ProxyResolverMojo::Job::LoadStateChanged(int32_t load_state
) {
110 load_state_
= static_cast<LoadState
>(load_state
);
113 ProxyResolverMojo::ProxyResolverMojo(
114 MojoProxyResolverFactory
* mojo_proxy_resolver_factory
,
115 HostResolver
* host_resolver
)
116 : ProxyResolver(true /* |expects_pac_bytes| */),
117 mojo_proxy_resolver_factory_(mojo_proxy_resolver_factory
),
118 host_resolver_(host_resolver
) {
121 ProxyResolverMojo::~ProxyResolverMojo() {
122 DCHECK(thread_checker_
.CalledOnValidThread());
123 // All pending requests should have been cancelled.
124 DCHECK(pending_jobs_
.empty());
125 DCHECK(set_pac_script_callback_
.IsCancelled());
128 void ProxyResolverMojo::CancelSetPacScript() {
129 DCHECK(thread_checker_
.CalledOnValidThread());
130 set_pac_script_callback_
.Cancel();
133 int ProxyResolverMojo::SetPacScript(
134 const scoped_refptr
<ProxyResolverScriptData
>& pac_script
,
135 const CompletionCallback
& callback
) {
136 DCHECK(thread_checker_
.CalledOnValidThread());
137 DCHECK(set_pac_script_callback_
.IsCancelled());
138 DCHECK(!callback
.is_null());
139 if (pac_script
->type() != ProxyResolverScriptData::TYPE_SCRIPT_CONTENTS
||
140 pac_script
->utf16().empty()) {
141 return ERR_PAC_SCRIPT_FAILED
;
144 DVLOG(1) << "ProxyResolverMojo::SetPacScript: " << pac_script
->utf16();
145 set_pac_script_callback_
.Reset(
146 base::Bind(&ProxyResolverMojo::OnSetPacScriptDone
, base::Unretained(this),
147 pac_script
, callback
));
149 if (!mojo_proxy_resolver_ptr_
)
152 mojo_proxy_resolver_ptr_
->SetPacScript(
153 mojo::String::From(pac_script
->utf16()),
154 set_pac_script_callback_
.callback());
156 return ERR_IO_PENDING
;
159 void ProxyResolverMojo::OnSetPacScriptDone(
160 const scoped_refptr
<ProxyResolverScriptData
>& pac_script
,
161 const CompletionCallback
& callback
,
163 DCHECK(thread_checker_
.CalledOnValidThread());
164 DCHECK(!set_pac_script_callback_
.IsCancelled());
165 DVLOG(1) << "ProxyResolverMojo::OnSetPacScriptDone: " << result
;
167 // |callback| is owned by |set_pac_script_callback_|, so make a copy before
169 auto callback_copy
= callback
;
170 set_pac_script_callback_
.Cancel();
171 callback_copy
.Run(result
);
174 void ProxyResolverMojo::SetUpServices() {
175 DCHECK(thread_checker_
.CalledOnValidThread());
176 // A Mojo service implementation must outlive its binding.
177 mojo_host_resolver_binding_
.reset();
179 interfaces::HostResolverPtr mojo_host_resolver_ptr
;
180 mojo_host_resolver_
.reset(new MojoHostResolverImpl(host_resolver_
));
181 mojo_host_resolver_binding_
.reset(new mojo::Binding
<interfaces::HostResolver
>(
182 mojo_host_resolver_
.get(), mojo::GetProxy(&mojo_host_resolver_ptr
)));
183 mojo_proxy_resolver_ptr_
.reset();
184 mojo_proxy_resolver_factory_
->Create(
185 mojo::GetProxy(&mojo_proxy_resolver_ptr_
), mojo_host_resolver_ptr
.Pass());
186 mojo_proxy_resolver_ptr_
.set_error_handler(this);
189 void ProxyResolverMojo::OnConnectionError() {
190 DCHECK(thread_checker_
.CalledOnValidThread());
191 DVLOG(1) << "ProxyResolverMojo::OnConnectionError";
193 // Disconnect from the Mojo proxy resolver service. An attempt to reconnect
194 // will happen on the next |SetPacScript()| request.
195 mojo_proxy_resolver_ptr_
.reset();
197 // This callback may call |SetPacScript()| and re-create the connection. So
198 // disconnect from the Mojo service (above) before aborting the pending
200 if (!set_pac_script_callback_
.IsCancelled())
201 set_pac_script_callback_
.callback().Run(ERR_PAC_SCRIPT_TERMINATED
);
204 void ProxyResolverMojo::RemoveJob(Job
* job
) {
205 DCHECK(thread_checker_
.CalledOnValidThread());
206 size_t num_erased
= pending_jobs_
.erase(job
);
211 int ProxyResolverMojo::GetProxyForURL(const GURL
& url
,
213 const CompletionCallback
& callback
,
214 RequestHandle
* request
,
215 const BoundNetLog
& net_log
) {
216 DCHECK(thread_checker_
.CalledOnValidThread());
218 // If the Mojo service is not connected, fail. The Mojo service is connected
219 // when the script is set, which must be done after construction and after a
220 // previous request returns ERR_PAC_SCRIPT_TERMINATED due to the Mojo proxy
221 // resolver process crashing.
222 if (!mojo_proxy_resolver_ptr_
) {
223 DVLOG(1) << "ProxyResolverMojo::GetProxyForURL: Mojo not connected";
224 return ERR_PAC_SCRIPT_TERMINATED
;
227 Job
* job
= new Job(this, url
, results
, callback
);
228 bool inserted
= pending_jobs_
.insert(job
).second
;
232 return ERR_IO_PENDING
;
235 void ProxyResolverMojo::CancelRequest(RequestHandle request
) {
236 DCHECK(thread_checker_
.CalledOnValidThread());
237 Job
* job
= static_cast<Job
*>(request
);
243 LoadState
ProxyResolverMojo::GetLoadState(RequestHandle request
) const {
244 Job
* job
= static_cast<Job
*>(request
);
245 CHECK_EQ(1u, pending_jobs_
.count(job
));
246 return job
->load_state();