blob: 0bc76797538475f91c95f8ffc6b47861c91cfedb [file] [log] [blame]
// 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 "services/network/proxy_resolver_factory_mojo.h"
#include <list>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/containers/queue.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/values.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/net_log_event_type.h"
#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/proxy_resolution/pac_file_data.h"
#include "net/proxy_resolution/proxy_info.h"
#include "net/proxy_resolution/proxy_resolver.h"
#include "net/proxy_resolution/proxy_resolver_error_observer.h"
#include "net/proxy_resolution/proxy_resolver_factory.h"
#include "net/test/event_waiter.h"
#include "net/test/gtest_util.h"
#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using net::test::IsError;
using net::test::IsOk;
namespace network {
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,
net::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;
net::Error error = net::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& other) = default;
static GetProxyForUrlAction ReturnError(const GURL& url, net::Error error) {
GetProxyForUrlAction result;
result.expected_url = url;
result.error = error;
return result;
}
static GetProxyForUrlAction ReturnServers(const GURL& url,
const net::ProxyInfo& proxy_info) {
GetProxyForUrlAction result;
result.expected_url = url;
result.proxy_info = proxy_info;
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;
net::Error error = net::OK;
net::ProxyInfo proxy_info;
GURL expected_url;
};
class MockMojoProxyResolver : public proxy_resolver::mojom::ProxyResolver {
public:
MockMojoProxyResolver();
~MockMojoProxyResolver() override;
void AddGetProxyAction(GetProxyForUrlAction action);
void WaitForNextRequest();
void ClearBlockedClients();
void AddConnection(
mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver> req);
private:
// Overridden from proxy_resolver::mojom::ProxyResolver:
void GetProxyForUrl(
const GURL& url,
proxy_resolver::mojom::ProxyResolverRequestClientPtr client) override;
void WakeWaiter();
std::string pac_script_data_;
base::queue<GetProxyForUrlAction> get_proxy_actions_;
base::Closure quit_closure_;
std::vector<
std::unique_ptr<proxy_resolver::mojom::ProxyResolverRequestClientPtr>>
blocked_clients_;
mojo::Binding<proxy_resolver::mojom::ProxyResolver> 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<proxy_resolver::mojom::ProxyResolver> req) {
if (binding_.is_bound())
binding_.Close();
binding_.Bind(std::move(req));
}
void MockMojoProxyResolver::GetProxyForUrl(
const GURL& url,
proxy_resolver::mojom::ProxyResolverRequestClientPtr client) {
ASSERT_FALSE(get_proxy_actions_.empty());
GetProxyForUrlAction action = get_proxy_actions_.front();
get_proxy_actions_.pop();
EXPECT_EQ(action.expected_url, url);
client->Alert(url.spec());
client->OnError(12345, url.spec());
switch (action.action) {
case GetProxyForUrlAction::COMPLETE: {
client->ReportResult(action.error, action.proxy_info);
break;
}
case GetProxyForUrlAction::DROP: {
client.reset();
break;
}
case GetProxyForUrlAction::DISCONNECT: {
binding_.Close();
break;
}
case GetProxyForUrlAction::WAIT_FOR_CLIENT_DISCONNECT: {
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
client.set_connection_error_handler(run_loop.QuitClosure());
run_loop.Run();
ASSERT_TRUE(client.encountered_error());
break;
}
case GetProxyForUrlAction::MAKE_DNS_REQUEST: {
auto request = std::make_unique<net::HostResolver::RequestInfo>(
net::HostPortPair(url.spec(), 12345));
proxy_resolver::mojom::HostResolverRequestClientPtr dns_client;
mojo::MakeRequest(&dns_client);
client->ResolveDns(std::move(request), std::move(dns_client));
blocked_clients_.push_back(
std::make_unique<
proxy_resolver::mojom::ProxyResolverRequestClientPtr>(
std::move(client)));
break;
}
}
WakeWaiter();
}
class Request {
public:
Request(net::ProxyResolver* resolver, const GURL& url);
int Resolve();
void Cancel();
int WaitForResult();
const net::ProxyInfo& results() const { return results_; }
net::LoadState load_state() { return request_->GetLoadState(); }
net::BoundTestNetLog& net_log() { return net_log_; }
const net::TestCompletionCallback& callback() const { return callback_; }
private:
net::ProxyResolver* resolver_;
const GURL url_;
net::ProxyInfo results_;
std::unique_ptr<net::ProxyResolver::Request> request_;
int error_;
net::TestCompletionCallback callback_;
net::BoundTestNetLog net_log_;
};
Request::Request(net::ProxyResolver* resolver, const GURL& url)
: resolver_(resolver), url_(url), error_(0) {}
int Request::Resolve() {
error_ = resolver_->GetProxyForURL(url_, &results_, callback_.callback(),
&request_, net_log_.bound());
return error_;
}
void Request::Cancel() {
request_.reset();
}
int Request::WaitForResult() {
error_ = callback_.WaitForResult();
return error_;
}
class MockMojoProxyResolverFactory
: public proxy_resolver::mojom::ProxyResolverFactory {
public:
MockMojoProxyResolverFactory(
MockMojoProxyResolver* resolver,
mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolverFactory> req);
~MockMojoProxyResolverFactory() override;
void AddCreateProxyResolverAction(CreateProxyResolverAction action);
void WaitForNextRequest();
void ClearBlockedClients();
void RespondToBlockedClientsWithResult(net::Error error);
private:
// Overridden from proxy_resolver::mojom::ProxyResolver:
void CreateResolver(
const std::string& pac_url,
mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver> request,
proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr client)
override;
void WakeWaiter();
MockMojoProxyResolver* resolver_;
base::queue<CreateProxyResolverAction> create_resolver_actions_;
base::Closure quit_closure_;
std::vector<std::unique_ptr<
proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr>>
blocked_clients_;
std::vector<std::unique_ptr<
mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver>>>
blocked_resolver_requests_;
mojo::Binding<proxy_resolver::mojom::ProxyResolverFactory> binding_;
};
MockMojoProxyResolverFactory::MockMojoProxyResolverFactory(
MockMojoProxyResolver* resolver,
mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolverFactory> 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::RespondToBlockedClientsWithResult(
net::Error error) {
for (const auto& client : blocked_clients_) {
(*client)->ReportResult(error);
}
}
void MockMojoProxyResolverFactory::CreateResolver(
const std::string& pac_script,
mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver> request,
proxy_resolver::mojom::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);
client->Alert(pac_script);
client->OnError(12345, pac_script);
switch (action.action) {
case CreateProxyResolverAction::COMPLETE: {
if (action.error == net::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(
std::make_unique<
mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver>>(
std::move(request)));
break;
}
case CreateProxyResolverAction::DROP_RESOLVER: {
// Save |client| so its pipe isn't closed.
blocked_clients_.push_back(
std::make_unique<
proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr>(
std::move(client)));
break;
}
case CreateProxyResolverAction::DROP_BOTH: {
// Both |request| and |client| will be closed.
break;
}
case CreateProxyResolverAction::WAIT_FOR_CLIENT_DISCONNECT: {
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
client.set_connection_error_handler(run_loop.QuitClosure());
run_loop.Run();
ASSERT_TRUE(client.encountered_error());
break;
}
case CreateProxyResolverAction::MAKE_DNS_REQUEST: {
auto request = std::make_unique<net::HostResolver::RequestInfo>(
net::HostPortPair(pac_script, 12345));
proxy_resolver::mojom::HostResolverRequestClientPtr dns_client;
mojo::MakeRequest(&dns_client);
client->ResolveDns(std::move(request), std::move(dns_client));
blocked_clients_.push_back(
std::make_unique<
proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr>(
std::move(client)));
break;
}
}
WakeWaiter();
}
void DeleteResolverFactoryRequestCallback(
std::unique_ptr<net::ProxyResolverFactory::Request>* request,
net::CompletionOnceCallback callback,
int result) {
ASSERT_TRUE(request);
EXPECT_TRUE(request->get());
request->reset();
std::move(callback).Run(result);
}
class MockHostResolver : public net::HostResolver {
public:
enum Event {
DNS_REQUEST,
};
// net::HostResolver overrides.
std::unique_ptr<HostResolver::ResolveHostRequest> CreateRequest(
const net::HostPortPair& host,
const net::NetLogWithSource& source_net_log,
const base::Optional<ResolveHostParameters>& optional_parameters)
override {
// TODO(crbug.com/821021): Implement.
NOTIMPLEMENTED();
return nullptr;
}
int Resolve(const RequestInfo& info,
net::RequestPriority priority,
net::AddressList* addresses,
net::CompletionOnceCallback callback,
std::unique_ptr<Request>* request,
const net::NetLogWithSource& source_net_log) override {
waiter_.NotifyEvent(DNS_REQUEST);
return net::ERR_IO_PENDING;
}
int ResolveFromCache(const RequestInfo& info,
net::AddressList* addresses,
const net::NetLogWithSource& source_net_log) override {
return net::ERR_DNS_CACHE_MISS;
}
int ResolveStaleFromCache(
const RequestInfo& info,
net::AddressList* addresses,
net::HostCache::EntryStaleness* stale_info,
const net::NetLogWithSource& source_net_log) override {
return net::ERR_DNS_CACHE_MISS;
}
net::HostCache* GetHostCache() override { return nullptr; }
bool HasCached(base::StringPiece hostname,
net::HostCache::Entry::Source* source_out,
net::HostCache::EntryStaleness* stale_out) const override {
return false;
}
net::EventWaiter<Event>& waiter() { return waiter_; }
private:
net::EventWaiter<Event> waiter_;
};
void CheckCapturedNetLogEntries(const std::string& expected_string,
const net::TestNetLogEntry::List& entries) {
ASSERT_EQ(2u, entries.size());
EXPECT_EQ(net::NetLogEventType::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(net::NetLogEventType::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:
void SetUp() override {
proxy_resolver::mojom::ProxyResolverFactoryPtr factory_ptr;
mock_proxy_resolver_factory_.reset(new MockMojoProxyResolverFactory(
&mock_proxy_resolver_, mojo::MakeRequest(&factory_ptr)));
proxy_resolver_factory_mojo_.reset(new ProxyResolverFactoryMojo(
std::move(factory_ptr), &host_resolver_,
base::Callback<std::unique_ptr<net::ProxyResolverErrorObserver>()>(),
&net_log_));
}
std::unique_ptr<Request> MakeRequest(const GURL& url) {
return std::make_unique<Request>(proxy_resolver_mojo_.get(), url);
}
net::ProxyInfo ProxyServersFromPacString(const std::string& pac_string) {
net::ProxyInfo proxy_info;
proxy_info.UsePacString(pac_string);
return proxy_info;
}
void CreateProxyResolver() {
mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
CreateProxyResolverAction::ReturnResult(kScriptData, net::OK));
net::TestCompletionCallback callback;
scoped_refptr<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
ASSERT_EQ(
net::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(net::CompletionOnceCallback callback,
int result) {
proxy_resolver_mojo_.reset();
std::move(callback).Run(result);
}
base::test::ScopedTaskEnvironment task_environment_;
MockHostResolver host_resolver_;
net::TestNetLog net_log_;
std::unique_ptr<MockMojoProxyResolverFactory> mock_proxy_resolver_factory_;
std::unique_ptr<net::ProxyResolverFactory> proxy_resolver_factory_mojo_;
MockMojoProxyResolver mock_proxy_resolver_;
std::unique_ptr<net::ProxyResolver> proxy_resolver_mojo_;
};
TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver) {
CreateProxyResolver();
net::TestNetLogEntry::List entries;
net_log_.GetEntries(&entries);
CheckCapturedNetLogEntries(kScriptData, entries);
}
TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Empty) {
net::TestCompletionCallback callback;
scoped_refptr<net::PacFileData> pac_script(net::PacFileData::FromUTF8(""));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
EXPECT_EQ(
net::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) {
net::TestCompletionCallback callback;
scoped_refptr<net::PacFileData> pac_script(
net::PacFileData::FromURL(GURL(kExampleUrl)));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
EXPECT_EQ(
net::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,
net::ERR_PAC_STATUS_NOT_OK));
net::TestCompletionCallback callback;
scoped_refptr<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
EXPECT_EQ(
net::ERR_PAC_STATUS_NOT_OK,
callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
pac_script, &proxy_resolver_mojo_, callback.callback(), &request)));
EXPECT_TRUE(request);
// A second attempt succeeds.
CreateProxyResolver();
}
TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_BothDisconnected) {
mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
CreateProxyResolverAction::DropBoth(kScriptData));
scoped_refptr<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
net::TestCompletionCallback callback;
EXPECT_EQ(
net::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<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
net::TestCompletionCallback callback;
EXPECT_EQ(
net::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<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
// When the ResolverRequest pipe is dropped, the ProxyResolverFactory should
// still wait to get an error from the client pipe.
net::TestCompletionCallback callback;
EXPECT_EQ(
net::ERR_IO_PENDING,
proxy_resolver_factory_mojo_->CreateProxyResolver(
pac_script, &proxy_resolver_mojo_, callback.callback(), &request));
EXPECT_TRUE(request);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(callback.have_result());
mock_proxy_resolver_factory_->RespondToBlockedClientsWithResult(
net::ERR_PAC_SCRIPT_FAILED);
EXPECT_EQ(net::ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
}
// The resolver pipe is dropped, but the client is told the request succeeded
// (This could happen if a proxy resolver is created successfully, but then the
// proxy crashes before the client reads the success message).
TEST_F(ProxyResolverFactoryMojoTest,
CreateProxyResolver_ResolverDisconnectedButClientSucceeded) {
mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
CreateProxyResolverAction::DropResolver(kScriptData));
scoped_refptr<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
// When the ResolverRequest pipe is dropped, the ProxyResolverFactory
// shouldn't notice, and should just continue to wait for a response on the
// other pipe.
net::TestCompletionCallback callback;
EXPECT_EQ(
net::ERR_IO_PENDING,
proxy_resolver_factory_mojo_->CreateProxyResolver(
pac_script, &proxy_resolver_mojo_, callback.callback(), &request));
EXPECT_TRUE(request);
mock_proxy_resolver_factory_->WaitForNextRequest();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(callback.have_result());
// The client pipe reports success!
mock_proxy_resolver_factory_->RespondToBlockedClientsWithResult(net::OK);
EXPECT_EQ(net::OK, callback.WaitForResult());
// Proxy resolutions should fail with ERR_PAC_SCRIPT_TERMINATED, however. That
// error should normally cause the ProxyResolutionService to destroy the
// resolver.
net::ProxyInfo results;
std::unique_ptr<net::ProxyResolver::Request> pac_request;
EXPECT_EQ(net::ERR_PAC_SCRIPT_TERMINATED,
callback.GetResult(proxy_resolver_mojo_->GetProxyForURL(
GURL(kExampleUrl), &results,
base::BindOnce(
&ProxyResolverFactoryMojoTest::DeleteProxyResolverCallback,
base::Unretained(this), callback.callback()),
&pac_request, net::NetLogWithSource())));
}
TEST_F(ProxyResolverFactoryMojoTest,
CreateProxyResolver_ResolverDisconnected_DeleteRequestInCallback) {
mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
CreateProxyResolverAction::DropClient(kScriptData));
scoped_refptr<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
net::TestCompletionCallback callback;
EXPECT_EQ(
net::ERR_PAC_SCRIPT_TERMINATED,
callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
pac_script, &proxy_resolver_mojo_,
base::BindOnce(&DeleteResolverFactoryRequestCallback, &request,
callback.callback()),
&request)));
}
TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Cancel) {
mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
CreateProxyResolverAction::WaitForClientDisconnect(kScriptData));
scoped_refptr<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
net::TestCompletionCallback callback;
EXPECT_EQ(
net::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();
}
TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_DnsRequest) {
mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
CreateProxyResolverAction::MakeDnsRequest(kScriptData));
scoped_refptr<net::PacFileData> pac_script(
net::PacFileData::FromUTF8(kScriptData));
std::unique_ptr<net::ProxyResolverFactory::Request> request;
net::TestCompletionCallback callback;
EXPECT_EQ(
net::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();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
EXPECT_THAT(request->WaitForResult(), IsOk());
EXPECT_EQ("DIRECT", request->results().ToPacString());
net::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();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
EXPECT_THAT(request->WaitForResult(), IsOk());
EXPECT_EQ(kPacString, request->results().ToPacString());
}
TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Error) {
mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnError(
GURL(kExampleUrl), net::ERR_UNEXPECTED));
CreateProxyResolver();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
EXPECT_THAT(request->WaitForResult(), IsError(net::ERR_UNEXPECTED));
EXPECT_TRUE(request->results().is_empty());
}
TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Cancel) {
mock_proxy_resolver_.AddGetProxyAction(
GetProxyForUrlAction::WaitForClientDisconnect(GURL(kExampleUrl)));
CreateProxyResolver();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
request->Cancel();
EXPECT_FALSE(request->callback().have_result());
// 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();
std::unique_ptr<Request> request1(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request1->Resolve(), IsError(net::ERR_IO_PENDING));
std::unique_ptr<Request> request2(
MakeRequest(GURL("https://www.chromium.org")));
EXPECT_THAT(request2->Resolve(), IsError(net::ERR_IO_PENDING));
EXPECT_THAT(request1->WaitForResult(), IsOk());
EXPECT_THAT(request2->WaitForResult(), IsOk());
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();
{
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
EXPECT_THAT(request->WaitForResult(),
IsError(net::ERR_PAC_SCRIPT_TERMINATED));
EXPECT_TRUE(request->results().is_empty());
}
// Run Watcher::OnHandleReady() tasks posted by Watcher::CallOnHandleReady().
base::RunLoop().RunUntilIdle();
{
// Calling GetProxyForURL after a disconnect should fail.
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request->Resolve(), IsError(net::ERR_PAC_SCRIPT_TERMINATED));
}
}
TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_ClientClosed) {
mock_proxy_resolver_.AddGetProxyAction(
GetProxyForUrlAction::DropRequest(GURL(kExampleUrl)));
CreateProxyResolver();
std::unique_ptr<Request> request1(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request1->Resolve(), IsError(net::ERR_IO_PENDING));
EXPECT_THAT(request1->WaitForResult(),
IsError(net::ERR_PAC_SCRIPT_TERMINATED));
}
TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DeleteInCallback) {
mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers(
GURL(kExampleUrl), ProxyServersFromPacString("DIRECT")));
CreateProxyResolver();
net::ProxyInfo results;
net::TestCompletionCallback callback;
std::unique_ptr<net::ProxyResolver::Request> request;
net::NetLogWithSource net_log;
EXPECT_EQ(net::OK,
callback.GetResult(proxy_resolver_mojo_->GetProxyForURL(
GURL(kExampleUrl), &results,
base::BindOnce(
&ProxyResolverFactoryMojoTest::DeleteProxyResolverCallback,
base::Unretained(this), callback.callback()),
&request, net_log)));
}
TEST_F(ProxyResolverFactoryMojoTest,
GetProxyForURL_DeleteInCallbackFromDisconnect) {
mock_proxy_resolver_.AddGetProxyAction(
GetProxyForUrlAction::Disconnect(GURL(kExampleUrl)));
CreateProxyResolver();
net::ProxyInfo results;
net::TestCompletionCallback callback;
std::unique_ptr<net::ProxyResolver::Request> request;
net::NetLogWithSource net_log;
EXPECT_EQ(net::ERR_PAC_SCRIPT_TERMINATED,
callback.GetResult(proxy_resolver_mojo_->GetProxyForURL(
GURL(kExampleUrl), &results,
base::BindOnce(
&ProxyResolverFactoryMojoTest::DeleteProxyResolverCallback,
base::Unretained(this), callback.callback()),
&request, net_log)));
}
TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DnsRequest) {
mock_proxy_resolver_.AddGetProxyAction(
GetProxyForUrlAction::MakeDnsRequest(GURL(kExampleUrl)));
CreateProxyResolver();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
EXPECT_EQ(net::LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->load_state());
host_resolver_.waiter().WaitForEvent(MockHostResolver::DNS_REQUEST);
EXPECT_EQ(net::LOAD_STATE_RESOLVING_HOST_IN_PAC_FILE, request->load_state());
mock_proxy_resolver_.ClearBlockedClients();
request->WaitForResult();
}
TEST_F(ProxyResolverFactoryMojoTest, DeleteResolver) {
CreateProxyResolver();
proxy_resolver_mojo_.reset();
}
} // namespace network