// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/proxy/proxy_resolver_factory_mojo.h" #include #include #include #include #include #include #include "base/bind.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "base/values.h" #include "mojo/common/common_type_converters.h" #include "mojo/public/cpp/bindings/binding.h" #include "net/base/load_states.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/dns/host_resolver.h" #include "net/log/test_net_log.h" #include "net/proxy/mojo_proxy_resolver_factory.h" #include "net/proxy/mojo_proxy_type_converters.h" #include "net/proxy/proxy_info.h" #include "net/proxy/proxy_resolver.h" #include "net/proxy/proxy_resolver_error_observer.h" #include "net/proxy/proxy_resolver_script_data.h" #include "net/test/event_waiter.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" namespace net { namespace { const char kScriptData[] = "FooBarBaz"; const char kExampleUrl[] = "http://www.example.com"; struct CreateProxyResolverAction { enum Action { COMPLETE, DROP_CLIENT, DROP_RESOLVER, DROP_BOTH, WAIT_FOR_CLIENT_DISCONNECT, MAKE_DNS_REQUEST, }; static CreateProxyResolverAction ReturnResult( const std::string& expected_pac_script, Error error) { CreateProxyResolverAction result; result.expected_pac_script = expected_pac_script; result.error = error; return result; } static CreateProxyResolverAction DropClient( const std::string& expected_pac_script) { CreateProxyResolverAction result; result.expected_pac_script = expected_pac_script; result.action = DROP_CLIENT; return result; } static CreateProxyResolverAction DropResolver( const std::string& expected_pac_script) { CreateProxyResolverAction result; result.expected_pac_script = expected_pac_script; result.action = DROP_RESOLVER; return result; } static CreateProxyResolverAction DropBoth( const std::string& expected_pac_script) { CreateProxyResolverAction result; result.expected_pac_script = expected_pac_script; result.action = DROP_BOTH; return result; } static CreateProxyResolverAction WaitForClientDisconnect( const std::string& expected_pac_script) { CreateProxyResolverAction result; result.expected_pac_script = expected_pac_script; result.action = WAIT_FOR_CLIENT_DISCONNECT; return result; } static CreateProxyResolverAction MakeDnsRequest( const std::string& expected_pac_script) { CreateProxyResolverAction result; result.expected_pac_script = expected_pac_script; result.action = MAKE_DNS_REQUEST; return result; } std::string expected_pac_script; Action action = COMPLETE; Error error = OK; }; struct GetProxyForUrlAction { enum Action { COMPLETE, // Drop the request by closing the reply channel. DROP, // Disconnect the service. DISCONNECT, // Wait for the client pipe to be disconnected. WAIT_FOR_CLIENT_DISCONNECT, // Make a DNS request. MAKE_DNS_REQUEST, }; GetProxyForUrlAction() {} GetProxyForUrlAction(const GetProxyForUrlAction& old) { action = old.action; error = old.error; expected_url = old.expected_url; proxy_servers = old.proxy_servers.Clone(); } static GetProxyForUrlAction ReturnError(const GURL& url, Error error) { GetProxyForUrlAction result; result.expected_url = url; result.error = error; return result; } static GetProxyForUrlAction ReturnServers( const GURL& url, const mojo::Array& proxy_servers) { GetProxyForUrlAction result; result.expected_url = url; result.proxy_servers = proxy_servers.Clone(); return result; } static GetProxyForUrlAction DropRequest(const GURL& url) { GetProxyForUrlAction result; result.expected_url = url; result.action = DROP; return result; } static GetProxyForUrlAction Disconnect(const GURL& url) { GetProxyForUrlAction result; result.expected_url = url; result.action = DISCONNECT; return result; } static GetProxyForUrlAction WaitForClientDisconnect(const GURL& url) { GetProxyForUrlAction result; result.expected_url = url; result.action = WAIT_FOR_CLIENT_DISCONNECT; return result; } static GetProxyForUrlAction MakeDnsRequest(const GURL& url) { GetProxyForUrlAction result; result.expected_url = url; result.action = MAKE_DNS_REQUEST; return result; } Action action = COMPLETE; Error error = OK; mojo::Array proxy_servers; GURL expected_url; }; class MockMojoProxyResolver : public interfaces::ProxyResolver { public: MockMojoProxyResolver(); ~MockMojoProxyResolver() override; void AddGetProxyAction(GetProxyForUrlAction action); void WaitForNextRequest(); void ClearBlockedClients(); void AddConnection(mojo::InterfaceRequest req); private: // Overridden from interfaces::ProxyResolver: void GetProxyForUrl( const mojo::String& url, interfaces::ProxyResolverRequestClientPtr client) override; void WakeWaiter(); std::string pac_script_data_; std::queue get_proxy_actions_; base::Closure quit_closure_; std::vector> blocked_clients_; mojo::Binding binding_; }; MockMojoProxyResolver::~MockMojoProxyResolver() { EXPECT_TRUE(get_proxy_actions_.empty()) << "Actions remaining: " << get_proxy_actions_.size(); } MockMojoProxyResolver::MockMojoProxyResolver() : binding_(this) { } void MockMojoProxyResolver::AddGetProxyAction(GetProxyForUrlAction action) { get_proxy_actions_.push(action); } void MockMojoProxyResolver::WaitForNextRequest() { base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); run_loop.Run(); } void MockMojoProxyResolver::WakeWaiter() { if (!quit_closure_.is_null()) quit_closure_.Run(); quit_closure_.Reset(); } void MockMojoProxyResolver::ClearBlockedClients() { blocked_clients_.clear(); } void MockMojoProxyResolver::AddConnection( mojo::InterfaceRequest req) { if (binding_.is_bound()) binding_.Close(); binding_.Bind(std::move(req)); } void MockMojoProxyResolver::GetProxyForUrl( const mojo::String& url, interfaces::ProxyResolverRequestClientPtr client) { ASSERT_FALSE(get_proxy_actions_.empty()); GetProxyForUrlAction action = get_proxy_actions_.front(); get_proxy_actions_.pop(); EXPECT_EQ(action.expected_url.spec(), url.To()); client->Alert(url); client->OnError(12345, url); switch (action.action) { case GetProxyForUrlAction::COMPLETE: { client->ReportResult(action.error, std::move(action.proxy_servers)); break; } case GetProxyForUrlAction::DROP: { client.reset(); break; } case GetProxyForUrlAction::DISCONNECT: { binding_.Close(); break; } case GetProxyForUrlAction::WAIT_FOR_CLIENT_DISCONNECT: { ASSERT_FALSE(client.WaitForIncomingResponse()); break; } case GetProxyForUrlAction::MAKE_DNS_REQUEST: { interfaces::HostResolverRequestInfoPtr request( interfaces::HostResolverRequestInfo::New()); request->host = url; request->port = 12345; interfaces::HostResolverRequestClientPtr dns_client; mojo::GetProxy(&dns_client); client->ResolveDns(std::move(request), std::move(dns_client)); blocked_clients_.push_back(make_scoped_ptr( new interfaces::ProxyResolverRequestClientPtr(std::move(client)))); break; } } WakeWaiter(); } class Request { public: Request(ProxyResolver* resolver, const GURL& url); int Resolve(); void Cancel(); int WaitForResult(); const ProxyInfo& results() const { return results_; } LoadState load_state() { return resolver_->GetLoadState(handle_); } BoundTestNetLog& net_log() { return net_log_; } private: ProxyResolver* resolver_; const GURL url_; ProxyInfo results_; ProxyResolver::RequestHandle handle_; int error_; TestCompletionCallback callback_; BoundTestNetLog net_log_; }; Request::Request(ProxyResolver* resolver, const GURL& url) : resolver_(resolver), url_(url), error_(0) { } int Request::Resolve() { error_ = resolver_->GetProxyForURL(url_, &results_, callback_.callback(), &handle_, net_log_.bound()); return error_; } void Request::Cancel() { resolver_->CancelRequest(handle_); } int Request::WaitForResult() { error_ = callback_.WaitForResult(); return error_; } class MockMojoProxyResolverFactory : public interfaces::ProxyResolverFactory { public: MockMojoProxyResolverFactory( MockMojoProxyResolver* resolver, mojo::InterfaceRequest req); ~MockMojoProxyResolverFactory() override; void AddCreateProxyResolverAction(CreateProxyResolverAction action); void WaitForNextRequest(); void ClearBlockedClients(); private: // Overridden from interfaces::ProxyResolver: void CreateResolver( const mojo::String& pac_url, mojo::InterfaceRequest request, interfaces::ProxyResolverFactoryRequestClientPtr client) override; void WakeWaiter(); MockMojoProxyResolver* resolver_; std::queue create_resolver_actions_; base::Closure quit_closure_; std::vector> blocked_clients_; std::vector>> blocked_resolver_requests_; mojo::Binding binding_; }; MockMojoProxyResolverFactory::MockMojoProxyResolverFactory( MockMojoProxyResolver* resolver, mojo::InterfaceRequest req) : resolver_(resolver), binding_(this, std::move(req)) {} MockMojoProxyResolverFactory::~MockMojoProxyResolverFactory() { EXPECT_TRUE(create_resolver_actions_.empty()) << "Actions remaining: " << create_resolver_actions_.size(); } void MockMojoProxyResolverFactory::AddCreateProxyResolverAction( CreateProxyResolverAction action) { create_resolver_actions_.push(action); } void MockMojoProxyResolverFactory::WaitForNextRequest() { base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); run_loop.Run(); } void MockMojoProxyResolverFactory::WakeWaiter() { if (!quit_closure_.is_null()) quit_closure_.Run(); quit_closure_.Reset(); } void MockMojoProxyResolverFactory::ClearBlockedClients() { blocked_clients_.clear(); } void MockMojoProxyResolverFactory::CreateResolver( const mojo::String& pac_script, mojo::InterfaceRequest request, interfaces::ProxyResolverFactoryRequestClientPtr client) { ASSERT_FALSE(create_resolver_actions_.empty()); CreateProxyResolverAction action = create_resolver_actions_.front(); create_resolver_actions_.pop(); EXPECT_EQ(action.expected_pac_script, pac_script.To()); client->Alert(pac_script); client->OnError(12345, pac_script); switch (action.action) { case CreateProxyResolverAction::COMPLETE: { if (action.error == OK) resolver_->AddConnection(std::move(request)); client->ReportResult(action.error); break; } case CreateProxyResolverAction::DROP_CLIENT: { // Save |request| so its pipe isn't closed. blocked_resolver_requests_.push_back( make_scoped_ptr(new mojo::InterfaceRequest( std::move(request)))); break; } case CreateProxyResolverAction::DROP_RESOLVER: { // Save |client| so its pipe isn't closed. blocked_clients_.push_back( make_scoped_ptr(new interfaces::ProxyResolverFactoryRequestClientPtr( std::move(client)))); break; } case CreateProxyResolverAction::DROP_BOTH: { // Both |request| and |client| will be closed. break; } case CreateProxyResolverAction::WAIT_FOR_CLIENT_DISCONNECT: { ASSERT_FALSE(client.WaitForIncomingResponse()); break; } case CreateProxyResolverAction::MAKE_DNS_REQUEST: { interfaces::HostResolverRequestInfoPtr request( interfaces::HostResolverRequestInfo::New()); request->host = pac_script; request->port = 12345; interfaces::HostResolverRequestClientPtr dns_client; mojo::GetProxy(&dns_client); client->ResolveDns(std::move(request), std::move(dns_client)); blocked_clients_.push_back( make_scoped_ptr(new interfaces::ProxyResolverFactoryRequestClientPtr( std::move(client)))); break; } } WakeWaiter(); } void DeleteResolverFactoryRequestCallback( scoped_ptr* request, const CompletionCallback& callback, int result) { ASSERT_TRUE(request); EXPECT_TRUE(request->get()); request->reset(); callback.Run(result); } class MockHostResolver : public HostResolver { public: enum Event { DNS_REQUEST, }; // HostResolver overrides. int Resolve(const RequestInfo& info, RequestPriority priority, AddressList* addresses, const CompletionCallback& callback, RequestHandle* request_handle, const BoundNetLog& source_net_log) override { waiter_.NotifyEvent(DNS_REQUEST); return ERR_IO_PENDING; } int ResolveFromCache(const RequestInfo& info, AddressList* addresses, const BoundNetLog& source_net_log) override { return ERR_DNS_CACHE_MISS; } void CancelRequest(RequestHandle req) override {} HostCache* GetHostCache() override { return nullptr; } EventWaiter& waiter() { return waiter_; } private: EventWaiter waiter_; }; void CheckCapturedNetLogEntries(const std::string& expected_string, const TestNetLogEntry::List& entries) { ASSERT_EQ(2u, entries.size()); EXPECT_EQ(NetLog::TYPE_PAC_JAVASCRIPT_ALERT, entries[0].type); std::string message; ASSERT_TRUE(entries[0].GetStringValue("message", &message)); EXPECT_EQ(expected_string, message); ASSERT_FALSE(entries[0].params->HasKey("line_number")); message.clear(); EXPECT_EQ(NetLog::TYPE_PAC_JAVASCRIPT_ERROR, entries[1].type); ASSERT_TRUE(entries[1].GetStringValue("message", &message)); EXPECT_EQ(expected_string, message); int line_number = 0; ASSERT_TRUE(entries[1].GetIntegerValue("line_number", &line_number)); EXPECT_EQ(12345, line_number); } } // namespace class ProxyResolverFactoryMojoTest : public testing::Test, public MojoProxyResolverFactory { public: void SetUp() override { mock_proxy_resolver_factory_.reset(new MockMojoProxyResolverFactory( &mock_proxy_resolver_, mojo::GetProxy(&factory_ptr_))); proxy_resolver_factory_mojo_.reset(new ProxyResolverFactoryMojo( this, &host_resolver_, base::Callback()>(), &net_log_)); } scoped_ptr MakeRequest(const GURL& url) { return make_scoped_ptr(new Request(proxy_resolver_mojo_.get(), url)); } scoped_ptr CreateResolver( const mojo::String& pac_script, mojo::InterfaceRequest req, interfaces::ProxyResolverFactoryRequestClientPtr client) override { factory_ptr_->CreateResolver(pac_script, std::move(req), std::move(client)); return make_scoped_ptr( new base::ScopedClosureRunner(on_delete_callback_.closure())); } mojo::Array ProxyServersFromPacString( const std::string& pac_string) { ProxyInfo proxy_info; proxy_info.UsePacString(pac_string); return mojo::Array::From( proxy_info.proxy_list().GetAll()); } void CreateProxyResolver() { mock_proxy_resolver_factory_->AddCreateProxyResolverAction( CreateProxyResolverAction::ReturnResult(kScriptData, OK)); TestCompletionCallback callback; scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8(kScriptData)); scoped_ptr request; ASSERT_EQ( OK, callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request))); EXPECT_TRUE(request); ASSERT_TRUE(proxy_resolver_mojo_); } void DeleteProxyResolverCallback(const CompletionCallback& callback, int result) { proxy_resolver_mojo_.reset(); callback.Run(result); } MockHostResolver host_resolver_; TestNetLog net_log_; scoped_ptr mock_proxy_resolver_factory_; interfaces::ProxyResolverFactoryPtr factory_ptr_; scoped_ptr proxy_resolver_factory_mojo_; MockMojoProxyResolver mock_proxy_resolver_; TestClosure on_delete_callback_; scoped_ptr proxy_resolver_mojo_; }; TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver) { CreateProxyResolver(); TestNetLogEntry::List entries; net_log_.GetEntries(&entries); CheckCapturedNetLogEntries(kScriptData, entries); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Empty) { TestCompletionCallback callback; scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8("")); scoped_ptr request; EXPECT_EQ( ERR_PAC_SCRIPT_FAILED, callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request))); EXPECT_FALSE(request); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Url) { TestCompletionCallback callback; scoped_refptr pac_script( ProxyResolverScriptData::FromURL(GURL(kExampleUrl))); scoped_ptr request; EXPECT_EQ( ERR_PAC_SCRIPT_FAILED, callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request))); EXPECT_FALSE(request); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Failed) { mock_proxy_resolver_factory_->AddCreateProxyResolverAction( CreateProxyResolverAction::ReturnResult(kScriptData, ERR_PAC_STATUS_NOT_OK)); TestCompletionCallback callback; scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8(kScriptData)); scoped_ptr request; EXPECT_EQ( ERR_PAC_STATUS_NOT_OK, callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request))); EXPECT_TRUE(request); on_delete_callback_.WaitForResult(); // A second attempt succeeds. CreateProxyResolver(); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_BothDisconnected) { mock_proxy_resolver_factory_->AddCreateProxyResolverAction( CreateProxyResolverAction::DropBoth(kScriptData)); scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8(kScriptData)); scoped_ptr request; TestCompletionCallback callback; EXPECT_EQ( ERR_PAC_SCRIPT_TERMINATED, callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request))); EXPECT_TRUE(request); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_ClientDisconnected) { mock_proxy_resolver_factory_->AddCreateProxyResolverAction( CreateProxyResolverAction::DropClient(kScriptData)); scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8(kScriptData)); scoped_ptr request; TestCompletionCallback callback; EXPECT_EQ( ERR_PAC_SCRIPT_TERMINATED, callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request))); EXPECT_TRUE(request); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_ResolverDisconnected) { mock_proxy_resolver_factory_->AddCreateProxyResolverAction( CreateProxyResolverAction::DropResolver(kScriptData)); scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8(kScriptData)); scoped_ptr request; TestCompletionCallback callback; EXPECT_EQ( ERR_PAC_SCRIPT_TERMINATED, callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request))); EXPECT_TRUE(request); on_delete_callback_.WaitForResult(); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_ResolverDisconnected_DeleteRequestInCallback) { mock_proxy_resolver_factory_->AddCreateProxyResolverAction( CreateProxyResolverAction::DropResolver(kScriptData)); scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8(kScriptData)); scoped_ptr request; TestCompletionCallback callback; EXPECT_EQ( ERR_PAC_SCRIPT_TERMINATED, callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, base::Bind(&DeleteResolverFactoryRequestCallback, &request, callback.callback()), &request))); on_delete_callback_.WaitForResult(); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Cancel) { mock_proxy_resolver_factory_->AddCreateProxyResolverAction( CreateProxyResolverAction::WaitForClientDisconnect(kScriptData)); scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8(kScriptData)); scoped_ptr request; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request)); ASSERT_TRUE(request); request.reset(); // The Mojo request is still made. mock_proxy_resolver_factory_->WaitForNextRequest(); on_delete_callback_.WaitForResult(); } TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_DnsRequest) { mock_proxy_resolver_factory_->AddCreateProxyResolverAction( CreateProxyResolverAction::MakeDnsRequest(kScriptData)); scoped_refptr pac_script( ProxyResolverScriptData::FromUTF8(kScriptData)); scoped_ptr request; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, proxy_resolver_factory_mojo_->CreateProxyResolver( pac_script, &proxy_resolver_mojo_, callback.callback(), &request)); ASSERT_TRUE(request); host_resolver_.waiter().WaitForEvent(MockHostResolver::DNS_REQUEST); mock_proxy_resolver_factory_->ClearBlockedClients(); callback.WaitForResult(); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL) { const GURL url(kExampleUrl); mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers( url, ProxyServersFromPacString("DIRECT"))); CreateProxyResolver(); net_log_.Clear(); scoped_ptr request(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_IO_PENDING, request->Resolve()); EXPECT_EQ(OK, request->WaitForResult()); EXPECT_EQ("DIRECT", request->results().ToPacString()); TestNetLogEntry::List entries; net_log_.GetEntries(&entries); CheckCapturedNetLogEntries(url.spec(), entries); entries.clear(); request->net_log().GetEntries(&entries); CheckCapturedNetLogEntries(url.spec(), entries); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_MultipleResults) { static const char kPacString[] = "PROXY foo1:80;DIRECT;SOCKS foo2:1234;" "SOCKS5 foo3:1080;HTTPS foo4:443;QUIC foo6:8888"; mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers( GURL(kExampleUrl), ProxyServersFromPacString(kPacString))); CreateProxyResolver(); scoped_ptr request(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_IO_PENDING, request->Resolve()); EXPECT_EQ(OK, request->WaitForResult()); EXPECT_EQ(kPacString, request->results().ToPacString()); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Error) { mock_proxy_resolver_.AddGetProxyAction( GetProxyForUrlAction::ReturnError(GURL(kExampleUrl), ERR_UNEXPECTED)); CreateProxyResolver(); scoped_ptr request(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_IO_PENDING, request->Resolve()); EXPECT_EQ(ERR_UNEXPECTED, request->WaitForResult()); EXPECT_TRUE(request->results().is_empty()); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Cancel) { mock_proxy_resolver_.AddGetProxyAction( GetProxyForUrlAction::WaitForClientDisconnect(GURL(kExampleUrl))); CreateProxyResolver(); scoped_ptr request(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_IO_PENDING, request->Resolve()); request->Cancel(); // The Mojo request is still made. mock_proxy_resolver_.WaitForNextRequest(); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_MultipleRequests) { mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers( GURL(kExampleUrl), ProxyServersFromPacString("DIRECT"))); mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers( GURL("https://www.chromium.org"), ProxyServersFromPacString("HTTPS foo:443"))); CreateProxyResolver(); scoped_ptr request1(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_IO_PENDING, request1->Resolve()); scoped_ptr request2(MakeRequest(GURL("https://www.chromium.org"))); EXPECT_EQ(ERR_IO_PENDING, request2->Resolve()); EXPECT_EQ(OK, request1->WaitForResult()); EXPECT_EQ(OK, request2->WaitForResult()); EXPECT_EQ("DIRECT", request1->results().ToPacString()); EXPECT_EQ("HTTPS foo:443", request2->results().ToPacString()); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Disconnect) { mock_proxy_resolver_.AddGetProxyAction( GetProxyForUrlAction::Disconnect(GURL(kExampleUrl))); CreateProxyResolver(); { scoped_ptr request(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_IO_PENDING, request->Resolve()); EXPECT_EQ(ERR_PAC_SCRIPT_TERMINATED, request->WaitForResult()); EXPECT_TRUE(request->results().is_empty()); } { // Calling GetProxyForURL after a disconnect should fail. scoped_ptr request(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_PAC_SCRIPT_TERMINATED, request->Resolve()); } } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_ClientClosed) { mock_proxy_resolver_.AddGetProxyAction( GetProxyForUrlAction::DropRequest(GURL(kExampleUrl))); CreateProxyResolver(); scoped_ptr request1(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_IO_PENDING, request1->Resolve()); EXPECT_EQ(ERR_PAC_SCRIPT_TERMINATED, request1->WaitForResult()); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DeleteInCallback) { mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers( GURL(kExampleUrl), ProxyServersFromPacString("DIRECT"))); CreateProxyResolver(); ProxyInfo results; TestCompletionCallback callback; ProxyResolver::RequestHandle handle; BoundNetLog net_log; EXPECT_EQ( OK, callback.GetResult(proxy_resolver_mojo_->GetProxyForURL( GURL(kExampleUrl), &results, base::Bind(&ProxyResolverFactoryMojoTest::DeleteProxyResolverCallback, base::Unretained(this), callback.callback()), &handle, net_log))); on_delete_callback_.WaitForResult(); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DeleteInCallbackFromDisconnect) { mock_proxy_resolver_.AddGetProxyAction( GetProxyForUrlAction::Disconnect(GURL(kExampleUrl))); CreateProxyResolver(); ProxyInfo results; TestCompletionCallback callback; ProxyResolver::RequestHandle handle; BoundNetLog net_log; EXPECT_EQ( ERR_PAC_SCRIPT_TERMINATED, callback.GetResult(proxy_resolver_mojo_->GetProxyForURL( GURL(kExampleUrl), &results, base::Bind(&ProxyResolverFactoryMojoTest::DeleteProxyResolverCallback, base::Unretained(this), callback.callback()), &handle, net_log))); on_delete_callback_.WaitForResult(); } TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DnsRequest) { mock_proxy_resolver_.AddGetProxyAction( GetProxyForUrlAction::MakeDnsRequest(GURL(kExampleUrl))); CreateProxyResolver(); scoped_ptr request(MakeRequest(GURL(kExampleUrl))); EXPECT_EQ(ERR_IO_PENDING, request->Resolve()); EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->load_state()); host_resolver_.waiter().WaitForEvent(MockHostResolver::DNS_REQUEST); EXPECT_EQ(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT, request->load_state()); mock_proxy_resolver_.ClearBlockedClients(); request->WaitForResult(); } TEST_F(ProxyResolverFactoryMojoTest, DeleteResolver) { CreateProxyResolver(); proxy_resolver_mojo_.reset(); on_delete_callback_.WaitForResult(); } } // namespace net