blob: 62119e09daf4b34a6b16194dcf5485e7650b2635 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/proxy_resolver_win/windows_system_proxy_resolver_impl.h"
#include <windows.h>
#include <winhttp.h>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/net_errors.h"
#include "net/base/proxy_server.h"
#include "net/base/proxy_string_util.h"
#include "net/proxy_resolution/proxy_config.h"
#include "net/proxy_resolution/proxy_list.h"
#include "net/proxy_resolution/win/windows_system_proxy_resolution_service.h"
#include "net/test/test_with_task_environment.h"
#include "services/proxy_resolver_win/public/mojom/proxy_resolver_win.mojom.h"
#include "services/proxy_resolver_win/winhttp_api_wrapper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace proxy_resolver_win {
namespace {
const GURL kUrl("https://example.test:8080/");
// This limit is arbitrary and exists only to make memory management in this
// test easier.
constexpr uint32_t kMaxProxyEntryLimit = 10u;
void CopySettingToIEProxyConfigString(const std::wstring& setting,
LPWSTR* ie_proxy_config_string) {
// The trailing null for the string is provided by GlobalAlloc, which
// zero-initializes the memory when using the GPTR flag.
*ie_proxy_config_string = static_cast<LPWSTR>(
GlobalAlloc(GPTR, sizeof(wchar_t) * (setting.length() + 1)));
memcpy(*ie_proxy_config_string, setting.data(),
sizeof(wchar_t) * setting.length());
}
// This class will internally validate behavior that MUST be present in the code
// in order to successfully use WinHttp APIs.
class MockWinHttpAPIWrapper final : public WinHttpAPIWrapper {
public:
MockWinHttpAPIWrapper() {}
~MockWinHttpAPIWrapper() override {
if (did_call_get_proxy_result_) {
EXPECT_TRUE(did_call_free_proxy_result_);
}
EXPECT_TRUE(opened_proxy_resolvers_.empty());
ResetWinHttpResults();
}
void set_call_winhttp_open_success(bool open_success) {
open_success_ = open_success;
}
bool CallWinHttpOpen() override {
did_call_open_ = true;
return open_success_;
}
void set_call_winhttp_set_timeouts_success(bool set_timeouts_success) {
set_timeouts_success_ = set_timeouts_success;
}
bool CallWinHttpSetTimeouts(int resolve_timeout,
int connect_timeout,
int send_timeout,
int receive_timeout) override {
EXPECT_TRUE(did_call_open_);
did_call_set_timeouts_ = true;
return set_timeouts_success_;
}
void set_call_winhttp_set_status_callback_success(
bool set_status_callback_success) {
set_status_callback_success_ = set_status_callback_success;
}
bool CallWinHttpSetStatusCallback(
WINHTTP_STATUS_CALLBACK internet_callback) override {
EXPECT_TRUE(did_call_open_);
EXPECT_NE(internet_callback, nullptr);
EXPECT_EQ(callback_, nullptr);
callback_ = internet_callback;
did_call_set_status_callback_ = true;
return set_status_callback_success_;
}
void set_call_winhttp_get_ie_proxy_config_success(
bool get_ie_proxy_config_success) {
get_ie_proxy_config_success_ = get_ie_proxy_config_success;
}
void set_ie_proxy_config(bool is_autoproxy_enabled,
const std::wstring& pac_url,
const std::wstring& proxy,
const std::wstring& proxy_bypass) {
is_autoproxy_enabled_ = is_autoproxy_enabled;
pac_url_ = pac_url;
proxy_ = proxy;
proxy_bypass_ = proxy_bypass;
}
bool CallWinHttpGetIEProxyConfigForCurrentUser(
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_proxy_config) override {
did_call_get_ie_proxy_config_ = true;
ie_proxy_config->fAutoDetect = is_autoproxy_enabled_ ? TRUE : FALSE;
if (!pac_url_.empty()) {
CopySettingToIEProxyConfigString(pac_url_,
&ie_proxy_config->lpszAutoConfigUrl);
}
if (!proxy_.empty()) {
CopySettingToIEProxyConfigString(proxy_, &ie_proxy_config->lpszProxy);
}
if (!proxy_bypass_.empty()) {
CopySettingToIEProxyConfigString(proxy_bypass_,
&ie_proxy_config->lpszProxyBypass);
}
return get_ie_proxy_config_success_;
}
void set_call_winhttp_create_proxy_resolver_success(
bool create_proxy_resolver_success) {
create_proxy_resolver_success_ = create_proxy_resolver_success;
}
bool CallWinHttpCreateProxyResolver(HINTERNET* out_resolver_handle) override {
EXPECT_TRUE(did_call_set_status_callback_);
EXPECT_NE(out_resolver_handle, nullptr);
if (!out_resolver_handle)
return false;
did_call_create_proxy_resolver_ = true;
if (!create_proxy_resolver_success_)
return false;
// The caller will be using this handle as an identifier later, so make this
// unique.
*out_resolver_handle =
reinterpret_cast<HINTERNET>(proxy_resolver_identifier_++);
EXPECT_EQ(opened_proxy_resolvers_.count(*out_resolver_handle), 0u);
opened_proxy_resolvers_.emplace(*out_resolver_handle);
return true;
}
void set_call_winhttp_get_proxy_for_url_success(
bool get_proxy_for_url_success) {
get_proxy_for_url_success_ = get_proxy_for_url_success;
}
bool CallWinHttpGetProxyForUrlEx(HINTERNET resolver_handle,
const std::string& url,
WINHTTP_AUTOPROXY_OPTIONS* autoproxy_options,
DWORD_PTR context) override {
// This API must be called only after the session has been correctly set up.
EXPECT_TRUE(did_call_open_);
EXPECT_TRUE(did_call_set_timeouts_);
EXPECT_TRUE(did_call_set_status_callback_);
EXPECT_NE(callback_, nullptr);
EXPECT_TRUE(did_call_get_ie_proxy_config_);
EXPECT_TRUE(did_call_create_proxy_resolver_);
EXPECT_TRUE(!did_call_get_proxy_result_);
EXPECT_TRUE(!did_call_free_proxy_result_);
// This API must always receive valid inputs.
EXPECT_TRUE(!url.empty());
EXPECT_TRUE(autoproxy_options);
EXPECT_FALSE(autoproxy_options->fAutoLogonIfChallenged);
EXPECT_TRUE(autoproxy_options->dwFlags & WINHTTP_AUTOPROXY_ALLOW_STATIC);
EXPECT_TRUE(autoproxy_options->dwFlags & WINHTTP_AUTOPROXY_ALLOW_CM);
if (autoproxy_options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) {
EXPECT_TRUE(autoproxy_options->lpszAutoConfigUrl);
} else {
EXPECT_TRUE(!autoproxy_options->lpszAutoConfigUrl);
}
if (autoproxy_options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) {
EXPECT_TRUE(autoproxy_options->dwAutoDetectFlags &
WINHTTP_AUTO_DETECT_TYPE_DNS_A);
EXPECT_TRUE(autoproxy_options->dwAutoDetectFlags &
WINHTTP_AUTO_DETECT_TYPE_DHCP);
} else {
EXPECT_TRUE(!autoproxy_options->dwAutoDetectFlags);
}
EXPECT_NE(resolver_handle, nullptr);
EXPECT_EQ(opened_proxy_resolvers_.count(resolver_handle), 1u);
EXPECT_NE(context, 0u);
if (!resolver_handle || !context || !callback_)
return false;
did_call_get_proxy_for_url_ = true;
if (!get_proxy_for_url_success_)
return false;
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&MockWinHttpAPIWrapper::RunCallback,
base::Unretained(this), resolver_handle, context));
return true;
}
void set_call_winhttp_get_proxy_result_success(
bool get_proxy_result_success) {
get_proxy_result_success_ = get_proxy_result_success;
}
void SetCallbackStatusAndInfo(DWORD callback_status, DWORD info_error) {
callback_status_ = callback_status;
callback_info_ = std::make_unique<WINHTTP_ASYNC_RESULT>();
callback_info_->dwError = info_error;
}
void AddBypassToProxyResults() {
ASSERT_LT(proxy_result_.cEntries, kMaxProxyEntryLimit - 1);
AllocateProxyResultEntriesIfNeeded();
proxy_result_.pEntries[proxy_result_.cEntries].fBypass = TRUE;
proxy_result_.cEntries++;
}
void AddDirectToProxyResults() {
ASSERT_LT(proxy_result_.cEntries, kMaxProxyEntryLimit - 1);
AllocateProxyResultEntriesIfNeeded();
proxy_result_.cEntries++;
}
void AddToProxyResults(INTERNET_SCHEME scheme,
std::wstring proxy_host,
INTERNET_PORT port) {
ASSERT_LT(proxy_result_.cEntries, kMaxProxyEntryLimit - 1);
AllocateProxyResultEntriesIfNeeded();
proxy_list_.push_back(std::move(proxy_host));
wchar_t* proxy_host_raw = const_cast<wchar_t*>(proxy_list_.back().data());
proxy_result_.pEntries[proxy_result_.cEntries].fProxy = TRUE;
proxy_result_.pEntries[proxy_result_.cEntries].ProxyScheme = scheme;
proxy_result_.pEntries[proxy_result_.cEntries].pwszProxy = proxy_host_raw;
proxy_result_.pEntries[proxy_result_.cEntries].ProxyPort = port;
proxy_result_.cEntries++;
}
bool CallWinHttpGetProxyResult(HINTERNET resolver_handle,
WINHTTP_PROXY_RESULT* proxy_result) override {
EXPECT_TRUE(did_call_get_proxy_for_url_);
EXPECT_NE(resolver_handle, nullptr);
EXPECT_EQ(opened_proxy_resolvers_.count(resolver_handle), 1u);
if (!get_proxy_result_success_)
return false;
EXPECT_NE(proxy_result, nullptr);
proxy_result->cEntries = proxy_result_.cEntries;
proxy_result->pEntries = proxy_result_.pEntries;
did_call_get_proxy_result_ = true;
return get_proxy_result_success_;
}
void CallWinHttpFreeProxyResult(WINHTTP_PROXY_RESULT* proxy_result) override {
EXPECT_TRUE(did_call_get_proxy_result_);
EXPECT_NE(proxy_result, nullptr);
did_call_free_proxy_result_ = true;
}
void CallWinHttpCloseHandle(HINTERNET internet_handle) override {
EXPECT_EQ(opened_proxy_resolvers_.count(internet_handle), 1u);
opened_proxy_resolvers_.erase(internet_handle);
}
void ResetWinHttpResults() {
if (proxy_result_.pEntries) {
delete[] proxy_result_.pEntries;
proxy_result_.pEntries = nullptr;
proxy_result_ = {0};
}
proxy_list_.clear();
}
base::WeakPtr<MockWinHttpAPIWrapper> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
void RunCallback(HINTERNET resolver_handle, DWORD_PTR context) {
EXPECT_NE(callback_, nullptr);
EXPECT_NE(resolver_handle, nullptr);
EXPECT_EQ(opened_proxy_resolvers_.count(resolver_handle), 1u);
EXPECT_NE(context, 0u);
callback_(resolver_handle, context, callback_status_, callback_info_.get(),
sizeof(callback_info_.get()));
// As soon as the callback resolves, WinHttp may choose to delete the memory
// contained by `callback_info_`. This is simulated here.
callback_info_.reset();
}
void AllocateProxyResultEntriesIfNeeded() {
if (proxy_result_.cEntries != 0)
return;
proxy_result_.pEntries =
new WINHTTP_PROXY_RESULT_ENTRY[kMaxProxyEntryLimit];
std::memset(proxy_result_.pEntries, 0,
kMaxProxyEntryLimit * sizeof(WINHTTP_PROXY_RESULT_ENTRY));
// The memory of the strings above will be backed by a vector of strings.
proxy_list_.reserve(kMaxProxyEntryLimit);
}
// Data configurable by tests to simulate errors and results from WinHttp.
bool open_success_ = true;
bool set_timeouts_success_ = true;
bool set_status_callback_success_ = true;
bool get_ie_proxy_config_success_ = true;
bool create_proxy_resolver_success_ = true;
bool get_proxy_for_url_success_ = true;
bool get_proxy_result_success_ = true;
DWORD callback_status_ = WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE;
std::unique_ptr<WINHTTP_ASYNC_RESULT> callback_info_;
bool is_autoproxy_enabled_ = false;
std::wstring pac_url_;
std::wstring proxy_;
std::wstring proxy_bypass_;
WINHTTP_PROXY_RESULT proxy_result_ = {0};
std::vector<std::wstring> proxy_list_;
// Data used internally in the mock to function and validate its own behavior.
bool did_call_open_ = false;
bool did_call_set_timeouts_ = false;
bool did_call_set_status_callback_ = false;
bool did_call_get_ie_proxy_config_ = false;
int proxy_resolver_identifier_ = 1;
std::set<HINTERNET> opened_proxy_resolvers_;
bool did_call_create_proxy_resolver_ = false;
bool did_call_get_proxy_for_url_ = false;
bool did_call_get_proxy_result_ = false;
bool did_call_free_proxy_result_ = false;
WINHTTP_STATUS_CALLBACK callback_ = nullptr;
base::WeakPtrFactory<MockWinHttpAPIWrapper> weak_factory_{this};
};
} // namespace
// These tests verify the behavior of the WindowsSystemProxyResolverImpl in
// isolation by mocking out the WinHttpAPIWrapper it uses.
class WindowsSystemProxyResolverImplTest : public testing::Test {
public:
void SetUp() override {
testing::Test::SetUp();
if (!net::WindowsSystemProxyResolutionService::IsSupported()) {
GTEST_SKIP()
<< "Windows System Proxy Resolution is only supported on Windows 8+.";
}
proxy_resolver_ = std::make_unique<WindowsSystemProxyResolverImpl>(
proxy_resolver_remote_.BindNewPipeAndPassReceiver());
auto winhttp_api_wrapper = std::make_unique<MockWinHttpAPIWrapper>();
winhttp_api_wrapper_ = winhttp_api_wrapper->GetWeakPtr();
proxy_resolver_->SetCreateWinHttpAPIWrapperForTesting(
std::move(winhttp_api_wrapper));
}
void TearDown() override {
ResetProxyResolutionService();
testing::Test::TearDown();
}
MockWinHttpAPIWrapper* winhttp_api_wrapper() {
return winhttp_api_wrapper_.get();
}
void ValidateProxyResult(base::OnceClosure closure,
const net::ProxyList& expected_proxy_list,
net::WinHttpStatus expected_winhttp_status,
int expected_windows_error,
const net::ProxyList& actual_proxy_list,
net::WinHttpStatus actual_winhttp_status,
int actual_windows_error) {
EXPECT_TRUE(expected_proxy_list.Equals(actual_proxy_list));
EXPECT_EQ(expected_winhttp_status, actual_winhttp_status);
EXPECT_EQ(expected_windows_error, actual_windows_error);
std::move(closure).Run();
}
void PerformGetProxyForUrlAndValidateResult(const net::ProxyList& proxy_list,
net::WinHttpStatus winhttp_status,
int windows_error) {
base::RunLoop run_loop;
proxy_resolver_remote_->GetProxyForUrl(
kUrl,
base::BindOnce(&WindowsSystemProxyResolverImplTest::ValidateProxyResult,
base::Unretained(this), run_loop.QuitClosure(),
proxy_list, winhttp_status, windows_error));
run_loop.Run();
}
// Tests that use DoFailedGetProxyForUrlTest validate failure conditions in
// WindowsSystemProxyResolverImpl.
void DoFailedGetProxyForUrlTest(net::WinHttpStatus winhttp_status,
int windows_error) {
::SetLastError(windows_error);
PerformGetProxyForUrlAndValidateResult(net::ProxyList(), winhttp_status,
windows_error);
}
// Tests that use DoProxyConfigTest validate that the proxy configs retrieved
// from Windows can be read by WindowsSystemProxyResolverImpl.
void DoProxyConfigTest(const net::ProxyConfig& proxy_config) {
winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy",
8443);
net::ProxyList proxy_list;
proxy_list.AddProxyServer(
net::PacResultElementToProxyServer("HTTPS foopy:8443"));
std::wstring pac_url;
if (proxy_config.has_pac_url())
pac_url = base::UTF8ToWide(proxy_config.pac_url().spec());
std::wstring proxy;
if (!proxy_config.proxy_rules().single_proxies.IsEmpty()) {
proxy = base::UTF8ToWide(
proxy_config.proxy_rules().single_proxies.ToDebugString());
}
std::wstring proxy_bypass;
if (!proxy_config.proxy_rules().bypass_rules.ToString().empty()) {
proxy_bypass =
base::UTF8ToWide(proxy_config.proxy_rules().bypass_rules.ToString());
}
winhttp_api_wrapper_->set_ie_proxy_config(proxy_config.auto_detect(),
pac_url, proxy, proxy_bypass);
PerformGetProxyForUrlAndValidateResult(proxy_list, net::WinHttpStatus::kOk,
0);
}
// Tests that use DoGetProxyForUrlTest validate successful proxy retrievals.
void DoGetProxyForUrlTest(const net::ProxyList& proxy_list) {
PerformGetProxyForUrlAndValidateResult(proxy_list, net::WinHttpStatus::kOk,
0);
}
void ResetProxyResolutionService() {
proxy_resolver_remote_.reset();
winhttp_api_wrapper_.reset();
proxy_resolver_.reset();
}
protected:
mojo::Remote<mojom::WindowsSystemProxyResolver> proxy_resolver_remote_;
private:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<WindowsSystemProxyResolverImpl> proxy_resolver_;
base::WeakPtr<MockWinHttpAPIWrapper> winhttp_api_wrapper_;
};
TEST_F(WindowsSystemProxyResolverImplTest, InitializeFailOnOpen) {
winhttp_api_wrapper()->set_call_winhttp_open_success(false);
DoFailedGetProxyForUrlTest(net::WinHttpStatus::kWinHttpOpenFailed, 0);
}
TEST_F(WindowsSystemProxyResolverImplTest, InitializeFailOnSetTimeouts) {
winhttp_api_wrapper()->set_call_winhttp_set_timeouts_success(false);
DoFailedGetProxyForUrlTest(net::WinHttpStatus::kWinHttpSetTimeoutsFailed, 0);
}
TEST_F(WindowsSystemProxyResolverImplTest, InitializeFailOnSetStatusCallback) {
winhttp_api_wrapper()->set_call_winhttp_set_status_callback_success(false);
DoFailedGetProxyForUrlTest(
net::WinHttpStatus::kWinHttpSetStatusCallbackFailed, 0);
}
TEST_F(WindowsSystemProxyResolverImplTest,
GetProxyForUrlFailOnGetIEProxySettings) {
winhttp_api_wrapper()->set_call_winhttp_get_ie_proxy_config_success(false);
DoFailedGetProxyForUrlTest(
net::WinHttpStatus::kWinHttpGetIEProxyConfigForCurrentUserFailed, 0);
}
TEST_F(WindowsSystemProxyResolverImplTest,
GetProxyForUrlFailOnCreateProxyResolver) {
winhttp_api_wrapper()->set_call_winhttp_create_proxy_resolver_success(false);
DoFailedGetProxyForUrlTest(
net::WinHttpStatus::kWinHttpCreateProxyResolverFailed, 0);
}
TEST_F(WindowsSystemProxyResolverImplTest,
GetProxyForUrlFailOnWinHttpGetProxyForUrlEx) {
winhttp_api_wrapper()->set_call_winhttp_get_proxy_for_url_success(false);
DoFailedGetProxyForUrlTest(net::WinHttpStatus::kWinHttpGetProxyForURLExFailed,
0);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlFailOnFailedCallback) {
winhttp_api_wrapper()->SetCallbackStatusAndInfo(
WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, API_RECEIVE_RESPONSE);
DoFailedGetProxyForUrlTest(net::WinHttpStatus::kStatusCallbackFailed,
API_RECEIVE_RESPONSE);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlFailOnGetProxyResult) {
winhttp_api_wrapper()->set_call_winhttp_get_proxy_result_success(false);
DoFailedGetProxyForUrlTest(net::WinHttpStatus::kWinHttpGetProxyResultFailed,
0);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlFailOnNoResults) {
DoFailedGetProxyForUrlTest(net::WinHttpStatus::kEmptyProxyList, 0);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlConfigDirect) {
DoProxyConfigTest(net::ProxyConfig::CreateDirect());
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlConfigAutoDetect) {
DoProxyConfigTest(net::ProxyConfig::CreateAutoDetect());
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlConfigPacUrl) {
const GURL pac_url("http://pac-site.test/path/to/pac-url.pac");
DoProxyConfigTest(net::ProxyConfig::CreateFromCustomPacURL(pac_url));
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlConfigSingleProxy) {
net::ProxyConfig config;
const net::ProxyServer proxy_server =
net::PacResultElementToProxyServer("HTTPS ignored:33");
config.proxy_rules().single_proxies.AddProxyServer(proxy_server);
DoProxyConfigTest(config);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlConfigBypass) {
net::ProxyConfig config;
config.proxy_rules().bypass_rules.AddRuleFromString("example.test");
DoProxyConfigTest(config);
}
TEST_F(WindowsSystemProxyResolverImplTest,
GetProxyForUrlConfigMultipleSettings) {
net::ProxyConfig config;
config.set_auto_detect(true);
const GURL pac_url("http://pac-site.test/path/to/pac-url.pac");
config.set_pac_url(pac_url);
const net::ProxyServer proxy_server =
net::PacResultElementToProxyServer("HTTPS ignored:33");
config.proxy_rules().single_proxies.AddProxyServer(proxy_server);
DoProxyConfigTest(config);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlDirect) {
winhttp_api_wrapper()->AddDirectToProxyResults();
net::ProxyList expected_proxy_list;
expected_proxy_list.AddProxyChain(net::ProxyChain::Direct());
DoGetProxyForUrlTest(expected_proxy_list);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlBypass) {
winhttp_api_wrapper()->AddBypassToProxyResults();
net::ProxyList expected_proxy_list;
expected_proxy_list.AddProxyChain(net::ProxyChain::Direct());
DoGetProxyForUrlTest(expected_proxy_list);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlHTTP) {
winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTP, L"foopy",
8080);
net::ProxyList expected_proxy_list;
expected_proxy_list.AddProxyServer(
net::PacResultElementToProxyServer("PROXY foopy:8080"));
DoGetProxyForUrlTest(expected_proxy_list);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlHTTPS) {
winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy",
8443);
net::ProxyList expected_proxy_list;
expected_proxy_list.AddProxyServer(
net::PacResultElementToProxyServer("HTTPS foopy:8443"));
DoGetProxyForUrlTest(expected_proxy_list);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlSOCKS) {
winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_SOCKS, L"foopy",
8080);
net::ProxyList expected_proxy_list;
expected_proxy_list.AddProxyServer(
net::PacResultElementToProxyServer("SOCKS4 foopy:8080"));
DoGetProxyForUrlTest(expected_proxy_list);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlIDNProxy) {
winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"föopy",
8080);
// Expect L"föopy" to be ascii-encoded as "xn--fopy-5qa".
net::ProxyList expected_proxy_list;
expected_proxy_list.AddProxyServer(
net::PacResultElementToProxyServer("HTTPS xn--fopy-5qa:8080"));
DoGetProxyForUrlTest(expected_proxy_list);
}
TEST_F(WindowsSystemProxyResolverImplTest,
GetProxyForUrlIgnoreInvalidProxyResults) {
winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTP, L"foopy",
INTERNET_DEFAULT_PORT);
winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_FTP, L"foopy", 80);
winhttp_api_wrapper()->AddDirectToProxyResults();
net::ProxyList expected_proxy_list;
expected_proxy_list.AddProxyChain(net::ProxyChain::Direct());
DoGetProxyForUrlTest(expected_proxy_list);
}
TEST_F(WindowsSystemProxyResolverImplTest, GetProxyForUrlMultipleResults) {
winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy",
8443);
winhttp_api_wrapper()->AddDirectToProxyResults();
net::ProxyList expected_proxy_list;
expected_proxy_list.AddProxyServer(
net::PacResultElementToProxyServer("HTTPS foopy:8443"));
expected_proxy_list.AddProxyChain(net::ProxyChain::Direct());
DoGetProxyForUrlTest(expected_proxy_list);
}
} // namespace proxy_resolver_win