diff --git a/include/pch.h b/include/pch.h index b22c0a1404..1a5b24180e 100644 --- a/include/pch.h +++ b/include/pch.h @@ -9,6 +9,7 @@ #include #include #include +#include #endif #include diff --git a/include/vcpkg/base/system.proxy.h b/include/vcpkg/base/system.proxy.h new file mode 100644 index 0000000000..a05aafa295 --- /dev/null +++ b/include/vcpkg/base/system.proxy.h @@ -0,0 +1,8 @@ +#pragma once +#include +#include +namespace vcpkg::System +{ + bool get_windows_proxy_enabled(); + std::optional get_windows_proxy_server(); +} \ No newline at end of file diff --git a/src/tls12-download.c b/src/tls12-download.c index 0a3a03fb4c..55b20ce466 100644 --- a/src/tls12-download.c +++ b/src/tls12-download.c @@ -1,6 +1,45 @@ #include #include #include + +/* + * 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 +/* + * 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 @@ -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; diff --git a/src/vcpkg/base/downloads.cpp b/src/vcpkg/base/downloads.cpp index 9fd3351d0e..85a0104231 100644 --- a/src/vcpkg/base/downloads.cpp +++ b/src/vcpkg/base/downloads.cpp @@ -8,10 +8,6 @@ #include #include -#if defined(_WIN32) -#include -#endif - namespace vcpkg::Downloads { #if defined(_WIN32) @@ -93,8 +89,7 @@ namespace vcpkg::Downloads static ExpectedS 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); @@ -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); } } diff --git a/src/vcpkg/base/system.proxy.cpp b/src/vcpkg/base/system.proxy.cpp new file mode 100644 index 0000000000..d859b144dc --- /dev/null +++ b/src/vcpkg/base/system.proxy.cpp @@ -0,0 +1,40 @@ +#include +std::optional 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 +} \ No newline at end of file diff --git a/src/vcpkg/build.cpp b/src/vcpkg/build.cpp index 0a22425f3e..e1e32bc0e8 100644 --- a/src/vcpkg/build.cpp +++ b/src/vcpkg/build.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -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}; });