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/mojo_proxy_resolver_impl.h"
10 #include "base/run_loop.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "net/base/net_errors.h"
13 #include "net/proxy/mock_proxy_resolver.h"
14 #include "net/proxy/mojo_proxy_type_converters.h"
15 #include "net/proxy/proxy_info.h"
16 #include "net/proxy/proxy_server.h"
17 #include "net/test/event_waiter.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
20 #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
25 class TestRequestClient
: public interfaces::ProxyResolverRequestClient
,
26 public mojo::ErrorHandler
{
34 explicit TestRequestClient(
35 mojo::InterfaceRequest
<interfaces::ProxyResolverRequestClient
> request
);
39 Error
error() { return error_
; }
40 const mojo::Array
<interfaces::ProxyServerPtr
>& results() { return results_
; }
41 LoadState
load_state() { return load_state_
; }
42 EventWaiter
<Event
>& event_waiter() { return event_waiter_
; }
45 // interfaces::ProxyResolverRequestClient override.
46 void ReportResult(int32_t error
,
47 mojo::Array
<interfaces::ProxyServerPtr
> results
) override
;
48 void LoadStateChanged(int32_t load_state
) override
;
50 // mojo::ErrorHandler override.
51 void OnConnectionError() override
;
54 Error error_
= ERR_FAILED
;
55 LoadState load_state_
= LOAD_STATE_IDLE
;
56 mojo::Array
<interfaces::ProxyServerPtr
> results_
;
58 mojo::Binding
<interfaces::ProxyResolverRequestClient
> binding_
;
60 EventWaiter
<Event
> event_waiter_
;
63 TestRequestClient::TestRequestClient(
64 mojo::InterfaceRequest
<interfaces::ProxyResolverRequestClient
> request
)
65 : binding_(this, request
.Pass()) {
66 binding_
.set_error_handler(this);
69 void TestRequestClient::WaitForResult() {
73 event_waiter_
.WaitForEvent(RESULT_RECEIVED
);
77 void TestRequestClient::ReportResult(
79 mojo::Array
<interfaces::ProxyServerPtr
> results
) {
80 event_waiter_
.NotifyEvent(RESULT_RECEIVED
);
82 error_
= static_cast<Error
>(error
);
83 results_
= results
.Pass();
87 void TestRequestClient::LoadStateChanged(int32_t load_state
) {
88 event_waiter_
.NotifyEvent(LOAD_STATE_CHANGED
);
89 load_state_
= static_cast<LoadState
>(load_state
);
92 void TestRequestClient::OnConnectionError() {
93 event_waiter_
.NotifyEvent(CONNECTION_ERROR
);
96 class SetPacScriptClient
{
98 base::Callback
<void(int32_t)> CreateCallback();
99 Error
error() { return error_
; }
102 void ReportResult(int32_t error
);
104 Error error_
= ERR_FAILED
;
107 base::Callback
<void(int32_t)> SetPacScriptClient::CreateCallback() {
108 return base::Bind(&SetPacScriptClient::ReportResult
, base::Unretained(this));
111 void SetPacScriptClient::ReportResult(int32_t error
) {
112 error_
= static_cast<Error
>(error
);
115 class CallbackMockProxyResolver
: public MockAsyncProxyResolverExpectsBytes
{
117 CallbackMockProxyResolver() {}
118 ~CallbackMockProxyResolver() override
;
120 // MockAsyncProxyResolverExpectsBytes overrides.
121 int GetProxyForURL(const GURL
& url
,
123 const net::CompletionCallback
& callback
,
124 RequestHandle
* request_handle
,
125 const BoundNetLog
& net_log
) override
;
126 void CancelRequest(RequestHandle request_handle
) override
;
127 int SetPacScript(const scoped_refptr
<ProxyResolverScriptData
>& script_data
,
128 const net::CompletionCallback
& callback
) override
;
130 // Wait until the mock resolver has received a CancelRequest call.
131 void WaitForCancel();
133 // Queues a proxy result to be returned synchronously.
134 void ReturnProxySynchronously(const ProxyInfo
& result
);
136 // Queues a SetPacScript to be completed synchronously.
137 void CompleteSetPacScriptSynchronously();
140 base::Closure cancel_callback_
;
141 scoped_ptr
<ProxyInfo
> sync_result_
;
142 bool set_pac_script_sync_
= false;
145 CallbackMockProxyResolver::~CallbackMockProxyResolver() {
146 EXPECT_TRUE(pending_requests().empty());
149 int CallbackMockProxyResolver::GetProxyForURL(
152 const net::CompletionCallback
& callback
,
153 RequestHandle
* request_handle
,
154 const BoundNetLog
& net_log
) {
156 *results
= *sync_result_
;
157 sync_result_
.reset();
160 return MockAsyncProxyResolverExpectsBytes::GetProxyForURL(
161 url
, results
, callback
, request_handle
, net_log
);
164 void CallbackMockProxyResolver::CancelRequest(RequestHandle request_handle
) {
165 MockAsyncProxyResolverExpectsBytes::CancelRequest(request_handle
);
166 if (!cancel_callback_
.is_null()) {
167 cancel_callback_
.Run();
168 cancel_callback_
.Reset();
172 int CallbackMockProxyResolver::SetPacScript(
173 const scoped_refptr
<ProxyResolverScriptData
>& script_data
,
174 const net::CompletionCallback
& callback
) {
175 if (set_pac_script_sync_
) {
176 set_pac_script_sync_
= false;
179 return MockAsyncProxyResolverExpectsBytes::SetPacScript(script_data
,
183 void CallbackMockProxyResolver::WaitForCancel() {
184 while (cancelled_requests().empty()) {
185 base::RunLoop run_loop
;
186 cancel_callback_
= run_loop
.QuitClosure();
191 void CallbackMockProxyResolver::ReturnProxySynchronously(
192 const ProxyInfo
& result
) {
193 sync_result_
.reset(new ProxyInfo(result
));
196 void CallbackMockProxyResolver::CompleteSetPacScriptSynchronously() {
197 set_pac_script_sync_
= true;
200 void Fail(int32_t error
) {
201 FAIL() << "Unexpected callback with error: " << error
;
206 class MojoProxyResolverImplTest
: public testing::Test
{
208 void SetUp() override
{
209 scoped_ptr
<CallbackMockProxyResolver
> mock_resolver(
210 new CallbackMockProxyResolver
);
211 mock_proxy_resolver_
= mock_resolver
.get();
212 resolver_impl_
.reset(new MojoProxyResolverImpl(mock_resolver
.Pass()));
213 resolver_
= resolver_impl_
.get();
216 CallbackMockProxyResolver
* mock_proxy_resolver_
;
218 scoped_ptr
<MojoProxyResolverImpl
> resolver_impl_
;
219 interfaces::ProxyResolver
* resolver_
;
222 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrl
) {
223 interfaces::ProxyResolverRequestClientPtr client_ptr
;
224 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
226 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
227 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
228 scoped_refptr
<MockAsyncProxyResolverBase::Request
> request
=
229 mock_proxy_resolver_
->pending_requests()[0];
230 EXPECT_EQ(GURL("http://example.com"), request
->url());
232 resolver_impl_
->LoadStateChanged(request
.get(),
233 LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
);
234 client
.event_waiter().WaitForEvent(TestRequestClient::LOAD_STATE_CHANGED
);
235 EXPECT_EQ(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
, client
.load_state());
237 request
->results()->UsePacString(
238 "PROXY proxy.example.com:1; "
239 "SOCKS4 socks4.example.com:2; "
240 "SOCKS5 socks5.example.com:3; "
241 "HTTPS https.example.com:4; "
242 "QUIC quic.example.com:65000; "
244 request
->CompleteNow(OK
);
245 client
.WaitForResult();
247 EXPECT_EQ(net::OK
, client
.error());
248 std::vector
<net::ProxyServer
> servers
=
249 client
.results().To
<std::vector
<net::ProxyServer
>>();
250 ASSERT_EQ(6u, servers
.size());
251 EXPECT_EQ(ProxyServer::SCHEME_HTTP
, servers
[0].scheme());
252 EXPECT_EQ("proxy.example.com", servers
[0].host_port_pair().host());
253 EXPECT_EQ(1, servers
[0].host_port_pair().port());
255 EXPECT_EQ(ProxyServer::SCHEME_SOCKS4
, servers
[1].scheme());
256 EXPECT_EQ("socks4.example.com", servers
[1].host_port_pair().host());
257 EXPECT_EQ(2, servers
[1].host_port_pair().port());
259 EXPECT_EQ(ProxyServer::SCHEME_SOCKS5
, servers
[2].scheme());
260 EXPECT_EQ("socks5.example.com", servers
[2].host_port_pair().host());
261 EXPECT_EQ(3, servers
[2].host_port_pair().port());
263 EXPECT_EQ(ProxyServer::SCHEME_HTTPS
, servers
[3].scheme());
264 EXPECT_EQ("https.example.com", servers
[3].host_port_pair().host());
265 EXPECT_EQ(4, servers
[3].host_port_pair().port());
267 EXPECT_EQ(ProxyServer::SCHEME_QUIC
, servers
[4].scheme());
268 EXPECT_EQ("quic.example.com", servers
[4].host_port_pair().host());
269 EXPECT_EQ(65000, servers
[4].host_port_pair().port());
271 EXPECT_EQ(ProxyServer::SCHEME_DIRECT
, servers
[5].scheme());
274 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrlSynchronous
) {
275 interfaces::ProxyResolverRequestClientPtr client_ptr
;
276 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
279 result
.UsePacString("DIRECT");
280 mock_proxy_resolver_
->ReturnProxySynchronously(result
);
281 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
282 ASSERT_EQ(0u, mock_proxy_resolver_
->pending_requests().size());
283 client
.WaitForResult();
285 EXPECT_EQ(net::OK
, client
.error());
286 std::vector
<net::ProxyServer
> proxy_servers
=
287 client
.results().To
<std::vector
<net::ProxyServer
>>();
288 ASSERT_EQ(1u, proxy_servers
.size());
289 net::ProxyServer
& server
= proxy_servers
[0];
290 EXPECT_TRUE(server
.is_direct());
293 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrlFailure
) {
294 interfaces::ProxyResolverRequestClientPtr client_ptr
;
295 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
297 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
298 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
299 scoped_refptr
<MockAsyncProxyResolverBase::Request
> request
=
300 mock_proxy_resolver_
->pending_requests()[0];
301 EXPECT_EQ(GURL("http://example.com"), request
->url());
302 request
->CompleteNow(ERR_FAILED
);
303 client
.WaitForResult();
305 EXPECT_EQ(ERR_FAILED
, client
.error());
306 std::vector
<net::ProxyServer
> proxy_servers
=
307 client
.results().To
<std::vector
<net::ProxyServer
>>();
308 EXPECT_TRUE(proxy_servers
.empty());
311 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrlMultiple
) {
312 interfaces::ProxyResolverRequestClientPtr client_ptr1
;
313 TestRequestClient
client1(mojo::GetProxy(&client_ptr1
));
314 interfaces::ProxyResolverRequestClientPtr client_ptr2
;
315 TestRequestClient
client2(mojo::GetProxy(&client_ptr2
));
317 resolver_
->GetProxyForUrl("http://example.com", client_ptr1
.Pass());
318 resolver_
->GetProxyForUrl("https://example.com", client_ptr2
.Pass());
319 ASSERT_EQ(2u, mock_proxy_resolver_
->pending_requests().size());
320 scoped_refptr
<MockAsyncProxyResolverBase::Request
> request1
=
321 mock_proxy_resolver_
->pending_requests()[0];
322 EXPECT_EQ(GURL("http://example.com"), request1
->url());
323 scoped_refptr
<MockAsyncProxyResolverBase::Request
> request2
=
324 mock_proxy_resolver_
->pending_requests()[1];
325 EXPECT_EQ(GURL("https://example.com"), request2
->url());
326 request1
->results()->UsePacString("HTTPS proxy.example.com:12345");
327 request1
->CompleteNow(OK
);
328 request2
->results()->UsePacString("SOCKS5 another-proxy.example.com:6789");
329 request2
->CompleteNow(OK
);
330 client1
.WaitForResult();
331 client2
.WaitForResult();
333 EXPECT_EQ(net::OK
, client1
.error());
334 std::vector
<net::ProxyServer
> proxy_servers1
=
335 client1
.results().To
<std::vector
<net::ProxyServer
>>();
336 ASSERT_EQ(1u, proxy_servers1
.size());
337 net::ProxyServer
& server1
= proxy_servers1
[0];
338 EXPECT_EQ(ProxyServer::SCHEME_HTTPS
, server1
.scheme());
339 EXPECT_EQ("proxy.example.com", server1
.host_port_pair().host());
340 EXPECT_EQ(12345, server1
.host_port_pair().port());
342 EXPECT_EQ(net::OK
, client2
.error());
343 std::vector
<net::ProxyServer
> proxy_servers2
=
344 client2
.results().To
<std::vector
<net::ProxyServer
>>();
345 ASSERT_EQ(1u, proxy_servers1
.size());
346 net::ProxyServer
& server2
= proxy_servers2
[0];
347 EXPECT_EQ(ProxyServer::SCHEME_SOCKS5
, server2
.scheme());
348 EXPECT_EQ("another-proxy.example.com", server2
.host_port_pair().host());
349 EXPECT_EQ(6789, server2
.host_port_pair().port());
352 TEST_F(MojoProxyResolverImplTest
, SetPacScript
) {
353 SetPacScriptClient client
;
355 resolver_
->SetPacScript("pac script", client
.CreateCallback());
356 MockAsyncProxyResolverBase::SetPacScriptRequest
* request
=
357 mock_proxy_resolver_
->pending_set_pac_script_request();
358 ASSERT_TRUE(request
);
359 EXPECT_EQ("pac script", base::UTF16ToUTF8(request
->script_data()->utf16()));
360 request
->CompleteNow(OK
);
361 EXPECT_EQ(OK
, client
.error());
364 TEST_F(MojoProxyResolverImplTest
, SetPacScriptSynchronous
) {
365 SetPacScriptClient client
;
367 mock_proxy_resolver_
->CompleteSetPacScriptSynchronously();
368 resolver_
->SetPacScript("pac script", client
.CreateCallback());
369 EXPECT_FALSE(mock_proxy_resolver_
->pending_set_pac_script_request());
370 EXPECT_EQ(OK
, client
.error());
373 TEST_F(MojoProxyResolverImplTest
, SetPacScriptMultiple
) {
374 SetPacScriptClient client1
;
375 SetPacScriptClient client2
;
377 resolver_
->SetPacScript("pac script", client1
.CreateCallback());
378 resolver_
->SetPacScript("a different pac script", client2
.CreateCallback());
379 MockAsyncProxyResolverBase::SetPacScriptRequest
* request
=
380 mock_proxy_resolver_
->pending_set_pac_script_request();
381 ASSERT_TRUE(request
);
382 EXPECT_EQ("pac script", base::UTF16ToUTF8(request
->script_data()->utf16()));
383 request
->CompleteNow(OK
);
384 EXPECT_EQ(OK
, client1
.error());
386 request
= mock_proxy_resolver_
->pending_set_pac_script_request();
387 ASSERT_TRUE(request
);
388 EXPECT_EQ("a different pac script",
389 base::UTF16ToUTF8(request
->script_data()->utf16()));
390 request
->CompleteNow(ERR_PAC_SCRIPT_FAILED
);
391 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, client2
.error());
394 TEST_F(MojoProxyResolverImplTest
, DestroyClient
) {
395 interfaces::ProxyResolverRequestClientPtr client_ptr
;
396 scoped_ptr
<TestRequestClient
> client(
397 new TestRequestClient(mojo::GetProxy(&client_ptr
)));
399 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
400 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
401 scoped_refptr
<MockAsyncProxyResolverBase::Request
> request
=
402 mock_proxy_resolver_
->pending_requests()[0];
403 EXPECT_EQ(GURL("http://example.com"), request
->url());
404 request
->results()->UsePacString("PROXY proxy.example.com:8080");
406 mock_proxy_resolver_
->WaitForCancel();
409 TEST_F(MojoProxyResolverImplTest
, DestroyService
) {
410 interfaces::ProxyResolverRequestClientPtr client_ptr
;
411 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
413 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
414 resolver_
->SetPacScript("pac script", base::Bind(&Fail
));
415 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
416 scoped_refptr
<MockAsyncProxyResolverBase::Request
> request
=
417 mock_proxy_resolver_
->pending_requests()[0];
418 resolver_impl_
.reset();
419 client
.event_waiter().WaitForEvent(TestRequestClient::CONNECTION_ERROR
);