Skip to content
1 change: 1 addition & 0 deletions include/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <process.h>
#include <shellapi.h>
#include <winhttp.h>
#include <winreg.h>
#endif

#include <math.h>
Expand Down
8 changes: 8 additions & 0 deletions include/vcpkg/base/system.proxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once
#include <optional>
#include <string>
namespace vcpkg::System
{
bool get_windows_proxy_enabled();
std::optional<std::string> get_windows_proxy_server();
}
45 changes: 44 additions & 1 deletion src/tls12-download.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
#include <Windows.h>
#include <process.h>
#include <winhttp.h>

/*
* Instead of WPAD, on Windows platform it is a user-friendly way to check
* HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings
* instead of only checking HTTPS_PROXY. Because most proxies on Windows
* doesn't set these environment variables.
*/
#include <winreg.h>
/*
* This helper function reads proxy settings from registry, returns 1 if succeed
* and copy the proxy setting in outProxyBuffer, returns 0 if failed.
*
* According to the code below we can say the buffer's size passed in is 32767,
* which is for sure enough for reading proxy server from registry. So the size
* check is skipped.
*/
static int GetWindowsProxyFromRegistry(wchar_t* outProxyBuffer)
{
HKEY proxy_reg;
DWORD len = 0;
DWORD enable = 0;

int ret =
RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &proxy_reg);
if (ret) return 0;

len = 4;
ret = RegGetValueW(proxy_reg, NULL, L"ProxyEnable", RRF_RT_REG_DWORD, NULL, &enable, &len);
if (ret) return 0;

if (!enable) return 0;

len = 32767;
ret = RegGetValueW(proxy_reg, NULL, L"ProxyServer", RRF_RT_REG_SZ, NULL, outProxyBuffer, &len);
if (ret) return 0;

return 1;
}

