OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "net/proxy/mojo_proxy_resolver_impl.h" |
| 6 |
| 7 #include <string> |
| 8 #include <vector> |
| 9 |
| 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_type_converters.h" |
| 15 #include "net/proxy/proxy_info.h" |
| 16 #include "net/proxy/proxy_server.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" |
| 20 |
| 21 namespace net { |
| 22 namespace { |
| 23 |
| 24 class TestRequestClient : public interfaces::ProxyResolverRequestClient, |
| 25 public mojo::ErrorHandler { |
| 26 public: |
| 27 explicit TestRequestClient( |
| 28 mojo::InterfaceRequest<interfaces::ProxyResolverRequestClient> request); |
| 29 |
| 30 void WaitForResult(); |
| 31 void WaitForConnectionError(); |
| 32 |
| 33 Error error() { return error_; } |
| 34 const mojo::Array<interfaces::ProxyServerPtr>& results() { return results_; } |
| 35 |
| 36 private: |
| 37 // interfaces::ProxyResolverRequestClient override. |
| 38 void ReportResult(int32_t error, |
| 39 mojo::Array<interfaces::ProxyServerPtr> results) override; |
| 40 |
| 41 // mojo::ErrorHandler override. |
| 42 void OnConnectionError() override; |
| 43 |
| 44 bool done_ = false; |
| 45 bool encountered_connection_error_ = false; |
| 46 Error error_ = ERR_FAILED; |
| 47 mojo::Array<interfaces::ProxyServerPtr> results_; |
| 48 base::Closure run_loop_quit_closure_; |
| 49 base::Closure connection_error_callback_; |
| 50 |
| 51 mojo::Binding<interfaces::ProxyResolverRequestClient> binding_; |
| 52 }; |
| 53 |
| 54 TestRequestClient::TestRequestClient( |
| 55 mojo::InterfaceRequest<interfaces::ProxyResolverRequestClient> request) |
| 56 : binding_(this, request.Pass()) { |
| 57 binding_.set_error_handler(this); |
| 58 } |
| 59 |
| 60 void TestRequestClient::WaitForResult() { |
| 61 if (done_) |
| 62 return; |
| 63 |
| 64 base::RunLoop run_loop; |
| 65 run_loop_quit_closure_ = run_loop.QuitClosure(); |
| 66 run_loop.Run(); |
| 67 ASSERT_TRUE(done_); |
| 68 } |
| 69 |
| 70 void TestRequestClient::WaitForConnectionError() { |
| 71 if (encountered_connection_error_) |
| 72 return; |
| 73 |
| 74 base::RunLoop run_loop; |
| 75 connection_error_callback_ = run_loop.QuitClosure(); |
| 76 run_loop.Run(); |
| 77 ASSERT_TRUE(encountered_connection_error_); |
| 78 } |
| 79 |
| 80 void TestRequestClient::ReportResult( |
| 81 int32_t error, |
| 82 mojo::Array<interfaces::ProxyServerPtr> results) { |
| 83 if (!run_loop_quit_closure_.is_null()) { |
| 84 run_loop_quit_closure_.Run(); |
| 85 } |
| 86 ASSERT_FALSE(done_); |
| 87 error_ = static_cast<Error>(error); |
| 88 results_ = results.Pass(); |
| 89 done_ = true; |
| 90 } |
| 91 |
| 92 void TestRequestClient::OnConnectionError() { |
| 93 if (!connection_error_callback_.is_null()) |
| 94 connection_error_callback_.Run(); |
| 95 encountered_connection_error_ = true; |
| 96 } |
| 97 |
| 98 class SetPacScriptClient { |
| 99 public: |
| 100 base::Callback<void(int32_t)> CreateCallback(); |
| 101 Error error() { return error_; } |
| 102 |
| 103 private: |
| 104 void ReportResult(int32_t error); |
| 105 |
| 106 Error error_ = ERR_FAILED; |
| 107 }; |
| 108 |
| 109 base::Callback<void(int32_t)> SetPacScriptClient::CreateCallback() { |
| 110 return base::Bind(&SetPacScriptClient::ReportResult, base::Unretained(this)); |
| 111 } |
| 112 |
| 113 void SetPacScriptClient::ReportResult(int32_t error) { |
| 114 error_ = static_cast<Error>(error); |
| 115 } |
| 116 |
| 117 class CallbackMockProxyResolver : public MockAsyncProxyResolverExpectsBytes { |
| 118 public: |
| 119 CallbackMockProxyResolver() {} |
| 120 ~CallbackMockProxyResolver() override; |
| 121 |
| 122 // MockAsyncProxyResolverExpectsBytes overrides. |
| 123 int GetProxyForURL(const GURL& url, |
| 124 ProxyInfo* results, |
| 125 const net::CompletionCallback& callback, |
| 126 RequestHandle* request_handle, |
| 127 const BoundNetLog& net_log) override; |
| 128 void CancelRequest(RequestHandle request_handle) override; |
| 129 int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& script_data, |
| 130 const net::CompletionCallback& callback) override; |
| 131 |
| 132 // Wait until the mock resolver has received a CancelRequest call. |
| 133 void WaitForCancel(); |
| 134 |
| 135 // Queues a proxy result to be returned synchronously. |
| 136 void ReturnProxySynchronously(const ProxyInfo& result); |
| 137 |
| 138 // Queues a SetPacScript to be completed synchronously. |
| 139 void CompleteSetPacScriptSynchronously(); |
| 140 |
| 141 private: |
| 142 base::Closure cancel_callback_; |
| 143 scoped_ptr<ProxyInfo> sync_result_; |
| 144 bool set_pac_script_sync_ = false; |
| 145 }; |
| 146 |
| 147 CallbackMockProxyResolver::~CallbackMockProxyResolver() { |
| 148 EXPECT_TRUE(pending_requests().empty()); |
| 149 } |
| 150 |
| 151 int CallbackMockProxyResolver::GetProxyForURL( |
| 152 const GURL& url, |
| 153 ProxyInfo* results, |
| 154 const net::CompletionCallback& callback, |
| 155 RequestHandle* request_handle, |
| 156 const BoundNetLog& net_log) { |
| 157 if (sync_result_) { |
| 158 *results = *sync_result_; |
| 159 sync_result_.reset(); |
| 160 return OK; |
| 161 } |
| 162 return MockAsyncProxyResolverExpectsBytes::GetProxyForURL( |
| 163 url, results, callback, request_handle, net_log); |
| 164 } |
| 165 |
| 166 void CallbackMockProxyResolver::CancelRequest(RequestHandle request_handle) { |
| 167 MockAsyncProxyResolverExpectsBytes::CancelRequest(request_handle); |
| 168 if (!cancel_callback_.is_null()) { |
| 169 cancel_callback_.Run(); |
| 170 cancel_callback_.Reset(); |
| 171 } |
| 172 } |
| 173 |
| 174 int CallbackMockProxyResolver::SetPacScript( |
| 175 const scoped_refptr<ProxyResolverScriptData>& script_data, |
| 176 const net::CompletionCallback& callback) { |
| 177 if (set_pac_script_sync_) { |
| 178 set_pac_script_sync_ = false; |
| 179 return OK; |
| 180 } |
| 181 return MockAsyncProxyResolverExpectsBytes::SetPacScript(script_data, |
| 182 callback); |
| 183 } |
| 184 |
| 185 void CallbackMockProxyResolver::WaitForCancel() { |
| 186 while (cancelled_requests().empty()) { |
| 187 base::RunLoop run_loop; |
| 188 cancel_callback_ = run_loop.QuitClosure(); |
| 189 run_loop.Run(); |
| 190 } |
| 191 } |
| 192 |
| 193 void CallbackMockProxyResolver::ReturnProxySynchronously( |
| 194 const ProxyInfo& result) { |
| 195 sync_result_.reset(new ProxyInfo(result)); |
| 196 } |
| 197 |
| 198 void CallbackMockProxyResolver::CompleteSetPacScriptSynchronously() { |
| 199 set_pac_script_sync_ = true; |
| 200 } |
| 201 |
| 202 void Fail(int32_t error) { |
| 203 FAIL() << "Unexpected callback with error: " << error; |
| 204 } |
| 205 |
| 206 } // namespace |
| 207 |
| 208 class MojoProxyResolverImplTest : public testing::Test { |
| 209 protected: |
| 210 void SetUp() override { |
| 211 scoped_ptr<CallbackMockProxyResolver> mock_resolver( |
| 212 new CallbackMockProxyResolver); |
| 213 mock_proxy_resolver_ = mock_resolver.get(); |
| 214 resolver_.reset(new MojoProxyResolverImpl(mock_resolver.Pass())); |
| 215 } |
| 216 |
| 217 CallbackMockProxyResolver* mock_proxy_resolver_; |
| 218 |
| 219 scoped_ptr<interfaces::ProxyResolver> resolver_; |
| 220 }; |
| 221 |
| 222 TEST_F(MojoProxyResolverImplTest, GetProxyForUrl) { |
| 223 interfaces::ProxyResolverRequestClientPtr client_ptr; |
| 224 TestRequestClient client(mojo::GetProxy(&client_ptr)); |
| 225 |
| 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()); |
| 231 request->results()->UsePacString( |
| 232 "PROXY proxy.example.com:1; " |
| 233 "SOCKS4 socks4.example.com:2; " |
| 234 "SOCKS5 socks5.example.com:3; " |
| 235 "HTTPS https.example.com:4; " |
| 236 "QUIC quic.example.com:65000; " |
| 237 "DIRECT"); |
| 238 request->CompleteNow(OK); |
| 239 client.WaitForResult(); |
| 240 |
| 241 EXPECT_EQ(net::OK, client.error()); |
| 242 std::vector<net::ProxyServer> servers = |
| 243 client.results().To<std::vector<net::ProxyServer>>(); |
| 244 ASSERT_EQ(6u, servers.size()); |
| 245 EXPECT_EQ(ProxyServer::SCHEME_HTTP, servers[0].scheme()); |
| 246 EXPECT_EQ("proxy.example.com", servers[0].host_port_pair().host()); |
| 247 EXPECT_EQ(1, servers[0].host_port_pair().port()); |
| 248 |
| 249 EXPECT_EQ(ProxyServer::SCHEME_SOCKS4, servers[1].scheme()); |
| 250 EXPECT_EQ("socks4.example.com", servers[1].host_port_pair().host()); |
| 251 EXPECT_EQ(2, servers[1].host_port_pair().port()); |
| 252 |
| 253 EXPECT_EQ(ProxyServer::SCHEME_SOCKS5, servers[2].scheme()); |
| 254 EXPECT_EQ("socks5.example.com", servers[2].host_port_pair().host()); |
| 255 EXPECT_EQ(3, servers[2].host_port_pair().port()); |
| 256 |
| 257 EXPECT_EQ(ProxyServer::SCHEME_HTTPS, servers[3].scheme()); |
| 258 EXPECT_EQ("https.example.com", servers[3].host_port_pair().host()); |
| 259 EXPECT_EQ(4, servers[3].host_port_pair().port()); |
| 260 |
| 261 EXPECT_EQ(ProxyServer::SCHEME_QUIC, servers[4].scheme()); |
| 262 EXPECT_EQ("quic.example.com", servers[4].host_port_pair().host()); |
| 263 EXPECT_EQ(65000, servers[4].host_port_pair().port()); |
| 264 |
| 265 EXPECT_EQ(ProxyServer::SCHEME_DIRECT, servers[5].scheme()); |
| 266 } |
| 267 |
| 268 TEST_F(MojoProxyResolverImplTest, GetProxyForUrlSynchronous) { |
| 269 interfaces::ProxyResolverRequestClientPtr client_ptr; |
| 270 TestRequestClient client(mojo::GetProxy(&client_ptr)); |
| 271 |
| 272 ProxyInfo result; |
| 273 result.UsePacString("DIRECT"); |
| 274 mock_proxy_resolver_->ReturnProxySynchronously(result); |
| 275 resolver_->GetProxyForUrl("http://example.com", client_ptr.Pass()); |
| 276 ASSERT_EQ(0u, mock_proxy_resolver_->pending_requests().size()); |
| 277 client.WaitForResult(); |
| 278 |
| 279 EXPECT_EQ(net::OK, client.error()); |
| 280 std::vector<net::ProxyServer> proxy_servers = |
| 281 client.results().To<std::vector<net::ProxyServer>>(); |
| 282 ASSERT_EQ(1u, proxy_servers.size()); |
| 283 net::ProxyServer& server = proxy_servers[0]; |
| 284 EXPECT_TRUE(server.is_direct()); |
| 285 } |
| 286 |
| 287 TEST_F(MojoProxyResolverImplTest, GetProxyForUrlFailure) { |
| 288 interfaces::ProxyResolverRequestClientPtr client_ptr; |
| 289 TestRequestClient client(mojo::GetProxy(&client_ptr)); |
| 290 |
| 291 resolver_->GetProxyForUrl("http://example.com", client_ptr.Pass()); |
| 292 ASSERT_EQ(1u, mock_proxy_resolver_->pending_requests().size()); |
| 293 scoped_refptr<MockAsyncProxyResolverBase::Request> request = |
| 294 mock_proxy_resolver_->pending_requests()[0]; |
| 295 EXPECT_EQ(GURL("http://example.com"), request->url()); |
| 296 request->CompleteNow(ERR_FAILED); |
| 297 client.WaitForResult(); |
| 298 |
| 299 EXPECT_EQ(ERR_FAILED, client.error()); |
| 300 std::vector<net::ProxyServer> proxy_servers = |
| 301 client.results().To<std::vector<net::ProxyServer>>(); |
| 302 EXPECT_TRUE(proxy_servers.empty()); |
| 303 } |
| 304 |
| 305 TEST_F(MojoProxyResolverImplTest, GetProxyForUrlMultiple) { |
| 306 interfaces::ProxyResolverRequestClientPtr client_ptr1; |
| 307 TestRequestClient client1(mojo::GetProxy(&client_ptr1)); |
| 308 interfaces::ProxyResolverRequestClientPtr client_ptr2; |
| 309 TestRequestClient client2(mojo::GetProxy(&client_ptr2)); |
| 310 |
| 311 resolver_->GetProxyForUrl("http://example.com", client_ptr1.Pass()); |
| 312 resolver_->GetProxyForUrl("https://example.com", client_ptr2.Pass()); |
| 313 ASSERT_EQ(2u, mock_proxy_resolver_->pending_requests().size()); |
| 314 scoped_refptr<MockAsyncProxyResolverBase::Request> request1 = |
| 315 mock_proxy_resolver_->pending_requests()[0]; |
| 316 EXPECT_EQ(GURL("http://example.com"), request1->url()); |
| 317 scoped_refptr<MockAsyncProxyResolverBase::Request> request2 = |
| 318 mock_proxy_resolver_->pending_requests()[1]; |
| 319 EXPECT_EQ(GURL("https://example.com"), request2->url()); |
| 320 request1->results()->UsePacString("HTTPS proxy.example.com:12345"); |
| 321 request1->CompleteNow(OK); |
| 322 request2->results()->UsePacString("SOCKS5 another-proxy.example.com:6789"); |
| 323 request2->CompleteNow(OK); |
| 324 client1.WaitForResult(); |
| 325 client2.WaitForResult(); |
| 326 |
| 327 EXPECT_EQ(net::OK, client1.error()); |
| 328 std::vector<net::ProxyServer> proxy_servers1 = |
| 329 client1.results().To<std::vector<net::ProxyServer>>(); |
| 330 ASSERT_EQ(1u, proxy_servers1.size()); |
| 331 net::ProxyServer& server1 = proxy_servers1[0]; |
| 332 EXPECT_EQ(ProxyServer::SCHEME_HTTPS, server1.scheme()); |
| 333 EXPECT_EQ("proxy.example.com", server1.host_port_pair().host()); |
| 334 EXPECT_EQ(12345, server1.host_port_pair().port()); |
| 335 |
| 336 EXPECT_EQ(net::OK, client2.error()); |
| 337 std::vector<net::ProxyServer> proxy_servers2 = |
| 338 client2.results().To<std::vector<net::ProxyServer>>(); |
| 339 ASSERT_EQ(1u, proxy_servers1.size()); |
| 340 net::ProxyServer& server2 = proxy_servers2[0]; |
| 341 EXPECT_EQ(ProxyServer::SCHEME_SOCKS5, server2.scheme()); |
| 342 EXPECT_EQ("another-proxy.example.com", server2.host_port_pair().host()); |
| 343 EXPECT_EQ(6789, server2.host_port_pair().port()); |
| 344 } |
| 345 |
| 346 TEST_F(MojoProxyResolverImplTest, SetPacScript) { |
| 347 SetPacScriptClient client; |
| 348 |
| 349 resolver_->SetPacScript("pac script", client.CreateCallback()); |
| 350 MockAsyncProxyResolverBase::SetPacScriptRequest* request = |
| 351 mock_proxy_resolver_->pending_set_pac_script_request(); |
| 352 ASSERT_TRUE(request); |
| 353 EXPECT_EQ("pac script", base::UTF16ToUTF8(request->script_data()->utf16())); |
| 354 request->CompleteNow(OK); |
| 355 EXPECT_EQ(OK, client.error()); |
| 356 } |
| 357 |
| 358 TEST_F(MojoProxyResolverImplTest, SetPacScriptSynchronous) { |
| 359 SetPacScriptClient client; |
| 360 |
| 361 mock_proxy_resolver_->CompleteSetPacScriptSynchronously(); |
| 362 resolver_->SetPacScript("pac script", client.CreateCallback()); |
| 363 EXPECT_FALSE(mock_proxy_resolver_->pending_set_pac_script_request()); |
| 364 EXPECT_EQ(OK, client.error()); |
| 365 } |
| 366 |
| 367 TEST_F(MojoProxyResolverImplTest, SetPacScriptMultiple) { |
| 368 SetPacScriptClient client1; |
| 369 SetPacScriptClient client2; |
| 370 |
| 371 resolver_->SetPacScript("pac script", client1.CreateCallback()); |
| 372 resolver_->SetPacScript("a different pac script", client2.CreateCallback()); |
| 373 MockAsyncProxyResolverBase::SetPacScriptRequest* request = |
| 374 mock_proxy_resolver_->pending_set_pac_script_request(); |
| 375 ASSERT_TRUE(request); |
| 376 EXPECT_EQ("pac script", base::UTF16ToUTF8(request->script_data()->utf16())); |
| 377 request->CompleteNow(OK); |
| 378 EXPECT_EQ(OK, client1.error()); |
| 379 |
| 380 request = mock_proxy_resolver_->pending_set_pac_script_request(); |
| 381 ASSERT_TRUE(request); |
| 382 EXPECT_EQ("a different pac script", |
| 383 base::UTF16ToUTF8(request->script_data()->utf16())); |
| 384 request->CompleteNow(ERR_PAC_SCRIPT_FAILED); |
| 385 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, client2.error()); |
| 386 } |
| 387 |
| 388 TEST_F(MojoProxyResolverImplTest, DestroyClient) { |
| 389 interfaces::ProxyResolverRequestClientPtr client_ptr; |
| 390 scoped_ptr<TestRequestClient> client( |
| 391 new TestRequestClient(mojo::GetProxy(&client_ptr))); |
| 392 |
| 393 resolver_->GetProxyForUrl("http://example.com", client_ptr.Pass()); |
| 394 ASSERT_EQ(1u, mock_proxy_resolver_->pending_requests().size()); |
| 395 scoped_refptr<MockAsyncProxyResolverBase::Request> request = |
| 396 mock_proxy_resolver_->pending_requests()[0]; |
| 397 EXPECT_EQ(GURL("http://example.com"), request->url()); |
| 398 request->results()->UsePacString("PROXY proxy.example.com:8080"); |
| 399 client.reset(); |
| 400 mock_proxy_resolver_->WaitForCancel(); |
| 401 } |
| 402 |
| 403 TEST_F(MojoProxyResolverImplTest, DestroyService) { |
| 404 interfaces::ProxyResolverRequestClientPtr client_ptr; |
| 405 TestRequestClient client(mojo::GetProxy(&client_ptr)); |
| 406 |
| 407 resolver_->GetProxyForUrl("http://example.com", client_ptr.Pass()); |
| 408 resolver_->SetPacScript("pac script", base::Bind(&Fail)); |
| 409 ASSERT_EQ(1u, mock_proxy_resolver_->pending_requests().size()); |
| 410 scoped_refptr<MockAsyncProxyResolverBase::Request> request = |
| 411 mock_proxy_resolver_->pending_requests()[0]; |
| 412 resolver_.reset(); |
| 413 client.WaitForConnectionError(); |
| 414 } |
| 415 |
| 416 } // namespace net |
OLD | NEW |