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_resolver_v8_tracing.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"
24 class TestRequestClient
: public interfaces::ProxyResolverRequestClient
{
31 explicit TestRequestClient(
32 mojo::InterfaceRequest
<interfaces::ProxyResolverRequestClient
> request
);
36 Error
error() { return error_
; }
37 const mojo::Array
<interfaces::ProxyServerPtr
>& results() { return results_
; }
38 EventWaiter
<Event
>& event_waiter() { return event_waiter_
; }
41 // interfaces::ProxyResolverRequestClient override.
42 void ReportResult(int32_t error
,
43 mojo::Array
<interfaces::ProxyServerPtr
> results
) override
;
44 void Alert(const mojo::String
& message
) override
;
45 void OnError(int32_t line_number
, const mojo::String
& message
) override
;
46 void ResolveDns(interfaces::HostResolverRequestInfoPtr request_info
,
47 interfaces::HostResolverRequestClientPtr client
) override
;
49 // Mojo error handler.
50 void OnConnectionError();
53 Error error_
= ERR_FAILED
;
54 mojo::Array
<interfaces::ProxyServerPtr
> results_
;
56 mojo::Binding
<interfaces::ProxyResolverRequestClient
> binding_
;
58 EventWaiter
<Event
> event_waiter_
;
61 TestRequestClient::TestRequestClient(
62 mojo::InterfaceRequest
<interfaces::ProxyResolverRequestClient
> request
)
63 : binding_(this, request
.Pass()) {
64 binding_
.set_connection_error_handler(base::Bind(
65 &TestRequestClient::OnConnectionError
, base::Unretained(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::Alert(const mojo::String
& message
) {
89 void TestRequestClient::OnError(int32_t line_number
,
90 const mojo::String
& message
) {
93 void TestRequestClient::ResolveDns(
94 interfaces::HostResolverRequestInfoPtr request_info
,
95 interfaces::HostResolverRequestClientPtr client
) {
98 void TestRequestClient::OnConnectionError() {
99 event_waiter_
.NotifyEvent(CONNECTION_ERROR
);
102 class MockProxyResolverV8Tracing
: public ProxyResolverV8Tracing
{
107 CompletionCallback callback
;
108 bool cancelled
= false;
110 MockProxyResolverV8Tracing() {}
112 // ProxyResolverV8Tracing overrides.
113 void GetProxyForURL(const GURL
& url
,
115 const CompletionCallback
& callback
,
116 ProxyResolver::RequestHandle
* request
,
117 scoped_ptr
<Bindings
> bindings
) override
;
118 void CancelRequest(ProxyResolver::RequestHandle request_handle
) override
;
119 LoadState
GetLoadState(ProxyResolver::RequestHandle request
) const override
;
121 // Wait until the mock resolver has received a CancelRequest call.
122 void WaitForCancel();
124 const std::vector
<Request
>& pending_requests() { return pending_requests_
; }
127 base::Closure cancel_callback_
;
128 std::vector
<Request
> pending_requests_
;
131 void MockProxyResolverV8Tracing::GetProxyForURL(
134 const CompletionCallback
& callback
,
135 ProxyResolver::RequestHandle
* request
,
136 scoped_ptr
<Bindings
> bindings
) {
137 pending_requests_
.push_back(Request());
138 auto& pending_request
= pending_requests_
.back();
139 pending_request
.url
= url
;
140 pending_request
.results
= results
;
141 pending_request
.callback
= callback
;
143 reinterpret_cast<ProxyResolver::RequestHandle
>(pending_requests_
.size());
146 void MockProxyResolverV8Tracing::CancelRequest(
147 ProxyResolver::RequestHandle request_handle
) {
148 size_t id
= reinterpret_cast<size_t>(request_handle
) - 1;
149 pending_requests_
[id
].cancelled
= true;
150 if (!cancel_callback_
.is_null()) {
151 cancel_callback_
.Run();
152 cancel_callback_
.Reset();
156 LoadState
MockProxyResolverV8Tracing::GetLoadState(
157 ProxyResolver::RequestHandle request
) const {
158 return LOAD_STATE_RESOLVING_PROXY_FOR_URL
;
161 void MockProxyResolverV8Tracing::WaitForCancel() {
162 while (std::find_if(pending_requests_
.begin(), pending_requests_
.end(),
163 [](const Request
& request
) {
164 return request
.cancelled
;
165 }) != pending_requests_
.end()) {
166 base::RunLoop run_loop
;
167 cancel_callback_
= run_loop
.QuitClosure();
174 class MojoProxyResolverImplTest
: public testing::Test
{
176 void SetUp() override
{
177 scoped_ptr
<MockProxyResolverV8Tracing
> mock_resolver(
178 new MockProxyResolverV8Tracing
);
179 mock_proxy_resolver_
= mock_resolver
.get();
180 resolver_impl_
.reset(new MojoProxyResolverImpl(mock_resolver
.Pass()));
181 resolver_
= resolver_impl_
.get();
184 MockProxyResolverV8Tracing
* mock_proxy_resolver_
;
186 scoped_ptr
<MojoProxyResolverImpl
> resolver_impl_
;
187 interfaces::ProxyResolver
* resolver_
;
190 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrl
) {
191 interfaces::ProxyResolverRequestClientPtr client_ptr
;
192 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
194 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
195 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
196 const MockProxyResolverV8Tracing::Request
& request
=
197 mock_proxy_resolver_
->pending_requests()[0];
198 EXPECT_EQ(GURL("http://example.com"), request
.url
);
200 request
.results
->UsePacString(
201 "PROXY proxy.example.com:1; "
202 "SOCKS4 socks4.example.com:2; "
203 "SOCKS5 socks5.example.com:3; "
204 "HTTPS https.example.com:4; "
205 "QUIC quic.example.com:65000; "
207 request
.callback
.Run(OK
);
208 client
.WaitForResult();
210 EXPECT_EQ(OK
, client
.error());
211 std::vector
<ProxyServer
> servers
=
212 client
.results().To
<std::vector
<ProxyServer
>>();
213 ASSERT_EQ(6u, servers
.size());
214 EXPECT_EQ(ProxyServer::SCHEME_HTTP
, servers
[0].scheme());
215 EXPECT_EQ("proxy.example.com", servers
[0].host_port_pair().host());
216 EXPECT_EQ(1, servers
[0].host_port_pair().port());
218 EXPECT_EQ(ProxyServer::SCHEME_SOCKS4
, servers
[1].scheme());
219 EXPECT_EQ("socks4.example.com", servers
[1].host_port_pair().host());
220 EXPECT_EQ(2, servers
[1].host_port_pair().port());
222 EXPECT_EQ(ProxyServer::SCHEME_SOCKS5
, servers
[2].scheme());
223 EXPECT_EQ("socks5.example.com", servers
[2].host_port_pair().host());
224 EXPECT_EQ(3, servers
[2].host_port_pair().port());
226 EXPECT_EQ(ProxyServer::SCHEME_HTTPS
, servers
[3].scheme());
227 EXPECT_EQ("https.example.com", servers
[3].host_port_pair().host());
228 EXPECT_EQ(4, servers
[3].host_port_pair().port());
230 EXPECT_EQ(ProxyServer::SCHEME_QUIC
, servers
[4].scheme());
231 EXPECT_EQ("quic.example.com", servers
[4].host_port_pair().host());
232 EXPECT_EQ(65000, servers
[4].host_port_pair().port());
234 EXPECT_EQ(ProxyServer::SCHEME_DIRECT
, servers
[5].scheme());
237 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrlFailure
) {
238 interfaces::ProxyResolverRequestClientPtr client_ptr
;
239 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
241 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
242 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
243 const MockProxyResolverV8Tracing::Request
& request
=
244 mock_proxy_resolver_
->pending_requests()[0];
245 EXPECT_EQ(GURL("http://example.com"), request
.url
);
246 request
.callback
.Run(ERR_FAILED
);
247 client
.WaitForResult();
249 EXPECT_EQ(ERR_FAILED
, client
.error());
250 std::vector
<ProxyServer
> proxy_servers
=
251 client
.results().To
<std::vector
<ProxyServer
>>();
252 EXPECT_TRUE(proxy_servers
.empty());
255 TEST_F(MojoProxyResolverImplTest
, GetProxyForUrlMultiple
) {
256 interfaces::ProxyResolverRequestClientPtr client_ptr1
;
257 TestRequestClient
client1(mojo::GetProxy(&client_ptr1
));
258 interfaces::ProxyResolverRequestClientPtr client_ptr2
;
259 TestRequestClient
client2(mojo::GetProxy(&client_ptr2
));
261 resolver_
->GetProxyForUrl("http://example.com", client_ptr1
.Pass());
262 resolver_
->GetProxyForUrl("https://example.com", client_ptr2
.Pass());
263 ASSERT_EQ(2u, mock_proxy_resolver_
->pending_requests().size());
264 const MockProxyResolverV8Tracing::Request
& request1
=
265 mock_proxy_resolver_
->pending_requests()[0];
266 EXPECT_EQ(GURL("http://example.com"), request1
.url
);
267 const MockProxyResolverV8Tracing::Request
& request2
=
268 mock_proxy_resolver_
->pending_requests()[1];
269 EXPECT_EQ(GURL("https://example.com"), request2
.url
);
270 request1
.results
->UsePacString("HTTPS proxy.example.com:12345");
271 request1
.callback
.Run(OK
);
272 request2
.results
->UsePacString("SOCKS5 another-proxy.example.com:6789");
273 request2
.callback
.Run(OK
);
274 client1
.WaitForResult();
275 client2
.WaitForResult();
277 EXPECT_EQ(OK
, client1
.error());
278 std::vector
<ProxyServer
> proxy_servers1
=
279 client1
.results().To
<std::vector
<ProxyServer
>>();
280 ASSERT_EQ(1u, proxy_servers1
.size());
281 ProxyServer
& server1
= proxy_servers1
[0];
282 EXPECT_EQ(ProxyServer::SCHEME_HTTPS
, server1
.scheme());
283 EXPECT_EQ("proxy.example.com", server1
.host_port_pair().host());
284 EXPECT_EQ(12345, server1
.host_port_pair().port());
286 EXPECT_EQ(OK
, client2
.error());
287 std::vector
<ProxyServer
> proxy_servers2
=
288 client2
.results().To
<std::vector
<ProxyServer
>>();
289 ASSERT_EQ(1u, proxy_servers1
.size());
290 ProxyServer
& server2
= proxy_servers2
[0];
291 EXPECT_EQ(ProxyServer::SCHEME_SOCKS5
, server2
.scheme());
292 EXPECT_EQ("another-proxy.example.com", server2
.host_port_pair().host());
293 EXPECT_EQ(6789, server2
.host_port_pair().port());
296 TEST_F(MojoProxyResolverImplTest
, DestroyClient
) {
297 interfaces::ProxyResolverRequestClientPtr client_ptr
;
298 scoped_ptr
<TestRequestClient
> client(
299 new TestRequestClient(mojo::GetProxy(&client_ptr
)));
301 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
302 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
303 const MockProxyResolverV8Tracing::Request
& request
=
304 mock_proxy_resolver_
->pending_requests()[0];
305 EXPECT_EQ(GURL("http://example.com"), request
.url
);
306 request
.results
->UsePacString("PROXY proxy.example.com:8080");
308 mock_proxy_resolver_
->WaitForCancel();
311 TEST_F(MojoProxyResolverImplTest
, DestroyService
) {
312 interfaces::ProxyResolverRequestClientPtr client_ptr
;
313 TestRequestClient
client(mojo::GetProxy(&client_ptr
));
315 resolver_
->GetProxyForUrl("http://example.com", client_ptr
.Pass());
316 ASSERT_EQ(1u, mock_proxy_resolver_
->pending_requests().size());
317 resolver_impl_
.reset();
318 client
.event_waiter().WaitForEvent(TestRequestClient::CONNECTION_ERROR
);