From 17d79996a4c775b0be4d23785c38a5bc609d5c8b Mon Sep 17 00:00:00 2001 From: eternalphane Date: Sun, 5 Dec 2021 23:42:04 +0800 Subject: [PATCH 1/6] add proxy settings --- src/AppInstallerCommonCore/Downloader.cpp | 27 +++++++++++++++++-- .../Public/winget/UserSettings.h | 2 ++ src/AppInstallerCommonCore/UserSettings.cpp | 2 ++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/AppInstallerCommonCore/Downloader.cpp b/src/AppInstallerCommonCore/Downloader.cpp index 5f77cfdd14..c74b5e243b 100644 --- a/src/AppInstallerCommonCore/Downloader.cpp +++ b/src/AppInstallerCommonCore/Downloader.cpp @@ -11,6 +11,8 @@ #include "Public/AppInstallerTelemetry.h" #include "Public/winget/UserSettings.h" #include "DODownloader.h" +#include +#include using namespace AppInstaller::Runtime; using namespace AppInstaller::Settings; @@ -29,10 +31,31 @@ namespace AppInstaller::Utility AICLI_LOG(Core, Info, << "WinINet downloading from url: " << url); + auto proxy = User().Get(); + if (proxy.empty()) + { + std::wstring allProxy; + wil::GetEnvironmentVariableW(L"ALL_PROXY", allProxy); + proxy = Utility::ConvertToUTF8(allProxy); + if (proxy.empty()) + { + std::wstring httpProxy, httpsProxy, ftpProxy; + wil::GetEnvironmentVariableW(L"HTTP_PROXY", httpProxy); + wil::GetEnvironmentVariableW(L"HTTPS_PROXY", httpsProxy); + wil::GetEnvironmentVariableW(L"FTP_PROXY", ftpProxy); + if (!httpProxy.empty()) + proxy = "HTTP=" + Utility::ConvertToUTF8(httpProxy); + if (!httpsProxy.empty()) + proxy += (proxy.empty() ? "HTTPS=" : " HTTPS=") + Utility::ConvertToUTF8(httpsProxy); + if (!ftpProxy.empty()) + proxy += (proxy.empty() ? "FTP=" : " FTP=") + Utility::ConvertToUTF8(ftpProxy); + } + } + wil::unique_hinternet session(InternetOpenA( "winget-cli", - INTERNET_OPEN_TYPE_PRECONFIG, - NULL, + proxy.empty() ? INTERNET_OPEN_TYPE_PRECONFIG : INTERNET_OPEN_TYPE_PROXY, + proxy.empty() ? NULL : proxy.c_str(), NULL, 0)); THROW_LAST_ERROR_IF_NULL_MSG(session, "InternetOpen() failed."); diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h index 7cf95b2ec1..cb9a6d662c 100644 --- a/src/AppInstallerCommonCore/Public/winget/UserSettings.h +++ b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -76,6 +76,7 @@ namespace AppInstaller::Settings InstallScopeRequirement, NetworkDownloader, NetworkDOProgressTimeoutInSeconds, + NetworkProxy, InstallArchitecturePreference, InstallArchitectureRequirement, InstallLocalePreference, @@ -127,6 +128,7 @@ namespace AppInstaller::Settings SETTINGMAPPING_SPECIALIZATION(Setting::InstallScopeRequirement, std::string, ScopePreference, ScopePreference::None, ".installBehavior.requirements.scope"sv); SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDownloader, std::string, InstallerDownloader, InstallerDownloader::Default, ".network.downloader"sv); SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDOProgressTimeoutInSeconds, uint32_t, std::chrono::seconds, 60s, ".network.doProgressTimeoutInSeconds"sv); + SETTINGMAPPING_SPECIALIZATION(Setting::NetworkProxy, std::string, std::string, {}, ".network.proxy"sv); SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocalePreference, std::vector, std::vector, {}, ".installBehavior.preferences.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocaleRequirement, std::vector, std::vector, {}, ".installBehavior.requirements.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::EFDirectMSI, bool, bool, false, ".experimentalFeatures.directMSI"sv); diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp index 8ea3b34585..8e26a28c3f 100644 --- a/src/AppInstallerCommonCore/UserSettings.cpp +++ b/src/AppInstallerCommonCore/UserSettings.cpp @@ -316,6 +316,8 @@ namespace AppInstaller::Settings { return std::chrono::seconds(value); } + + WINGET_VALIDATE_PASS_THROUGH(NetworkProxy) } #ifndef AICLI_DISABLE_TEST_HOOKS From 366df5448737f73b440fa065df00e6273030bd2d Mon Sep 17 00:00:00 2001 From: eternalphane Date: Mon, 6 Dec 2021 01:05:53 +0800 Subject: [PATCH 2/6] add proxyOverride settings --- src/AppInstallerCommonCore/Downloader.cpp | 12 +++++++++--- .../Public/winget/UserSettings.h | 2 ++ src/AppInstallerCommonCore/UserSettings.cpp | 8 ++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/AppInstallerCommonCore/Downloader.cpp b/src/AppInstallerCommonCore/Downloader.cpp index c74b5e243b..3eb3fc2092 100644 --- a/src/AppInstallerCommonCore/Downloader.cpp +++ b/src/AppInstallerCommonCore/Downloader.cpp @@ -36,8 +36,7 @@ namespace AppInstaller::Utility { std::wstring allProxy; wil::GetEnvironmentVariableW(L"ALL_PROXY", allProxy); - proxy = Utility::ConvertToUTF8(allProxy); - if (proxy.empty()) + if ((proxy = Utility::ConvertToUTF8(allProxy)).empty()) { std::wstring httpProxy, httpsProxy, ftpProxy; wil::GetEnvironmentVariableW(L"HTTP_PROXY", httpProxy); @@ -51,12 +50,19 @@ namespace AppInstaller::Utility proxy += (proxy.empty() ? "FTP=" : " FTP=") + Utility::ConvertToUTF8(ftpProxy); } } + auto proxyOverride = User().Get(); + if (proxyOverride.empty()) + { + std::wstring noProxy; + wil::GetEnvironmentVariableW(L"NO_PROXY", noProxy); + proxyOverride = Utility::ConvertToUTF8(noProxy); + } wil::unique_hinternet session(InternetOpenA( "winget-cli", proxy.empty() ? INTERNET_OPEN_TYPE_PRECONFIG : INTERNET_OPEN_TYPE_PROXY, proxy.empty() ? NULL : proxy.c_str(), - NULL, + proxyOverride.empty() ? NULL : proxyOverride.c_str(), 0)); THROW_LAST_ERROR_IF_NULL_MSG(session, "InternetOpen() failed."); diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h index cb9a6d662c..4296295822 100644 --- a/src/AppInstallerCommonCore/Public/winget/UserSettings.h +++ b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -77,6 +77,7 @@ namespace AppInstaller::Settings NetworkDownloader, NetworkDOProgressTimeoutInSeconds, NetworkProxy, + NetworkProxyOverride, InstallArchitecturePreference, InstallArchitectureRequirement, InstallLocalePreference, @@ -129,6 +130,7 @@ namespace AppInstaller::Settings SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDownloader, std::string, InstallerDownloader, InstallerDownloader::Default, ".network.downloader"sv); SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDOProgressTimeoutInSeconds, uint32_t, std::chrono::seconds, 60s, ".network.doProgressTimeoutInSeconds"sv); SETTINGMAPPING_SPECIALIZATION(Setting::NetworkProxy, std::string, std::string, {}, ".network.proxy"sv); + SETTINGMAPPING_SPECIALIZATION(Setting::NetworkProxyOverride, std::vector, std::string, {}, ".network.proxyOverride"sv); SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocalePreference, std::vector, std::vector, {}, ".installBehavior.preferences.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocaleRequirement, std::vector, std::vector, {}, ".installBehavior.requirements.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::EFDirectMSI, bool, bool, false, ".experimentalFeatures.directMSI"sv); diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp index 8e26a28c3f..394c5e59cd 100644 --- a/src/AppInstallerCommonCore/UserSettings.cpp +++ b/src/AppInstallerCommonCore/UserSettings.cpp @@ -10,6 +10,7 @@ #include "AppInstallerArchitecture.h" #include "winget/Locale.h" +#include namespace AppInstaller::Settings { @@ -318,6 +319,13 @@ namespace AppInstaller::Settings } WINGET_VALIDATE_PASS_THROUGH(NetworkProxy) + + WINGET_VALIDATE_SIGNATURE(NetworkProxyOverride) + { + if (value.empty()) + return {}; + return std::accumulate(std::next(value.begin()), value.end(), value[0], [](auto& a, auto& b) { return a + ';' + b; }); + } } #ifndef AICLI_DISABLE_TEST_HOOKS From fb5430de8e80b62656875b86c5a6f23ea405af79 Mon Sep 17 00:00:00 2001 From: eternalphane Date: Sat, 11 Dec 2021 11:53:56 +0800 Subject: [PATCH 3/6] add options for proxy support --- src/AppInstallerCLICore/Argument.cpp | 4 + .../Commands/InstallCommand.cpp | 2 + .../Commands/UpgradeCommand.cpp | 2 + src/AppInstallerCLICore/ExecutionArgs.h | 4 + .../ExecutionContextData.h | 8 ++ src/AppInstallerCLICore/Resources.h | 2 + .../Workflows/DownloadFlow.cpp | 13 +++- .../Workflows/DownloadFlow.h | 6 ++ .../Workflows/InstallFlow.cpp | 1 + .../Workflows/UpdateFlow.cpp | 3 + .../Shared/Strings/en-us/winget.resw | 6 ++ src/AppInstallerCommonCore/Downloader.cpp | 77 ++++++++++--------- .../Public/AppInstallerDownloader.h | 19 ++++- 13 files changed, 107 insertions(+), 40 deletions(-) diff --git a/src/AppInstallerCLICore/Argument.cpp b/src/AppInstallerCLICore/Argument.cpp index d7cf9dd0ec..36eb3a887d 100644 --- a/src/AppInstallerCLICore/Argument.cpp +++ b/src/AppInstallerCLICore/Argument.cpp @@ -60,6 +60,10 @@ namespace AppInstaller::CLI return Argument{ "file", 'f', Args::Type::HashFile, Resource::String::FileArgumentDescription, ArgumentType::Positional, true }; case Args::Type::Msix: return Argument{ "msix", 'm', Args::Type::Msix, Resource::String::MsixArgumentDescription, ArgumentType::Flag }; + case Args::Type::NetworkProxy: + return Argument{ "proxy", NoAlias, Args::Type::NetworkProxy, Resource::String::NetworkProxyArgumentDescription, ArgumentType::Standard, Visibility::Help }; + case Args::Type::NetworkProxyOverride: + return Argument{ "no-proxy", NoAlias, Args::Type::NetworkProxyOverride, Resource::String::NetworkProxyOverrideArgumentDescription, ArgumentType::Standard, Visibility::Help }; case Args::Type::ListVersions: return Argument{ "versions", NoAlias, Args::Type::ListVersions, Resource::String::VersionsArgumentDescription, ArgumentType::Flag }; case Args::Type::Help: diff --git a/src/AppInstallerCLICore/Commands/InstallCommand.cpp b/src/AppInstallerCLICore/Commands/InstallCommand.cpp index 9ae6d2b338..5a859ad1f5 100644 --- a/src/AppInstallerCLICore/Commands/InstallCommand.cpp +++ b/src/AppInstallerCLICore/Commands/InstallCommand.cpp @@ -43,6 +43,8 @@ namespace AppInstaller::CLI Argument::ForType(Args::Type::HashOverride), Argument::ForType(Args::Type::DependencySource), Argument::ForType(Args::Type::AcceptPackageAgreements), + Argument::ForType(Args::Type::NetworkProxy), + Argument::ForType(Args::Type::NetworkProxyOverride), Argument::ForType(Args::Type::CustomHeader), Argument::ForType(Args::Type::AcceptSourceAgreements), }; diff --git a/src/AppInstallerCLICore/Commands/UpgradeCommand.cpp b/src/AppInstallerCLICore/Commands/UpgradeCommand.cpp index 783cd32252..0ffecff212 100644 --- a/src/AppInstallerCLICore/Commands/UpgradeCommand.cpp +++ b/src/AppInstallerCLICore/Commands/UpgradeCommand.cpp @@ -43,6 +43,8 @@ namespace AppInstaller::CLI Argument::ForType(Args::Type::InstallLocation), Argument::ForType(Args::Type::HashOverride), Argument::ForType(Args::Type::AcceptPackageAgreements), + Argument::ForType(Args::Type::NetworkProxy), + Argument::ForType(Args::Type::NetworkProxyOverride), Argument::ForType(Args::Type::AcceptSourceAgreements), Argument::ForType(Execution::Args::Type::CustomHeader), Argument{ "all", Argument::NoAlias, Args::Type::All, Resource::String::UpdateAllArgumentDescription, ArgumentType::Flag }, diff --git a/src/AppInstallerCLICore/ExecutionArgs.h b/src/AppInstallerCLICore/ExecutionArgs.h index 5632992b75..fb963fbc5a 100644 --- a/src/AppInstallerCLICore/ExecutionArgs.h +++ b/src/AppInstallerCLICore/ExecutionArgs.h @@ -73,6 +73,10 @@ namespace AppInstaller::CLI::Execution AdminSettingEnable, AdminSettingDisable, + // Network Behavior + NetworkProxy, + NetworkProxyOverride, + // Other All, // Used in Update command to update all installed packages to latest ListVersions, // Used in Show command to list all available versions of an app diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index d37abc7b12..2349ac4990 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -6,6 +6,7 @@ #include "CompletionData.h" #include "PackageCollection.h" #include "Workflows/WorkflowBase.h" +#include "AppInstallerDownloader.h" #include #include @@ -50,6 +51,7 @@ namespace AppInstaller::CLI::Execution Dependencies, DependencySource, AllowedArchitectures, + NetworkProxyInfo, Max }; @@ -207,5 +209,11 @@ namespace AppInstaller::CLI::Execution { using value_t = std::vector; }; + + template <> + struct DataMapping + { + using value_t = Utility::ProxyInfo; + }; } } diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 09629e5437..d27809f36f 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -181,6 +181,8 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(MultipleInstalledPackagesFound); WINGET_DEFINE_RESOURCE_STRINGID(MultiplePackagesFound); WINGET_DEFINE_RESOURCE_STRINGID(NameArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(NetworkProxyArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(NetworkProxyOverrideArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(NoApplicableInstallers); WINGET_DEFINE_RESOURCE_STRINGID(NoExperimentalFeaturesMessage); WINGET_DEFINE_RESOURCE_STRINGID(NoInstalledPackageFound); diff --git a/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp b/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp index 06fca0ad86..481d98e26a 100644 --- a/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp @@ -185,6 +185,16 @@ namespace AppInstaller::CLI::Workflow } } + void GetProxyInfo(Execution::Context& context) + { + auto proxy = context.Args.GetArg(Execution::Args::Type::NetworkProxy); + auto proxyOverride = context.Args.GetArg(Execution::Args::Type::NetworkProxyOverride); + if (!proxy.empty() || !proxyOverride.empty()) + context.Add({std::string{proxy}, std::string{proxyOverride}}); + else + context.Add(Utility::GetProxyInfo()); + } + void DownloadInstaller(Execution::Context& context) { // Check if file was already downloaded. @@ -308,7 +318,8 @@ namespace AppInstaller::CLI::Workflow Utility::DownloadType::Installer, std::placeholders::_1, true, - downloadInfo)); + downloadInfo, + context.Get())); success = true; } diff --git a/src/AppInstallerCLICore/Workflows/DownloadFlow.h b/src/AppInstallerCLICore/Workflows/DownloadFlow.h index 744de69467..fadd626b4a 100644 --- a/src/AppInstallerCLICore/Workflows/DownloadFlow.h +++ b/src/AppInstallerCLICore/Workflows/DownloadFlow.h @@ -5,6 +5,12 @@ namespace AppInstaller::CLI::Workflow { + // Gets the proxy settings + // Required Args: None + // Inputs: None + // Outputs: None + void GetProxyInfo(Execution::Context& context); + // Composite flow that chooses what to do based on the installer type. // Required Args: None // Inputs: Manifest, Installer diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 7f3712e4e1..8ff8fcb428 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -388,6 +388,7 @@ namespace AppInstaller::CLI::Workflow void InstallSinglePackage(Execution::Context& context) { context << + GetProxyInfo << Workflow::DownloadSinglePackage << Workflow::InstallPackageInstaller; } diff --git a/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp b/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp index a64924d1e3..cf4b4de2f8 100644 --- a/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp @@ -6,6 +6,7 @@ #include "DependenciesFlow.h" #include "InstallFlow.h" #include "UpdateFlow.h" +#include "DownloadFlow.h" #include "ManifestComparator.h" using namespace AppInstaller::Repository; @@ -129,6 +130,8 @@ namespace AppInstaller::CLI::Workflow void UpdateAllApplicable(Execution::Context& context) { + context << GetProxyInfo; + const auto& matches = context.Get().Matches; std::vector> packagesToInstall; bool updateAllFoundUpdate = false; diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 9600bf50eb..cbe4da7b2c 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1250,4 +1250,10 @@ Please specify one of them using the `--source` option to proceed. Select the architecture to install + + Use the specified proxy + + + Comma-separated list of hosts where proxy should not be used + \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Downloader.cpp b/src/AppInstallerCommonCore/Downloader.cpp index 3eb3fc2092..4720478dbd 100644 --- a/src/AppInstallerCommonCore/Downloader.cpp +++ b/src/AppInstallerCommonCore/Downloader.cpp @@ -23,46 +23,22 @@ namespace AppInstaller::Utility const std::string& url, std::ostream& dest, IProgressCallback& progress, - bool computeHash) + bool computeHash, + ProxyInfo info) { // For AICLI_LOG usages with string literals. #pragma warning(push) #pragma warning(disable:26449) AICLI_LOG(Core, Info, << "WinINet downloading from url: " << url); - - auto proxy = User().Get(); - if (proxy.empty()) - { - std::wstring allProxy; - wil::GetEnvironmentVariableW(L"ALL_PROXY", allProxy); - if ((proxy = Utility::ConvertToUTF8(allProxy)).empty()) - { - std::wstring httpProxy, httpsProxy, ftpProxy; - wil::GetEnvironmentVariableW(L"HTTP_PROXY", httpProxy); - wil::GetEnvironmentVariableW(L"HTTPS_PROXY", httpsProxy); - wil::GetEnvironmentVariableW(L"FTP_PROXY", ftpProxy); - if (!httpProxy.empty()) - proxy = "HTTP=" + Utility::ConvertToUTF8(httpProxy); - if (!httpsProxy.empty()) - proxy += (proxy.empty() ? "HTTPS=" : " HTTPS=") + Utility::ConvertToUTF8(httpsProxy); - if (!ftpProxy.empty()) - proxy += (proxy.empty() ? "FTP=" : " FTP=") + Utility::ConvertToUTF8(ftpProxy); - } - } - auto proxyOverride = User().Get(); - if (proxyOverride.empty()) - { - std::wstring noProxy; - wil::GetEnvironmentVariableW(L"NO_PROXY", noProxy); - proxyOverride = Utility::ConvertToUTF8(noProxy); - } + AICLI_LOG(Core, Info, << "Proxy: " << info.Proxy); + AICLI_LOG(Core, Info, << "Proxy Bypass: " << info.ProxyOverride); wil::unique_hinternet session(InternetOpenA( "winget-cli", - proxy.empty() ? INTERNET_OPEN_TYPE_PRECONFIG : INTERNET_OPEN_TYPE_PROXY, - proxy.empty() ? NULL : proxy.c_str(), - proxyOverride.empty() ? NULL : proxyOverride.c_str(), + info.Proxy.empty() ? INTERNET_OPEN_TYPE_PRECONFIG : INTERNET_OPEN_TYPE_PROXY, + info.Proxy.empty() ? NULL : info.Proxy.data(), + info.ProxyOverride.empty() ? NULL : info.ProxyOverride.data(), 0)); THROW_LAST_ERROR_IF_NULL_MSG(session, "InternetOpen() failed."); @@ -165,6 +141,36 @@ namespace AppInstaller::Utility return result; } + ProxyInfo GetProxyInfo() + { + ProxyInfo info; + if ((info.Proxy = Settings::User().Get()).empty()) + { + std::wstring allProxy; + wil::GetEnvironmentVariableW(L"ALL_PROXY", allProxy); + if ((info.Proxy = Utility::ConvertToUTF8(allProxy)).empty()) + { + std::wstring httpProxy, httpsProxy, ftpProxy; + wil::GetEnvironmentVariableW(L"HTTP_PROXY", httpProxy); + wil::GetEnvironmentVariableW(L"HTTPS_PROXY", httpsProxy); + wil::GetEnvironmentVariableW(L"FTP_PROXY", ftpProxy); + if (!httpProxy.empty()) + info.Proxy = "HTTP=" + Utility::ConvertToUTF8(httpProxy); + if (!httpsProxy.empty()) + info.Proxy += (info.Proxy.empty() ? "HTTPS=" : " HTTPS=") + Utility::ConvertToUTF8(httpsProxy); + if (!ftpProxy.empty()) + info.Proxy += (info.Proxy.empty() ? "FTP=" : " FTP=") + Utility::ConvertToUTF8(ftpProxy); + } + } + if ((info.ProxyOverride = Settings::User().Get()).empty()) + { + std::wstring noProxy; + wil::GetEnvironmentVariableW(L"NO_PROXY", noProxy); + info.ProxyOverride = Utility::ConvertToUTF8(noProxy); + } + return std::move(info); + } + std::optional> DownloadToStream( const std::string& url, std::ostream& dest, @@ -174,7 +180,7 @@ namespace AppInstaller::Utility std::optional) { THROW_HR_IF(E_INVALIDARG, url.empty()); - return WinINetDownloadToStream(url, dest, progress, computeHash); + return WinINetDownloadToStream(url, dest, progress, computeHash, GetProxyInfo()); } std::optional> Download( @@ -183,7 +189,8 @@ namespace AppInstaller::Utility DownloadType type, IProgressCallback& progress, bool computeHash, - std::optional info) + std::optional downloadInfo, + std::optional proxyInfo) { THROW_HR_IF(E_INVALIDARG, url.empty()); THROW_HR_IF(E_INVALIDARG, dest.empty()); @@ -206,7 +213,7 @@ namespace AppInstaller::Utility { try { - auto result = DODownload(url, dest, progress, computeHash, info); + auto result = DODownload(url, dest, progress, computeHash, downloadInfo); // Since we cannot pre-apply to the file with DO, post-apply the MotW to the file. // Only do so if the file exists, because cancellation will not throw here. if (std::filesystem::exists(dest)) @@ -248,7 +255,7 @@ namespace AppInstaller::Utility // Use std::ofstream::app to append to previous empty file so that it will not // create a new file and clear motw. std::ofstream outfile(dest, std::ofstream::binary | std::ofstream::app); - return WinINetDownloadToStream(url, outfile, progress, computeHash); + return WinINetDownloadToStream(url, outfile, progress, computeHash, proxyInfo ? *proxyInfo : GetProxyInfo()); } using namespace std::string_view_literals; diff --git a/src/AppInstallerCommonCore/Public/AppInstallerDownloader.h b/src/AppInstallerCommonCore/Public/AppInstallerDownloader.h index 0152346b8c..44000df9c4 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerDownloader.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerDownloader.h @@ -31,31 +31,42 @@ namespace AppInstaller::Utility std::string ContentId; }; + struct ProxyInfo + { + std::string Proxy; + std::string ProxyOverride; + }; + + // Retrieve proxy info from UserSettings and environment variables. + ProxyInfo GetProxyInfo(); + // Downloads a file from the given URL and places it in the given location. // url: The url to be downloaded from. http->https redirection is allowed. // dest: The stream to be downloaded to. // computeHash: Optional. Indicates if SHA256 hash should be calculated when downloading. - // downloadIdentifier: Optional. Currently only used by DO to identify the download. + // downloadInfo: Optional. Currently only used by DO to identify the download. std::optional> DownloadToStream( const std::string& url, std::ostream& dest, DownloadType type, IProgressCallback& progress, bool computeHash = false, - std::optional info = {}); + std::optional downloadInfo = {}); // Downloads a file from the given URL and places it in the given location. // url: The url to be downloaded from. http->https redirection is allowed. // dest: The path to local file to be downloaded to. // computeHash: Optional. Indicates if SHA256 hash should be calculated when downloading. - // downloadIdentifier: Optional. Currently only used by DO to identify the download. + // downloadInfo: Optional. Currently only used by DO to identify the download. + // proxyInfo: Optional. Currently only used by WinINet for proxy settings. std::optional> Download( const std::string& url, const std::filesystem::path& dest, DownloadType type, IProgressCallback& progress, bool computeHash = false, - std::optional info = {}); + std::optional downloadInfo = {}, + std::optional proxyInfo = {}); // Determines if the given url is a remote location. bool IsUrlRemote(std::string_view url); From ba795ac48a398f3366dc8c1e91ad0583e138811c Mon Sep 17 00:00:00 2001 From: eternalphane Date: Sun, 12 Dec 2021 00:16:07 +0800 Subject: [PATCH 4/6] add docs --- doc/Settings.md | 15 ++++++++++++++- schemas/JSON/settings/settings.schema.0.2.json | 11 +++++++++++ .../Shared/Strings/en-us/winget.resw | 4 ++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/doc/Settings.md b/doc/Settings.md index 8e463f7b28..37e9aa36fd 100644 --- a/doc/Settings.md +++ b/doc/Settings.md @@ -116,7 +116,7 @@ The `downloader` setting controls which code is used when downloading packages. `wininet` uses the [WinINet](https://docs.microsoft.com/windows/win32/wininet/about-wininet) APIs, while `do` uses the [Delivery Optimization](https://support.microsoft.com/windows/delivery-optimization-in-windows-10-0656e53c-15f2-90de-a87a-a2172c94cf6d) service. -The `doProgressTimeoutInSeconds` setting updates the number of seconds to wait without progress before fallback. The default number of seconds is 60, minimum is 1 and the maximum is 600. +The `doProgressTimeoutInSeconds` setting updates the number of seconds to wait without progress before fallback. The default number of seconds is 60, minimum is 1 and the maximum is 600. ```json "network": { @@ -125,6 +125,19 @@ The `doProgressTimeoutInSeconds` setting updates the number of seconds to wait w } ``` +### Proxy + +The `proxy` setting specifies the proxy server used for download packages. If not specified, winget will retrieve current proxy settings from the registry. + +The `proxyOverride` setting specifies a list of host names or IP addresses, or both, where no proxy should be used. Local hosts are always bypassed as if the list is extended by `["localhost", "loopback", "127.0.0.1", "[::1]"]`. + +```json + "network": { + "proxy": "http://127.0.0.1:7890", + "proxyOverride": ["192.168.*", "github.com"] + } +``` + ## Experimental Features To allow work to be done and distributed to early adopters for feedback, settings can be used to enable "experimental" features. diff --git a/schemas/JSON/settings/settings.schema.0.2.json b/schemas/JSON/settings/settings.schema.0.2.json index 2a9ab5bbd8..9d6a34a21a 100644 --- a/schemas/JSON/settings/settings.schema.0.2.json +++ b/schemas/JSON/settings/settings.schema.0.2.json @@ -113,6 +113,17 @@ "default": 60, "minimum": 1, "maximum": 600 + }, + "proxy": { + "description": "Proxy server used for download packages", + "type": "string" + }, + "proxyOverride": { + "description": "List of hosts where no proxy should be used", + "type": "array", + "items": { + "type": "string" + } } } }, diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index cbe4da7b2c..e8136d5416 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1251,9 +1251,9 @@ Please specify one of them using the `--source` option to proceed. Select the architecture to install - Use the specified proxy + Use the specified proxy server - Comma-separated list of hosts where proxy should not be used + Semicolon-separated list of hosts where proxy should not be used \ No newline at end of file From a6c2fa33ac6c4e92630973321c42138254d2748e Mon Sep 17 00:00:00 2001 From: eternalphane Date: Sun, 12 Dec 2021 00:32:41 +0800 Subject: [PATCH 5/6] support comma-seperated `NO_PROXY`; fix NVRO --- src/AppInstallerCommonCore/Downloader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AppInstallerCommonCore/Downloader.cpp b/src/AppInstallerCommonCore/Downloader.cpp index 4720478dbd..d5bd756951 100644 --- a/src/AppInstallerCommonCore/Downloader.cpp +++ b/src/AppInstallerCommonCore/Downloader.cpp @@ -167,8 +167,9 @@ namespace AppInstaller::Utility std::wstring noProxy; wil::GetEnvironmentVariableW(L"NO_PROXY", noProxy); info.ProxyOverride = Utility::ConvertToUTF8(noProxy); + std::replace_if(info.ProxyOverride.begin(), info.ProxyOverride.end(), [](char ch) { return ch == ','; }, ';'); } - return std::move(info); + return info; } std::optional> DownloadToStream( From 97838b42a79b6b3cc29486c3afe95a80d7ddc6ff Mon Sep 17 00:00:00 2001 From: Zuo Zongyuan Date: Tue, 14 Dec 2021 19:33:14 +0800 Subject: [PATCH 6/6] fix spelling --- .github/actions/spelling/expect.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 1f26c71dd8..0f8c447a96 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -329,6 +329,7 @@ SRL srs standalone startswith +stl streambuf strtoull subdir