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 "net/base/net_errors.h"
12 #include "net/proxy/mock_proxy_resolver.h"
13 #include "net/proxy/mojo_proxy_type_converters.h"
14 #include "net/proxy/proxy_info.h"
15 #include "net/proxy/proxy_server.h"
16 #include "net/test/event_waiter.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
19 #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
24 class TestRequestClient
: public interfaces::ProxyResolverRequestClient
,
25 public mojo::ErrorHandler
{
33 explicit TestRequestClient(
34 mojo::InterfaceRequest
<interfaces::ProxyResolverRequestClient
> request
);
38 Error
error() { return error_
; }
39 const mojo::Array
<interfaces::ProxyServerPtr
>& results() { return results_
; }
40 LoadState
load_state() { return load_state_
; }
41 EventWaiter
<Event
>& event_waiter() { return event_waiter_
; }
44 // interfaces::ProxyResolverRequestClient override.
45 void ReportResult(int32_t error
,
46 mojo::Array
<interfaces::ProxyServerPtr
> results
) override
;
47 void LoadStateChanged(int32_t load_state
) override
;
49 // mojo::ErrorHandler override.
50 void OnConnectionError() override
;
53 Error error_
= ERR_FAILED
;
54 LoadState load_state_
= LOAD_STATE_IDLE
;
55 mojo::Array
<interfaces::ProxyServerPtr
> results_
;
57 mojo::Binding
<interfaces::ProxyResolverRequestClient
> binding_
;
59 EventWaiter
<Event
> event_waiter_
;
62 TestRequestClient::TestRequestClient(
63 mojo::InterfaceRequest
<interfaces::ProxyResolverRequestClient
> request
)
64 : binding_(this, request
.Pass()) {
65 binding_
.set_error_handler(this);
68 void TestRequestClient::WaitForResult() {
72 event_waiter_
.WaitForEvent(RESULT_RECEIVED
);
76 void TestRequestClient::ReportResult(
78 mojo::Array
<interfaces::ProxyServerPtr
> results
) {
79 event_waiter_
.NotifyEvent(RESULT_RECEIVED
);
81 error_
= static_cast<Error
>(error
);
82 results_
= results
.Pass();
86 void TestRequestClient::LoadStateChanged(int32_t load_state
) {
87 event_waiter_
.NotifyEvent(LOAD_STATE_CHANGED
);
88 load_state_
= static_cast<LoadState
>(load_state
);
91 void TestRequestClient::OnConnectionError() {
92 event_waiter_
.NotifyEvent(CONNECTION_ERROR
);
95 class CallbackMockProxyResolver
: public MockAsyncProxyResolver
{
97 CallbackMockProxyResolver() {}
98 ~CallbackMockProxyResolver() override
;
100 // MockAsyncProxyResolver overrides.
101 int GetProxyForURL(const GURL
& url
,
103 const CompletionCallback
& callback
,
104 RequestHandle
* request_handle
,
105 const BoundNetLog
& net_log
) override
;
106 void CancelRequest(RequestHandle request_handle
) override
;
108 // Wait until the mock resolver has received a CancelRequest call.
109 void WaitForCancel();
111 // Queues a proxy result to be returned synchronously.
112 void ReturnProxySynchronously(const ProxyInfo
& result
);
115 base::Closure cancel_callback_
;
116 scoped_ptr
<ProxyInfo
> sync_result_
;
119 CallbackMockProxyResolver::~CallbackMockProxyResolver() {
120 EXPECT_TRUE(pending_requests().empty());
123 int CallbackMockProxyResolver::GetProxyForURL(
126 const CompletionCallback
& callback
,
127 RequestHandle
* request_handle
,
128 const BoundNetLog
& net_log
) {
130 *results
= *sync_result_
;
131 sync_result_
.reset();
134 return MockAsyncProxyResolver::GetProxyForURL(url
, results
, callback
,
135 request_handle
, net_log
);
138 void CallbackMockProxyResolver::CancelRequest(RequestHandle request_handle
) {
139 MockAsyncProxyResolver::CancelRequest(request_handle
);
140 if (!cancel_callback_
.is_null()) {
141 cancel_callback_
.Run();
142 cancel_callback_
.Reset();
146 void CallbackMockProxyResolver::WaitForCancel() {
147 while (cancelled_requests().empty()) {
148 base::RunLoop run_loop
;
149 cancel_callback_
= run_loop
.QuitClosure();
154 void CallbackMockProxyResolver::ReturnProxySynchronously(
155 const ProxyInfo
& result
) {
156 sync_result_
.reset(new ProxyInfo(result
));
161 class MojoProxyResolverImplTest
: public testing::Test
{
163 void SetUp() override
{
164 scoped_ptr
<CallbackMockProxyResolver
> mock_resolver(
165 new CallbackMockProxyResolver
);
166 mock_proxy_resolver_
= mock_resolver
.get();
167 resolver_impl_
.reset(new MojoProxyResolverImpl(
168 mock_resolver
.Pass(),
169 base::Bind(&MojoProxyResolverImplTest::set_load_state_changed_callback
,
170 base::Unretained(this))));
171 resolver_
= resolver_impl_
.get();
174 void set_load_state_changed_callback(
175 const ProxyResolver::LoadStateChangedCallback
& callback
) {
176 EXPECT_TRUE(load_state_changed_callback_
.is_null());
177 EXPECT_FALSE(callback
.is_null());
178 load_state_changed_callback_
= callback
;
181 CallbackMockProxyResolver
* mock_proxy_resolver_
;
183 scoped_ptr
<MojoProxyResolverImpl
> resolver_impl_
;
184 interfaces::ProxyResolver
* resolver_
;
185 ProxyResolver::LoadStateChangedCallback load_state_changed_callback_
;
188 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrl
) {
189 interfaces::ProxyResolverRequestClientPtr client_ptr
;
190 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
192 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
193 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
194 scoped_refptr
<MockAsyncProxyResolver::Request
> request
=
195 mock_proxy_resolver_
->pending_requests()[0];
196 EXPECT_EQ(GURL("http://example.com"), request
->url());
198 ASSERT_FALSE(load_state_changed_callback_
.is_null());
199 load_state_changed_callback_
.Run(request
.get(),
200 LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
);
201 client
.event_waiter().WaitForEvent(TestRequestClient::LOAD_STATE_CHANGED
);
202 EXPECT_EQ(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
, client
.load_state());
204 request
->results()->UsePacString(
205 "PROXY proxy.example.com:1; "
206 "SOCKS4 socks4.example.com:2; "
207 "SOCKS5 socks5.example.com:3; "
208 "HTTPS https.example.com:4; "
209 "QUIC quic.example.com:65000; "
211 request
->CompleteNow(OK
);
212 client
.WaitForResult();
214 EXPECT_EQ(OK
, client
.error());
215 std::vector
<ProxyServer
> servers
=
216 client
.results().To
<std::vector
<ProxyServer
>>();
217 ASSERT_EQ(6u, servers
.size());
218 EXPECT_EQ(ProxyServer::SCHEME_HTTP
, servers
[0].scheme());
219 EXPECT_EQ("proxy.example.com", servers
[0].host_port_pair().host());
220 EXPECT_EQ(1, servers
[0].host_port_pair().port());
222 EXPECT_EQ(ProxyServer::SCHEME_SOCKS4
, servers
[1].scheme());
223 EXPECT_EQ("socks4.example.com", servers
[1].host_port_pair().host());
224 EXPECT_EQ(2, servers
[1].host_port_pair().port());
226 EXPECT_EQ(ProxyServer::SCHEME_SOCKS5
, servers
[2].scheme());
227 EXPECT_EQ("socks5.example.com", servers
[2].host_port_pair().host());
228 EXPECT_EQ(3, servers
[2].host_port_pair().port());
230 EXPECT_EQ(ProxyServer::SCHEME_HTTPS
, servers
[3].scheme());
231 EXPECT_EQ("https.example.com", servers
[3].host_port_pair().host());
232 EXPECT_EQ(4, servers
[3].host_port_pair().port());
234 EXPECT_EQ(ProxyServer::SCHEME_QUIC
, servers
[4].scheme());
235 EXPECT_EQ("quic.example.com", servers
[4].host_port_pair().host());
236 EXPECT_EQ(65000, servers
[4].host_port_pair().port());
238 EXPECT_EQ(ProxyServer::SCHEME_DIRECT
, servers
[5].scheme());
241 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrlSynchronous
) {
242 interfaces::ProxyResolverRequestClientPtr client_ptr
;
243 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
246 result
.UsePacString("DIRECT");
247 mock_proxy_resolver_
->ReturnProxySynchronously(result
);
248 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
249 ASSERT_EQ(0u, mock_proxy_resolver_
->pending_requests().size());
250 client
.WaitForResult();
252 EXPECT_EQ(OK
, client
.error());
253 std::vector
<ProxyServer
> proxy_servers
=
254 client
.results().To
<std::vector
<ProxyServer
>>();
255 ASSERT_EQ(1u, proxy_servers
.size());
256 ProxyServer
& server
= proxy_servers
[0];
257 EXPECT_TRUE(server
.is_direct());
260 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrlFailure
) {
261 interfaces::ProxyResolverRequestClientPtr client_ptr
;
262 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
264 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
265 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
266 scoped_refptr
<MockAsyncProxyResolver::Request
> request
=
267 mock_proxy_resolver_
->pending_requests()[0];
268 EXPECT_EQ(GURL("http://example.com"), request
->url());
269 request
->CompleteNow(ERR_FAILED
);
270 client
.WaitForResult();
272 EXPECT_EQ(ERR_FAILED
, client
.error());
273 std::vector
<ProxyServer
> proxy_servers
=
274 client
.results().To
<std::vector
<ProxyServer
>>();
275 EXPECT_TRUE(proxy_servers
.empty());
278 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrlMultiple
) {
279 interfaces::ProxyResolverRequestClientPtr client_ptr1
;
280 TestRequestClient
client1(mojo::GetProxy(&client_ptr1
));
281 interfaces::ProxyResolverRequestClientPtr client_ptr2
;
282 TestRequestClient
client2(mojo::GetProxy(&client_ptr2
));
284 resolver_
->GetProxyForUrl("http://example.com", client_ptr1
.Pass());
285 resolver_
->GetProxyForUrl("https://example.com", client_ptr2
.Pass());
286 ASSERT_EQ(2u, mock_proxy_resolver_
->pending_requests().size());
287 scoped_refptr
<MockAsyncProxyResolver::Request
> request1
=
288 mock_proxy_resolver_
->pending_requests()[0];
289 EXPECT_EQ(GURL("http://example.com"), request1
->url());
290 scoped_refptr
<MockAsyncProxyResolver::Request
> request2
=
291 mock_proxy_resolver_
->pending_requests()[1];
292 EXPECT_EQ(GURL("https://example.com"), request2
->url());
293 request1
->results()->UsePacString("HTTPS proxy.example.com:12345");
294 request1
->CompleteNow(OK
);
295 request2
->results()->UsePacString("SOCKS5 another-proxy.example.com:6789");
296 request2
->CompleteNow(OK
);
297 client1
.WaitForResult();
298 client2
.WaitForResult();
300 EXPECT_EQ(OK
, client1
.error());
301 std::vector
<ProxyServer
> proxy_servers1
=
302 client1
.results().To
<std::vector
<ProxyServer
>>();
303 ASSERT_EQ(1u, proxy_servers1
.size());
304 ProxyServer
& server1
= proxy_servers1
[0];
305 EXPECT_EQ(ProxyServer::SCHEME_HTTPS
, server1
.scheme());
306 EXPECT_EQ("proxy.example.com", server1
.host_port_pair().host());
307 EXPECT_EQ(12345, server1
.host_port_pair().port());
309 EXPECT_EQ(OK
, client2
.error());
310 std::vector
<ProxyServer
> proxy_servers2
=
311 client2
.results().To
<std::vector
<ProxyServer
>>();
312 ASSERT_EQ(1u, proxy_servers1
.size());
313 ProxyServer
& server2
= proxy_servers2
[0];
314 EXPECT_EQ(ProxyServer::SCHEME_SOCKS5
, server2
.scheme());
315 EXPECT_EQ("another-proxy.example.com", server2
.host_port_pair().host());
316 EXPECT_EQ(6789, server2
.host_port_pair().port());
319 TEST_F(MojoProxyResolverImplTest
, DestroyClient
) {
320 interfaces::ProxyResolverRequestClientPtr client_ptr
;
321 scoped_ptr
<TestRequestClient
> client(
322 new TestRequestClient(mojo::GetProxy(&client_ptr
)));
324 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
325 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
326 scoped_refptr
<MockAsyncProxyResolver::Request
> request
=
327 mock_proxy_resolver_
->pending_requests()[0];
328 EXPECT_EQ(GURL("http://example.com"), request
->url());
329 request
->results()->UsePacString("PROXY proxy.example.com:8080");
331 mock_proxy_resolver_
->WaitForCancel();
334 TEST_F(MojoProxyResolverImplTest
, DestroyService
) {
335 interfaces::ProxyResolverRequestClientPtr client_ptr
;
336 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
338 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
339 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
340 scoped_refptr
<MockAsyncProxyResolver::Request
> request
=
341 mock_proxy_resolver_
->pending_requests()[0];
342 resolver_impl_
.reset();
343 client
.event_waiter().WaitForEvent(TestRequestClient::CONNECTION_ERROR
);