From ad25265f4ed81df26a1792a2ca34b6d0b863d9ca Mon Sep 17 00:00:00 2001 From: Krzysztof Nozderko Date: Thu, 1 Jun 2023 15:15:23 +0200 Subject: [PATCH 1/3] SNOW-830959: Refactor of custom http handler setup --- .../{ => Http}/HttpUtilTest.cs | 22 +++++ .../Http/SFHttpMessageHandlerFactoryTest.cs | 63 +++++++++++++ Snowflake.Data.Tests/TestDataGenarator.cs | 55 ++++++++++++ .../Core/Http/HttpMessageHandlerFactory.cs | 77 ++++++++++++++++ .../Http/HttpMessageHandlerFactoryProvider.cs | 24 +++++ .../Http/HttpMessageHandlerForOtherFactory.cs | 37 ++++++++ ...tpMessageHandlerForWindowsDotnetFactory.cs | 38 ++++++++ Snowflake.Data/Core/{ => Http}/HttpUtil.cs | 88 ++----------------- 8 files changed, 321 insertions(+), 83 deletions(-) rename Snowflake.Data.Tests/{ => Http}/HttpUtilTest.cs (64%) create mode 100644 Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs create mode 100644 Snowflake.Data.Tests/TestDataGenarator.cs create mode 100644 Snowflake.Data/Core/Http/HttpMessageHandlerFactory.cs create mode 100644 Snowflake.Data/Core/Http/HttpMessageHandlerFactoryProvider.cs create mode 100644 Snowflake.Data/Core/Http/HttpMessageHandlerForOtherFactory.cs create mode 100644 Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs rename Snowflake.Data/Core/{ => Http}/HttpUtil.cs (75%) diff --git a/Snowflake.Data.Tests/HttpUtilTest.cs b/Snowflake.Data.Tests/Http/HttpUtilTest.cs similarity index 64% rename from Snowflake.Data.Tests/HttpUtilTest.cs rename to Snowflake.Data.Tests/Http/HttpUtilTest.cs index bd5f5583e..9abb9cde7 100644 --- a/Snowflake.Data.Tests/HttpUtilTest.cs +++ b/Snowflake.Data.Tests/Http/HttpUtilTest.cs @@ -36,5 +36,27 @@ public async Task TestIsRetryableHTTPCode(HttpStatusCode statusCode, bool forceR Assert.AreEqual(expectedIsRetryable, actualIsRetryable); } + + [Test] + public void ShouldCreateHttpClient() + { + // given + var config = new HttpClientConfig( + crlCheckEnabled: TestDataGenarator.NextBool(), + proxyHost: TestDataGenarator.NextAlphaNumeric(), + proxyPort: TestDataGenarator.NextDigitsString(4), + proxyUser: TestDataGenarator.NextAlphaNumeric(), + proxyPassword: TestDataGenarator.NextAlphaNumeric(), + noProxyList: TestDataGenarator.NextAlphaNumeric(), + disableRetry: TestDataGenarator.NextBool(), + forceRetryOn404: TestDataGenarator.NextBool() + ); + + // when + var client = HttpUtil.Instance.GetHttpClient(config); + + // then + Assert.IsNotNull(client); + } } } diff --git a/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs b/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs new file mode 100644 index 000000000..6197b82e6 --- /dev/null +++ b/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. + */ + +using System.Net.Http; +using Snowflake.Data.Core; + +namespace Snowflake.Data.Tests; + +using NUnit.Framework; + +[TestFixture] +public class SFHttpMessageHandlerFactoryTest +{ + + [Test] + public void ShouldCreateHttpMessageHandlerWithoutProxyTest() + { + // given + var config = new HttpClientConfig( + crlCheckEnabled: true, + proxyHost: null, + proxyPort: null, + proxyUser: null, + proxyPassword: null, + noProxyList: null, + disableRetry: false, + forceRetryOn404: false + ); + var handlerFactory = new HttpMessageHandlerFactoryProvider().createHttpMessageHandlerFactory(); + + // when + var handler = (HttpClientHandler) handlerFactory.Create(config); + + // then + Assert.NotNull(handler); + Assert.Null(handlerFactory.ExtractWebProxy(handler)); + } + + [Test] + public void ShouldCreateHttpMessageHandlerWithProxyTest() + { + // given + var config = new HttpClientConfig( + crlCheckEnabled: true, + proxyHost: "proxy.host.com", + proxyPort: "1234", + proxyUser: "user", + proxyPassword: "password", + noProxyList: null, + disableRetry: false, + forceRetryOn404: false + ); + var handlerFactory = new HttpMessageHandlerFactoryProvider().createHttpMessageHandlerFactory(); + + // when + var handler = (HttpClientHandler) handlerFactory.Create(config); + + // then + Assert.NotNull(handler); + Assert.NotNull(handlerFactory.ExtractWebProxy(handler)); + } +} diff --git a/Snowflake.Data.Tests/TestDataGenarator.cs b/Snowflake.Data.Tests/TestDataGenarator.cs new file mode 100644 index 000000000..d5236afff --- /dev/null +++ b/Snowflake.Data.Tests/TestDataGenarator.cs @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. + */ + +using System; +using System.Linq; + +namespace Snowflake.Data.Tests; + +public class TestDataGenarator +{ + private static Random random = new Random(); + private static string lowercaseChars = "abcdefghijklmnopqrstuvwxyz"; + private static string uppercaseChars = lowercaseChars.ToUpper(); + private static string nonZeroDigits = "123456789"; + private static string digitChars = "0" + nonZeroDigits; + private static string letterChars = lowercaseChars + uppercaseChars; + private static string alphanumericChars = letterChars + digitChars; + + + public static bool NextBool() + { + return random.Next(0, 1) == 1; + } + + public static string NextAlphaNumeric() + { + return NextLetter() + + Enumerable.Repeat(alphanumericChars, random.Next(5, 12)) + .Select(NextChar) + .Aggregate((s1, s2) => s1 + s2); + } + + public static string NextDigitsString(int length) + { + return NextNonZeroDigitString() + Enumerable.Repeat(digitChars, length - 1) + .Select(NextChar) + .Aggregate((s1, s2) => s1 + s2); + } + + public static string NextNonZeroDigitString() + { + return NextChar(nonZeroDigits); + } + + private static string NextLetter() + { + return NextChar(letterChars); + } + + private static string NextChar(string chars) + { + return chars[random.Next(chars.Length)].ToString(); + } +} diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerFactory.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerFactory.cs new file mode 100644 index 000000000..665059770 --- /dev/null +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerFactory.cs @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. + */ + +using System; +using System.Net; +using System.Net.Http; + +namespace Snowflake.Data.Core; + +internal abstract class HttpMessageHandlerFactory +{ + + public HttpMessageHandler Create(HttpClientConfig config) + { + var handler = CreateHandlerWithoutProxy(config); + if (ProxyNeedsToBeAdded(config)) + { + var proxy = CreateProxy(config); + return AttachProxyToHandler(handler, proxy); + } + return handler; + } + + protected abstract HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config); + + protected abstract HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, WebProxy proxy); + + public abstract IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler); + + private WebProxy CreateProxy(HttpClientConfig config) + { + WebProxy proxy = new WebProxy(config.ProxyHost, int.Parse(config.ProxyPort)); + AttachCredentials(proxy, config); + AttachBypassList(proxy, config); + return proxy; + } + + private bool ProxyNeedsToBeAdded(HttpClientConfig config) + { + return config.ProxyHost != null; + } + + private WebProxy AttachCredentials(WebProxy proxy, HttpClientConfig config) + { + if (String.IsNullOrEmpty(config.ProxyUser)) + return proxy; + ICredentials credentials = new NetworkCredential(config.ProxyUser, config.ProxyPassword); + proxy.Credentials = credentials; + return proxy; + } + + private WebProxy AttachBypassList(WebProxy proxy, HttpClientConfig config) + { + if (String.IsNullOrEmpty(config.NoProxyList)) + return proxy; + string[] bypassList = config.NoProxyList.Split( + new char[] { '|' }, + StringSplitOptions.RemoveEmptyEntries); + // Convert simplified syntax to standard regular expression syntax + string entry = null; + for (int i = 0; i < bypassList.Length; i++) + { + // Get the original entry + entry = bypassList[i].Trim(); + // . -> [.] because . means any char + entry = entry.Replace(".", "[.]"); + // * -> .* because * is a quantifier and need a char or group to apply to + entry = entry.Replace("*", ".*"); + + // Replace with the valid entry syntax + bypassList[i] = entry; + } + proxy.BypassList = bypassList; + return proxy; + } +} diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerFactoryProvider.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerFactoryProvider.cs new file mode 100644 index 000000000..8cadae6cd --- /dev/null +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerFactoryProvider.cs @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. + */ + +using System.Runtime.InteropServices; + +namespace Snowflake.Data.Core; + +public class HttpMessageHandlerFactoryProvider +{ + internal HttpMessageHandlerFactory createHttpMessageHandlerFactory() + { + if (IsRunningOnWindowsDotnet()) + { + return new HttpMessageHandlerForWindowsDotnetFactory(); + } + return new HttpMessageHandlerForOtherFactory(); + } + + internal bool IsRunningOnWindowsDotnet() + { + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && SFEnvironment.ClientEnv.IsNetFramework; + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerForOtherFactory.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerForOtherFactory.cs new file mode 100644 index 000000000..bbeecff1c --- /dev/null +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerForOtherFactory.cs @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. + */ + +using System.Net; +using System.Net.Http; +using System.Security.Authentication; + +namespace Snowflake.Data.Core; + +internal class HttpMessageHandlerForOtherFactory: HttpMessageHandlerFactory +{ + protected override HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config) + { + return new HttpClientHandler() + { + // Verify no certificates have been revoked + CheckCertificateRevocationList = config.CrlCheckEnabled, + // Enforce tls v1.2 + SslProtocols = SslProtocols.Tls12, + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + UseCookies = false // Disable cookies + }; + } + + protected override HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, WebProxy proxy) + { + HttpClientHandler httpHandlerWithProxy = (HttpClientHandler) httpMessageHandler; + httpHandlerWithProxy.Proxy = proxy; + return httpHandlerWithProxy; + } + + public override IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler) + { + return ((HttpClientHandler)httpMessageHandler).Proxy; + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs new file mode 100644 index 000000000..4e0cb84d4 --- /dev/null +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. + */ + +using System.Net; +using System.Net.Http; +using System.Security.Authentication; + +namespace Snowflake.Data.Core; + +internal class HttpMessageHandlerForWindowsDotnetFactory: HttpMessageHandlerFactory +{ + protected override HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config) + { + return new WinHttpHandler() + { + // Verify no certificates have been revoked + CheckCertificateRevocationList = config.CrlCheckEnabled, + // Enforce tls v1.2 + SslProtocols = SslProtocols.Tls12, + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + CookieUsePolicy = CookieUsePolicy.IgnoreCookies + }; + } + + protected override HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, WebProxy proxy) + { + WinHttpHandler httpHandlerWithProxy = (WinHttpHandler) httpMessageHandler; + httpHandlerWithProxy.WindowsProxyUsePolicy = WindowsProxyUsePolicy.UseCustomProxy; + httpHandlerWithProxy.Proxy = proxy; + return httpHandlerWithProxy; + } + + public override IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler) + { + return ((WinHttpHandler) httpMessageHandler).Proxy; + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/HttpUtil.cs b/Snowflake.Data/Core/Http/HttpUtil.cs similarity index 75% rename from Snowflake.Data/Core/HttpUtil.cs rename to Snowflake.Data/Core/Http/HttpUtil.cs index 034a5acb9..2168713db 100755 --- a/Snowflake.Data/Core/HttpUtil.cs +++ b/Snowflake.Data/Core/Http/HttpUtil.cs @@ -11,8 +11,6 @@ using Snowflake.Data.Log; using System.Collections.Specialized; using System.Web; -using System.Security.Authentication; -using System.Runtime.InteropServices; namespace Snowflake.Data.Core { @@ -64,8 +62,10 @@ public HttpClientConfig( public sealed class HttpUtil { - static internal readonly int MAX_RETRY = 6; + internal static readonly int MAX_RETRY = 6; private static readonly SFLogger logger = SFLoggerFactory.GetLogger(); + private static readonly HttpMessageHandlerFactory handlerFactory = new HttpMessageHandlerFactoryProvider() + .createHttpMessageHandlerFactory(); private HttpUtil() { } @@ -82,8 +82,7 @@ internal HttpClient GetHttpClient(HttpClientConfig config) return RegisterNewHttpClientIfNecessary(config); } } - - + private HttpClient RegisterNewHttpClientIfNecessary(HttpClientConfig config) { string name = config.ConfKey; @@ -106,84 +105,7 @@ private HttpClient RegisterNewHttpClientIfNecessary(HttpClientConfig config) private HttpMessageHandler setupCustomHttpHandler(HttpClientConfig config) { - HttpMessageHandler httpHandler; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && SFEnvironment.ClientEnv.IsNetFramework) - { - httpHandler = new WinHttpHandler() - { - // Verify no certificates have been revoked - CheckCertificateRevocationList = config.CrlCheckEnabled, - // Enforce tls v1.2 - SslProtocols = SslProtocols.Tls12, - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, - CookieUsePolicy = CookieUsePolicy.IgnoreCookies - }; - } - else - { - httpHandler = new HttpClientHandler() - { - // Verify no certificates have been revoked - CheckCertificateRevocationList = config.CrlCheckEnabled, - // Enforce tls v1.2 - SslProtocols = SslProtocols.Tls12, - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, - UseCookies = false // Disable cookies - }; - } - - // Add a proxy if necessary - if (null != config.ProxyHost) - { - // Proxy needed - WebProxy proxy = new WebProxy(config.ProxyHost, int.Parse(config.ProxyPort)); - - // Add credential if provided - if (!String.IsNullOrEmpty(config.ProxyUser)) - { - ICredentials credentials = new NetworkCredential(config.ProxyUser, config.ProxyPassword); - proxy.Credentials = credentials; - } - - // Add bypasslist if provided - if (!String.IsNullOrEmpty(config.NoProxyList)) - { - string[] bypassList = config.NoProxyList.Split( - new char[] { '|' }, - StringSplitOptions.RemoveEmptyEntries); - // Convert simplified syntax to standard regular expression syntax - string entry = null; - for (int i = 0; i < bypassList.Length; i++) - { - // Get the original entry - entry = bypassList[i].Trim(); - // . -> [.] because . means any char - entry = entry.Replace(".", "[.]"); - // * -> .* because * is a quantifier and need a char or group to apply to - entry = entry.Replace("*", ".*"); - - // Replace with the valid entry syntax - bypassList[i] = entry; - - } - proxy.BypassList = bypassList; - } - if (httpHandler is WinHttpHandler && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - WinHttpHandler httpHandlerWithProxy = (WinHttpHandler)httpHandler; - - httpHandlerWithProxy.WindowsProxyUsePolicy = WindowsProxyUsePolicy.UseCustomProxy; - httpHandlerWithProxy.Proxy = proxy; - return httpHandlerWithProxy; - } - else if (httpHandler is HttpClientHandler) - { - HttpClientHandler httpHandlerWithProxy = (HttpClientHandler)httpHandler; - httpHandlerWithProxy.Proxy = proxy; - return httpHandlerWithProxy; - } - } - return httpHandler; + return handlerFactory.Create(config); } /// From 211fdfc5b6766abf45359335d2a7b6f99b8c1603 Mon Sep 17 00:00:00 2001 From: Krzysztof Nozderko Date: Fri, 2 Jun 2023 09:15:59 +0200 Subject: [PATCH 2/3] Use old namespace syntax --- .../Http/SFHttpMessageHandlerFactoryTest.cs | 99 ++++++++-------- Snowflake.Data.Tests/TestDataGenarator.cs | 91 ++++++++------- .../Core/Http/HttpMessageHandlerFactory.cs | 109 +++++++++--------- .../Http/HttpMessageHandlerFactoryProvider.cs | 27 +++-- .../Http/HttpMessageHandlerForOtherFactory.cs | 49 ++++---- ...tpMessageHandlerForWindowsDotnetFactory.cs | 51 ++++---- 6 files changed, 223 insertions(+), 203 deletions(-) diff --git a/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs b/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs index 6197b82e6..c4a0a54de 100644 --- a/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs +++ b/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs @@ -5,59 +5,60 @@ using System.Net.Http; using Snowflake.Data.Core; -namespace Snowflake.Data.Tests; - using NUnit.Framework; -[TestFixture] -public class SFHttpMessageHandlerFactoryTest +namespace Snowflake.Data.Tests { - - [Test] - public void ShouldCreateHttpMessageHandlerWithoutProxyTest() + [TestFixture] + public class SFHttpMessageHandlerFactoryTest { - // given - var config = new HttpClientConfig( - crlCheckEnabled: true, - proxyHost: null, - proxyPort: null, - proxyUser: null, - proxyPassword: null, - noProxyList: null, - disableRetry: false, - forceRetryOn404: false - ); - var handlerFactory = new HttpMessageHandlerFactoryProvider().createHttpMessageHandlerFactory(); - - // when - var handler = (HttpClientHandler) handlerFactory.Create(config); - - // then - Assert.NotNull(handler); - Assert.Null(handlerFactory.ExtractWebProxy(handler)); - } - [Test] - public void ShouldCreateHttpMessageHandlerWithProxyTest() - { - // given - var config = new HttpClientConfig( - crlCheckEnabled: true, - proxyHost: "proxy.host.com", - proxyPort: "1234", - proxyUser: "user", - proxyPassword: "password", - noProxyList: null, - disableRetry: false, - forceRetryOn404: false - ); - var handlerFactory = new HttpMessageHandlerFactoryProvider().createHttpMessageHandlerFactory(); - - // when - var handler = (HttpClientHandler) handlerFactory.Create(config); - - // then - Assert.NotNull(handler); - Assert.NotNull(handlerFactory.ExtractWebProxy(handler)); + [Test] + public void ShouldCreateHttpMessageHandlerWithoutProxyTest() + { + // given + var config = new HttpClientConfig( + crlCheckEnabled: true, + proxyHost: null, + proxyPort: null, + proxyUser: null, + proxyPassword: null, + noProxyList: null, + disableRetry: false, + forceRetryOn404: false + ); + var handlerFactory = new HttpMessageHandlerFactoryProvider().createHttpMessageHandlerFactory(); + + // when + var handler = (HttpClientHandler)handlerFactory.Create(config); + + // then + Assert.NotNull(handler); + Assert.Null(handlerFactory.ExtractWebProxy(handler)); + } + + [Test] + public void ShouldCreateHttpMessageHandlerWithProxyTest() + { + // given + var config = new HttpClientConfig( + crlCheckEnabled: true, + proxyHost: "proxy.host.com", + proxyPort: "1234", + proxyUser: "user", + proxyPassword: "password", + noProxyList: null, + disableRetry: false, + forceRetryOn404: false + ); + var handlerFactory = new HttpMessageHandlerFactoryProvider().createHttpMessageHandlerFactory(); + + // when + var handler = (HttpClientHandler)handlerFactory.Create(config); + + // then + Assert.NotNull(handler); + Assert.NotNull(handlerFactory.ExtractWebProxy(handler)); + } } } diff --git a/Snowflake.Data.Tests/TestDataGenarator.cs b/Snowflake.Data.Tests/TestDataGenarator.cs index d5236afff..96990c9cd 100644 --- a/Snowflake.Data.Tests/TestDataGenarator.cs +++ b/Snowflake.Data.Tests/TestDataGenarator.cs @@ -5,51 +5,56 @@ using System; using System.Linq; -namespace Snowflake.Data.Tests; - -public class TestDataGenarator +namespace Snowflake.Data.Tests { - private static Random random = new Random(); - private static string lowercaseChars = "abcdefghijklmnopqrstuvwxyz"; - private static string uppercaseChars = lowercaseChars.ToUpper(); - private static string nonZeroDigits = "123456789"; - private static string digitChars = "0" + nonZeroDigits; - private static string letterChars = lowercaseChars + uppercaseChars; - private static string alphanumericChars = letterChars + digitChars; - - - public static bool NextBool() - { - return random.Next(0, 1) == 1; - } - - public static string NextAlphaNumeric() - { - return NextLetter() + - Enumerable.Repeat(alphanumericChars, random.Next(5, 12)) - .Select(NextChar) - .Aggregate((s1, s2) => s1 + s2); - } - - public static string NextDigitsString(int length) - { - return NextNonZeroDigitString() + Enumerable.Repeat(digitChars, length - 1) - .Select(NextChar) - .Aggregate((s1, s2) => s1 + s2); - } - - public static string NextNonZeroDigitString() - { - return NextChar(nonZeroDigits); - } - - private static string NextLetter() - { - return NextChar(letterChars); - } - private static string NextChar(string chars) + public class TestDataGenarator { - return chars[random.Next(chars.Length)].ToString(); + private static Random random = new Random(); + private static string lowercaseChars = "abcdefghijklmnopqrstuvwxyz"; + private static string uppercaseChars = lowercaseChars.ToUpper(); + private static string nonZeroDigits = "123456789"; + private static string digitChars = "0" + nonZeroDigits; + private static string letterChars = lowercaseChars + uppercaseChars; + private static string alphanumericChars = letterChars + digitChars; + + public static bool NextBool() + { + return random.Next(0, 1) == 1; + } + + public static string NextAlphaNumeric() + { + return NextLetter() + + Enumerable.Repeat(alphanumericChars, random.Next(5, 12)) + .Select(NextChar) + .Aggregate((s1, s2) => s1 + s2); + } + + public static string NextDigitsString(int length) + { + if (length == 1) + { + return NextNonZeroDigitString(); + } + return NextNonZeroDigitString() + Enumerable.Repeat(digitChars, length - 1) + .Select(NextChar) + .Aggregate((s1, s2) => s1 + s2); + } + + public static string NextNonZeroDigitString() + { + return NextChar(nonZeroDigits); + } + + private static string NextLetter() + { + return NextChar(letterChars); + } + + private static string NextChar(string chars) + { + return chars[random.Next(chars.Length)].ToString(); + } } } diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerFactory.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerFactory.cs index 665059770..79ee0fa63 100644 --- a/Snowflake.Data/Core/Http/HttpMessageHandlerFactory.cs +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerFactory.cs @@ -6,72 +6,77 @@ using System.Net; using System.Net.Http; -namespace Snowflake.Data.Core; - -internal abstract class HttpMessageHandlerFactory +namespace Snowflake.Data.Core { - public HttpMessageHandler Create(HttpClientConfig config) + internal abstract class HttpMessageHandlerFactory { - var handler = CreateHandlerWithoutProxy(config); - if (ProxyNeedsToBeAdded(config)) + + public HttpMessageHandler Create(HttpClientConfig config) { - var proxy = CreateProxy(config); - return AttachProxyToHandler(handler, proxy); + var handler = CreateHandlerWithoutProxy(config); + if (ProxyNeedsToBeAdded(config)) + { + var proxy = CreateProxy(config); + return AttachProxyToHandler(handler, proxy); + } + + return handler; } - return handler; - } - protected abstract HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config); + protected abstract HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config); - protected abstract HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, WebProxy proxy); + protected abstract HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, + WebProxy proxy); - public abstract IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler); - - private WebProxy CreateProxy(HttpClientConfig config) - { - WebProxy proxy = new WebProxy(config.ProxyHost, int.Parse(config.ProxyPort)); - AttachCredentials(proxy, config); - AttachBypassList(proxy, config); - return proxy; - } + public abstract IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler); - private bool ProxyNeedsToBeAdded(HttpClientConfig config) - { - return config.ProxyHost != null; - } - - private WebProxy AttachCredentials(WebProxy proxy, HttpClientConfig config) - { - if (String.IsNullOrEmpty(config.ProxyUser)) + private WebProxy CreateProxy(HttpClientConfig config) + { + WebProxy proxy = new WebProxy(config.ProxyHost, int.Parse(config.ProxyPort)); + AttachCredentials(proxy, config); + AttachBypassList(proxy, config); return proxy; - ICredentials credentials = new NetworkCredential(config.ProxyUser, config.ProxyPassword); - proxy.Credentials = credentials; - return proxy; - } + } - private WebProxy AttachBypassList(WebProxy proxy, HttpClientConfig config) - { - if (String.IsNullOrEmpty(config.NoProxyList)) + private bool ProxyNeedsToBeAdded(HttpClientConfig config) + { + return config.ProxyHost != null; + } + + private WebProxy AttachCredentials(WebProxy proxy, HttpClientConfig config) + { + if (String.IsNullOrEmpty(config.ProxyUser)) + return proxy; + ICredentials credentials = new NetworkCredential(config.ProxyUser, config.ProxyPassword); + proxy.Credentials = credentials; return proxy; - string[] bypassList = config.NoProxyList.Split( - new char[] { '|' }, - StringSplitOptions.RemoveEmptyEntries); - // Convert simplified syntax to standard regular expression syntax - string entry = null; - for (int i = 0; i < bypassList.Length; i++) + } + + private WebProxy AttachBypassList(WebProxy proxy, HttpClientConfig config) { - // Get the original entry - entry = bypassList[i].Trim(); - // . -> [.] because . means any char - entry = entry.Replace(".", "[.]"); - // * -> .* because * is a quantifier and need a char or group to apply to - entry = entry.Replace("*", ".*"); + if (String.IsNullOrEmpty(config.NoProxyList)) + return proxy; + string[] bypassList = config.NoProxyList.Split( + new char[] { '|' }, + StringSplitOptions.RemoveEmptyEntries); + // Convert simplified syntax to standard regular expression syntax + string entry = null; + for (int i = 0; i < bypassList.Length; i++) + { + // Get the original entry + entry = bypassList[i].Trim(); + // . -> [.] because . means any char + entry = entry.Replace(".", "[.]"); + // * -> .* because * is a quantifier and need a char or group to apply to + entry = entry.Replace("*", ".*"); - // Replace with the valid entry syntax - bypassList[i] = entry; + // Replace with the valid entry syntax + bypassList[i] = entry; + } + + proxy.BypassList = bypassList; + return proxy; } - proxy.BypassList = bypassList; - return proxy; } } diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerFactoryProvider.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerFactoryProvider.cs index 8cadae6cd..741cff693 100644 --- a/Snowflake.Data/Core/Http/HttpMessageHandlerFactoryProvider.cs +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerFactoryProvider.cs @@ -4,21 +4,24 @@ using System.Runtime.InteropServices; -namespace Snowflake.Data.Core; - -public class HttpMessageHandlerFactoryProvider +namespace Snowflake.Data.Core { - internal HttpMessageHandlerFactory createHttpMessageHandlerFactory() + + public class HttpMessageHandlerFactoryProvider { - if (IsRunningOnWindowsDotnet()) + internal HttpMessageHandlerFactory createHttpMessageHandlerFactory() { - return new HttpMessageHandlerForWindowsDotnetFactory(); + if (IsRunningOnWindowsDotnet()) + { + return new HttpMessageHandlerForWindowsDotnetFactory(); + } + + return new HttpMessageHandlerForOtherFactory(); } - return new HttpMessageHandlerForOtherFactory(); - } - internal bool IsRunningOnWindowsDotnet() - { - return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && SFEnvironment.ClientEnv.IsNetFramework; + internal bool IsRunningOnWindowsDotnet() + { + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && SFEnvironment.ClientEnv.IsNetFramework; + } } -} \ No newline at end of file +} diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerForOtherFactory.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerForOtherFactory.cs index bbeecff1c..712e60505 100644 --- a/Snowflake.Data/Core/Http/HttpMessageHandlerForOtherFactory.cs +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerForOtherFactory.cs @@ -6,32 +6,35 @@ using System.Net.Http; using System.Security.Authentication; -namespace Snowflake.Data.Core; - -internal class HttpMessageHandlerForOtherFactory: HttpMessageHandlerFactory +namespace Snowflake.Data.Core { - protected override HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config) + + internal class HttpMessageHandlerForOtherFactory : HttpMessageHandlerFactory { - return new HttpClientHandler() + protected override HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config) { - // Verify no certificates have been revoked - CheckCertificateRevocationList = config.CrlCheckEnabled, - // Enforce tls v1.2 - SslProtocols = SslProtocols.Tls12, - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, - UseCookies = false // Disable cookies - }; - } + return new HttpClientHandler() + { + // Verify no certificates have been revoked + CheckCertificateRevocationList = config.CrlCheckEnabled, + // Enforce tls v1.2 + SslProtocols = SslProtocols.Tls12, + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + UseCookies = false // Disable cookies + }; + } - protected override HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, WebProxy proxy) - { - HttpClientHandler httpHandlerWithProxy = (HttpClientHandler) httpMessageHandler; - httpHandlerWithProxy.Proxy = proxy; - return httpHandlerWithProxy; - } + protected override HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, + WebProxy proxy) + { + HttpClientHandler httpHandlerWithProxy = (HttpClientHandler)httpMessageHandler; + httpHandlerWithProxy.Proxy = proxy; + return httpHandlerWithProxy; + } - public override IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler) - { - return ((HttpClientHandler)httpMessageHandler).Proxy; + public override IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler) + { + return ((HttpClientHandler)httpMessageHandler).Proxy; + } } -} \ No newline at end of file +} diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs index 4e0cb84d4..dc6624083 100644 --- a/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs @@ -6,33 +6,36 @@ using System.Net.Http; using System.Security.Authentication; -namespace Snowflake.Data.Core; - -internal class HttpMessageHandlerForWindowsDotnetFactory: HttpMessageHandlerFactory +namespace Snowflake.Data.Core { - protected override HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config) + + internal class HttpMessageHandlerForWindowsDotnetFactory : HttpMessageHandlerFactory { - return new WinHttpHandler() + protected override HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig config) { - // Verify no certificates have been revoked - CheckCertificateRevocationList = config.CrlCheckEnabled, - // Enforce tls v1.2 - SslProtocols = SslProtocols.Tls12, - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, - CookieUsePolicy = CookieUsePolicy.IgnoreCookies - }; - } + return new WinHttpHandler() + { + // Verify no certificates have been revoked + CheckCertificateRevocationList = config.CrlCheckEnabled, + // Enforce tls v1.2 + SslProtocols = SslProtocols.Tls12, + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + CookieUsePolicy = CookieUsePolicy.IgnoreCookies + }; + } - protected override HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, WebProxy proxy) - { - WinHttpHandler httpHandlerWithProxy = (WinHttpHandler) httpMessageHandler; - httpHandlerWithProxy.WindowsProxyUsePolicy = WindowsProxyUsePolicy.UseCustomProxy; - httpHandlerWithProxy.Proxy = proxy; - return httpHandlerWithProxy; - } + protected override HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, + WebProxy proxy) + { + WinHttpHandler httpHandlerWithProxy = (WinHttpHandler)httpMessageHandler; + httpHandlerWithProxy.WindowsProxyUsePolicy = WindowsProxyUsePolicy.UseCustomProxy; + httpHandlerWithProxy.Proxy = proxy; + return httpHandlerWithProxy; + } - public override IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler) - { - return ((WinHttpHandler) httpMessageHandler).Proxy; + public override IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler) + { + return ((WinHttpHandler)httpMessageHandler).Proxy; + } } -} \ No newline at end of file +} From 3aec934cbe08236bbe005625c3a575100abfe528 Mon Sep 17 00:00:00 2001 From: Krzysztof Nozderko Date: Fri, 2 Jun 2023 14:23:13 +0200 Subject: [PATCH 3/3] fix test --- Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs | 5 ++--- .../Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs b/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs index c4a0a54de..fa352453c 100644 --- a/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs +++ b/Snowflake.Data.Tests/Http/SFHttpMessageHandlerFactoryTest.cs @@ -2,7 +2,6 @@ * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. */ -using System.Net.Http; using Snowflake.Data.Core; using NUnit.Framework; @@ -30,7 +29,7 @@ public void ShouldCreateHttpMessageHandlerWithoutProxyTest() var handlerFactory = new HttpMessageHandlerFactoryProvider().createHttpMessageHandlerFactory(); // when - var handler = (HttpClientHandler)handlerFactory.Create(config); + var handler = handlerFactory.Create(config); // then Assert.NotNull(handler); @@ -54,7 +53,7 @@ public void ShouldCreateHttpMessageHandlerWithProxyTest() var handlerFactory = new HttpMessageHandlerFactoryProvider().createHttpMessageHandlerFactory(); // when - var handler = (HttpClientHandler)handlerFactory.Create(config); + var handler = handlerFactory.Create(config); // then Assert.NotNull(handler); diff --git a/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs b/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs index dc6624083..a3db38c4d 100644 --- a/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs +++ b/Snowflake.Data/Core/Http/HttpMessageHandlerForWindowsDotnetFactory.cs @@ -27,7 +27,7 @@ protected override HttpMessageHandler CreateHandlerWithoutProxy(HttpClientConfig protected override HttpMessageHandler AttachProxyToHandler(HttpMessageHandler httpMessageHandler, WebProxy proxy) { - WinHttpHandler httpHandlerWithProxy = (WinHttpHandler)httpMessageHandler; + WinHttpHandler httpHandlerWithProxy = (WinHttpHandler) httpMessageHandler; httpHandlerWithProxy.WindowsProxyUsePolicy = WindowsProxyUsePolicy.UseCustomProxy; httpHandlerWithProxy.Proxy = proxy; return httpHandlerWithProxy; @@ -35,7 +35,7 @@ protected override HttpMessageHandler AttachProxyToHandler(HttpMessageHandler ht public override IWebProxy ExtractWebProxy(HttpMessageHandler httpMessageHandler) { - return ((WinHttpHandler)httpMessageHandler).Proxy; + return ((WinHttpHandler) httpMessageHandler).Proxy; } } }