/*
* This program must be as small as possible, because it is committed in binary form to the
* vcpkg github repo to enable downloading the main vcpkg program on Windows 7, where TLS 1.2 is
Expand Down Expand Up @@ -188,7 +227,11 @@ int __stdcall entry()
DWORD access_type;
const wchar_t* proxy_setting;
const wchar_t* proxy_bypass_setting;
if (GetEnvironmentVariableW(L"HTTPS_PROXY", https_proxy_env, sizeof(https_proxy_env) / sizeof(wchar_t)))
if (GetEnvironmentVariableW(L"HTTPS_PROXY", https_proxy_env, sizeof(https_proxy_env) / sizeof(wchar_t))
/*
* Check the windows proxy setting in registry too.
*/
|| GetWindowsProxyFromRegistry(https_proxy_env))
{
access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
proxy_setting = https_proxy_env;
Expand Down
44 changes: 15 additions & 29 deletions src/vcpkg/base/downloads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
#include <vcpkg/base/system.process.h>
#include <vcpkg/base/util.h>

#if defined(_WIN32)
#include <VersionHelpers.h>
#endif

namespace vcpkg::Downloads
{
#if defined(_WIN32)
Expand Down Expand Up @@ -93,8 +89,7 @@ namespace vcpkg::Downloads
static ExpectedS<WinHttpSession> make()
{
auto h = WinHttpOpen(L"vcpkg/1.0",
IsWindows8Point1OrGreater() ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
: WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
Expand All @@ -116,31 +111,22 @@ namespace vcpkg::Downloads

WinHttpSetOption(ret.m_hSession.get(), WINHTTP_OPTION_PROXY, &proxy, sizeof(proxy));
}
// Win7 IE Proxy fallback
else if (IsWindows7OrGreater() && !IsWindows8Point1OrGreater())
// IE Proxy fallback, this works on Windows 10
else
{
// First check if any proxy has been found automatically
WINHTTP_PROXY_INFO proxyInfo;
DWORD proxyInfoSize = sizeof(WINHTTP_PROXY_INFO);
auto noProxyFound =
!WinHttpQueryOption(ret.m_hSession.get(), WINHTTP_OPTION_PROXY, &proxyInfo, &proxyInfoSize) ||
proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY;

// If no proxy was found automatically, use IE's proxy settings, if any
if (noProxyFound)
// We do not use WPAD anymore
// Directly read IE Proxy setting
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxy;
if (WinHttpGetIEProxyConfigForCurrentUser(&ieProxy) && ieProxy.lpszProxy != nullptr)
{
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxy;
if (WinHttpGetIEProxyConfigForCurrentUser(&ieProxy) && ieProxy.lpszProxy != nullptr)
{
WINHTTP_PROXY_INFO proxy;
proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
proxy.lpszProxy = ieProxy.lpszProxy;
proxy.lpszProxyBypass = ieProxy.lpszProxyBypass;
WinHttpSetOption(ret.m_hSession.get(), WINHTTP_OPTION_PROXY, &proxy, sizeof(proxy));
GlobalFree(ieProxy.lpszProxy);
GlobalFree(ieProxy.lpszProxyBypass);
GlobalFree(ieProxy.lpszAutoConfigUrl);
}
WINHTTP_PROXY_INFO proxy;
proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
proxy.lpszProxy = ieProxy.lpszProxy;
proxy.lpszProxyBypass = ieProxy.lpszProxyBypass;
WinHttpSetOption(ret.m_hSession.get(), WINHTTP_OPTION_PROXY, &proxy, sizeof(proxy));
GlobalFree(ieProxy.lpszProxy);
GlobalFree(ieProxy.lpszProxyBypass);
GlobalFree(ieProxy.lpszAutoConfigUrl);
}
}

Expand Down
40 changes: 40 additions & 0 deletions src/vcpkg/base/system.proxy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <vcpkg/base/system.proxy.h>
std::optional<std::string> vcpkg::System::get_windows_proxy_server()
{
#if defined(_WIN32)
HKEY proxy_reg;
DWORD buf_len = 0;

auto ret =
RegOpenKey(HKEY_CURRENT_USER, R"(Software\Microsoft\Windows\CurrentVersion\Internet Settings)", &proxy_reg);
if (ret) return nullptr;

ret = RegGetValue(proxy_reg, nullptr, "ProxyServer", RRF_RT_REG_SZ, nullptr, nullptr, &buf_len);
if (ret) return nullptr;

std::string srv(buf_len, '\0');
ret = RegGetValue(proxy_reg, nullptr, "ProxyServer", RRF_RT_REG_SZ, nullptr, srv.data(), &buf_len);
if (ret) return nullptr;

return srv;
#else
return nullptr;
#endif
}
bool vcpkg::System::get_windows_proxy_enabled()
{
#if defined(_WIN32)
HKEY proxy_reg;
DWORD enable = 0;
DWORD len = 4;

auto ret =
RegOpenKey(HKEY_CURRENT_USER, R"(Software\Microsoft\Windows\CurrentVersion\Internet Settings)", &proxy_reg);

ret = RegGetValue(proxy_reg, nullptr, "ProxyEnable", RRF_RT_REG_DWORD, nullptr, &enable, &len);

return enable;
#else
return false;
#endif
}
19 changes: 19 additions & 0 deletions src/vcpkg/build.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <vcpkg/base/system.debug.h>
#include <vcpkg/base/system.print.h>
#include <vcpkg/base/system.process.h>
#include <vcpkg/base/system.proxy.h>
#include <vcpkg/base/util.h>

#include <vcpkg/binarycaching.h>
Expand Down Expand Up @@ -396,6 +397,24 @@ namespace vcpkg::Build
if (auto p_val = val.get()) env.emplace(var, *p_val);
}

/*
* On Windows 10 (>= 8.1) it is a user-friendly way to automatically set HTTP_PROXY and HTTPS_PROXY
* environment variables by reading proxy settings via WinHttpGetDefaultProxyConfiguration, preventing users
* set and unset these variables manually (which is not a decent way).
*/
if (System::get_windows_proxy_enabled())
{
auto proxy = System::get_windows_proxy_server();
if (proxy.has_value())
{
// Most HTTP proxy DOES proxy HTTPS requests.
env.emplace("HTTP_PROXY", proxy.value().c_str());
env.emplace("HTTPS_PROXY", proxy.value().c_str());

System::print2(
"-- Automatically setting HTTP(S)_PROXY environment variables to ", proxy.value(), "\n");
}
}
return {env};
});

Expand Down