From 03fe39efeb14183965bcf558c703fb9c9703a090 Mon Sep 17 00:00:00 2001 From: Koraniar Date: Thu, 30 Apr 2020 09:30:31 -0500 Subject: [PATCH 1/5] Use a custom proxy server --- src/Core/WinSWCore/Download.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Core/WinSWCore/Download.cs b/src/Core/WinSWCore/Download.cs index 0791d4e..f9caff3 100755 --- a/src/Core/WinSWCore/Download.cs +++ b/src/Core/WinSWCore/Download.cs @@ -36,6 +36,7 @@ namespace winsw public readonly string? Password; public readonly bool UnsecureAuth; public readonly bool FailOnError; + public readonly string? ProxyServer; public string ShortId => $"(download from {From})"; @@ -75,11 +76,13 @@ namespace winsw AuthType auth = AuthType.none, string? username = null, string? password = null, - bool unsecureAuth = false) + bool unsecureAuth = false, + string? proxyServer = null) { From = from; To = to; FailOnError = failOnError; + ProxyServer = proxyServer; Auth = auth; Username = username; Password = password; @@ -98,6 +101,7 @@ namespace winsw // All arguments below are optional FailOnError = XmlHelper.SingleAttribute(n, "failOnError", false); + ProxyServer = XmlHelper.SingleAttribute(n, "proxyServer", null); Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.none); Username = XmlHelper.SingleAttribute(n, "user", null); @@ -147,6 +151,10 @@ namespace winsw #endif { WebRequest request = WebRequest.Create(From); + if (!string.IsNullOrEmpty(ProxyServer)) + { + request.Proxy = new WebProxy(ProxyServer); + } switch (Auth) { From 0a81ca6ed2571c41f0203cd68e4b2f0dd868092a Mon Sep 17 00:00:00 2001 From: Esteban Garcia Date: Thu, 30 Apr 2020 11:52:08 -0500 Subject: [PATCH 2/5] Add proxyServer documentation --- doc/xmlConfigFile.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/xmlConfigFile.md b/doc/xmlConfigFile.md index 0caf0e0..5edb701 100644 --- a/doc/xmlConfigFile.md +++ b/doc/xmlConfigFile.md @@ -186,6 +186,8 @@ For target servers using the HTTPS transfer protocol it is necessary, that the C By default, the `download` command does not fail the service startup if the operation fails (e.g. `from` is not available). In order to force the download failure in such case, it is possible to specify the `failOnError` boolean attribute. +To specify a custom proxy you can put your proxy URL in the parameter `proxyServer`. + Examples: ```xml @@ -193,12 +195,14 @@ Examples: + + - ``` From 9c6518e246ce0ad7a836bf45d5f228d6cf4dee03 Mon Sep 17 00:00:00 2001 From: Koraniar Date: Fri, 1 May 2020 20:11:10 -0500 Subject: [PATCH 3/5] Use credentials for proxy server --- src/Core/WinSWCore/Download.cs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Core/WinSWCore/Download.cs b/src/Core/WinSWCore/Download.cs index f9caff3..897ea5c 100755 --- a/src/Core/WinSWCore/Download.cs +++ b/src/Core/WinSWCore/Download.cs @@ -36,7 +36,7 @@ namespace winsw public readonly string? Password; public readonly bool UnsecureAuth; public readonly bool FailOnError; - public readonly string? ProxyServer; + public readonly string? Proxy; public string ShortId => $"(download from {From})"; @@ -77,12 +77,12 @@ namespace winsw string? username = null, string? password = null, bool unsecureAuth = false, - string? proxyServer = null) + string? proxy = null) { From = from; To = to; FailOnError = failOnError; - ProxyServer = proxyServer; + Proxy = proxy; Auth = auth; Username = username; Password = password; @@ -101,7 +101,7 @@ namespace winsw // All arguments below are optional FailOnError = XmlHelper.SingleAttribute(n, "failOnError", false); - ProxyServer = XmlHelper.SingleAttribute(n, "proxyServer", null); + Proxy = XmlHelper.SingleAttribute(n, "proxy", null); Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.none); Username = XmlHelper.SingleAttribute(n, "user", null); @@ -151,9 +151,27 @@ namespace winsw #endif { WebRequest request = WebRequest.Create(From); - if (!string.IsNullOrEmpty(ProxyServer)) + if (!string.IsNullOrEmpty(Proxy)) { - request.Proxy = new WebProxy(ProxyServer); + if (Proxy.Contains("@")) + { + // Extract proxy credentials + int credsFrom = Proxy.IndexOf("://") + 3; + int credsTo = Proxy.IndexOf("@"); + string completeCredsStr = Proxy.Substring(credsFrom, credsTo - credsFrom); + int credsSeparator = completeCredsStr.IndexOf(":"); + + string proxyAddress = Proxy.Replace(completeCredsStr + "@", ""); + string username = completeCredsStr.Substring(0, credsSeparator); + string password = completeCredsStr.Substring(credsSeparator + 1); + ICredentials credentials = new NetworkCredential(username, password); + + request.Proxy = new WebProxy(proxyAddress, false, null, credentials); + } + else + { + request.Proxy = new WebProxy(Proxy); + } } switch (Auth) From c45a316008fa6824eda871aabd471990f234b757 Mon Sep 17 00:00:00 2001 From: Esteban Garcia Date: Fri, 1 May 2020 20:12:20 -0500 Subject: [PATCH 4/5] Update proxy documentation --- doc/xmlConfigFile.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/xmlConfigFile.md b/doc/xmlConfigFile.md index 5edb701..aebd65d 100644 --- a/doc/xmlConfigFile.md +++ b/doc/xmlConfigFile.md @@ -186,7 +186,9 @@ For target servers using the HTTPS transfer protocol it is necessary, that the C By default, the `download` command does not fail the service startup if the operation fails (e.g. `from` is not available). In order to force the download failure in such case, it is possible to specify the `failOnError` boolean attribute. -To specify a custom proxy you can put your proxy URL in the parameter `proxyServer`. +To specify a custom proxy use the parameter `proxy` with the following formats: +- With credentials: `http://USERNAME:PASSWORD@HOST:PORT/`. +- Without credentials: `http://HOST:PORT/`. Examples: @@ -195,14 +197,15 @@ Examples: - + - ``` From d03e80cea65fb81bb05ab7d79c57f491e66995b8 Mon Sep 17 00:00:00 2001 From: Koraniar Date: Mon, 4 May 2020 12:04:19 -0500 Subject: [PATCH 5/5] Unit tests for custom proxy server --- src/Core/WinSWCore/Download.cs | 47 ++++++++++++++++++++--------- src/Test/winswTests/DownloadTest.cs | 29 ++++++++++++++++++ 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/Core/WinSWCore/Download.cs b/src/Core/WinSWCore/Download.cs index 897ea5c..f0d2c22 100755 --- a/src/Core/WinSWCore/Download.cs +++ b/src/Core/WinSWCore/Download.cs @@ -153,24 +153,14 @@ namespace winsw WebRequest request = WebRequest.Create(From); if (!string.IsNullOrEmpty(Proxy)) { - if (Proxy.Contains("@")) + CustomProxyInformation proxyInformation = new CustomProxyInformation(Proxy); + if (proxyInformation.Credentials != null) { - // Extract proxy credentials - int credsFrom = Proxy.IndexOf("://") + 3; - int credsTo = Proxy.IndexOf("@"); - string completeCredsStr = Proxy.Substring(credsFrom, credsTo - credsFrom); - int credsSeparator = completeCredsStr.IndexOf(":"); - - string proxyAddress = Proxy.Replace(completeCredsStr + "@", ""); - string username = completeCredsStr.Substring(0, credsSeparator); - string password = completeCredsStr.Substring(credsSeparator + 1); - ICredentials credentials = new NetworkCredential(username, password); - - request.Proxy = new WebProxy(proxyAddress, false, null, credentials); + request.Proxy = new WebProxy(proxyInformation.ServerAddress, false, null, proxyInformation.Credentials); } else { - request.Proxy = new WebProxy(Proxy); + request.Proxy = new WebProxy(proxyInformation.ServerAddress); } } @@ -246,8 +236,8 @@ namespace winsw } } } -#if NET20 +#if NET20 private static void CopyStream(Stream source, Stream destination) { byte[] buffer = new byte[8192]; @@ -259,4 +249,31 @@ namespace winsw } #endif } + + public class CustomProxyInformation + { + public string ServerAddress { get; set; } + public NetworkCredential? Credentials { get; set; } + + public CustomProxyInformation(string proxy) + { + if (proxy.Contains("@")) + { + // Extract proxy credentials + int credsFrom = proxy.IndexOf("://") + 3; + int credsTo = proxy.LastIndexOf("@"); + string completeCredsStr = proxy.Substring(credsFrom, credsTo - credsFrom); + int credsSeparator = completeCredsStr.IndexOf(":"); + + string username = completeCredsStr.Substring(0, credsSeparator); + string password = completeCredsStr.Substring(credsSeparator + 1); + Credentials = new NetworkCredential(username, password); + ServerAddress = proxy.Replace(completeCredsStr + "@", ""); + } + else + { + ServerAddress = proxy; + } + } + } } diff --git a/src/Test/winswTests/DownloadTest.cs b/src/Test/winswTests/DownloadTest.cs index 9477c1f..3dceba0 100644 --- a/src/Test/winswTests/DownloadTest.cs +++ b/src/Test/winswTests/DownloadTest.cs @@ -202,6 +202,35 @@ namespace winswTests Assert.That(() => GetSingleEntry(sd), Throws.TypeOf().With.Message.StartsWith("Cannot parse Enum value from string 'digest'")); } + [TestCase("http://", "127.0.0.1:80", "egarcia", "Passw0rd")] + [TestCase("https://", "myurl.com.co:2298", "MyUsername", "P@ssw:rd")] + [TestCase("http://", "192.168.0.8:3030")] + public void Proxy_Credentials(string protocol, string address, string username = null, string password = null) + { + CustomProxyInformation cpi; + if (string.IsNullOrEmpty(username)) + { + cpi = new CustomProxyInformation(protocol + address + "/"); + } + else + { + cpi = new CustomProxyInformation(protocol + username + ":" + password + "@" + address + "/"); + } + + Assert.That(cpi.ServerAddress, Is.EqualTo(protocol + address + "/")); + + if (string.IsNullOrEmpty(username)) + { + Assert.IsNull(cpi.Credentials); + } + else + { + Assert.IsNotNull(cpi.Credentials); + Assert.That(cpi.Credentials.UserName, Is.EqualTo(username)); + Assert.That(cpi.Credentials.Password, Is.EqualTo(password)); + } + } + private Download GetSingleEntry(ServiceDescriptor sd) { var downloads = sd.Downloads.ToArray();