Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ The following table lists all valid connection properties:
| TOKEN | Depends | The OAuth token to use for OAuth authentication. Must be used in combination with AUTHENTICATOR=oauth. |
| INSECUREMODE | No | Set to true to disable the certificate revocation list check. Default is false. |
| USEPROXY | No | Set to true if you need to use a proxy server. The default value is false. <br/> <br/> This parameter was introduced in v2.0.4. |
| PROXYHOST | Depends | The hostname of the proxy server. <br/> <br/> If USEPROXY is set to `true`, you must set this parameter. <br/> <br/> This parameter was introduced in v2.0.4. |
| PROXYPORT | Depends | The port number of the proxy server. <br/> <br/> If USEPROXY is set to `true`, you must set this parameter. <br/> <br/> This parameter was introduced in v2.0.4. |
| PROXYHOST | No | The hostname of the proxy server. <br/> <br/> If USEPROXY is set to `true`, you can set this parameter to define the proxy explicitly. If not set, the default proxy will be used (HTTPS_PROXY, WinINet...). <br/> <br/> This parameter was introduced in v2.0.4. |
| PROXYPORT | Depends | The port number of the proxy server. <br/> <br/> If USEPROXY is set to `true` and PROXYHOST is specfied, you must set this parameter. <br/> <br/> This parameter was introduced in v2.0.4. |
| PROXYUSER | No | The username for authenticating to the proxy server. <br/> <br/> This parameter was introduced in v2.0.4. |
| PROXYPASSWORD | Depends | The password for authenticating to the proxy server. <br/> <br/> If USEPROXY is `true` and PROXYUSER is set, you must set this parameter. <br/> <br/> This parameter was introduced in v2.0.4. |
| NONPROXYHOSTS | No | The list of hosts that the driver should connect to directly, bypassing the proxy server. Separate the hostnames with a pipe symbol (\|). You can also use an asterisk (`*`) as a wildcard. <br/> The host target value should fully match with any item from the proxy host list to bypass the proxy server. <br/> <br/> This parameter was introduced in v2.0.4. |
Expand Down
4 changes: 2 additions & 2 deletions Snowflake.Data.Tests/SFBaseTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2012-2021 Snowflake Computing Inc. All rights reserved.
*/

Expand Down Expand Up @@ -444,4 +444,4 @@ public void AfterTest(ITest test)

public ActionTargets Targets => ActionTargets.Test | ActionTargets.Suite;
}
}
}
45 changes: 36 additions & 9 deletions Snowflake.Data.Tests/UnitTests/HttpUtilTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2022 Snowflake Computing Inc. All rights reserved.
*/

Expand Down Expand Up @@ -102,48 +102,75 @@ public void TestGetJitter(int seconds)
}

[Test]
public void ShouldCreateHttpClientHandlerWithProxy()
public void ShouldCreateHttpClientHandlerWithExplicitProxy()
{
// given
var config = new HttpClientConfig(
true,
true,
"snowflake.com",
"123",
"testUser",
"proxyPassword",
"localhost",
"localhost",
false,
false,
7
);

// when
var handler = (HttpClientHandler) HttpUtil.Instance.SetupCustomHttpHandler(config);

// then
Assert.IsTrue(handler.UseProxy);
Assert.IsNotNull(handler.Proxy);
}

[Test]
public void ShouldCreateHttpClientHandlerWithoutProxy()
public void ShouldCreateHttpClientHandlerWithImplicitProxy()
{
// given
var config = new HttpClientConfig(
true,
true,
null,
null,
null,
null,
null,
null,
false,
false,
7
);

// when
var handler = (HttpClientHandler) HttpUtil.Instance.SetupCustomHttpHandler(config);

// then
Assert.IsTrue(handler.UseProxy);
Assert.IsNull(handler.Proxy);
}

[Test]
public void ShouldCreateHttpClientHandlerWithoutProxy()
{
// given
var config = new HttpClientConfig(
false,
false,
null,
null,
null,
null,
null,
false,
false,
0
);

// when
var handler = (HttpClientHandler) HttpUtil.Instance.SetupCustomHttpHandler(config);

// then
Assert.IsFalse(handler.UseProxy);
Assert.IsNull(handler.Proxy);
Expand Down
95 changes: 52 additions & 43 deletions Snowflake.Data/Core/HttpUtil.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2012-2021 Snowflake Computing Inc. All rights reserved.
*/

Expand All @@ -21,6 +21,7 @@ public class HttpClientConfig
{
public HttpClientConfig(
bool crlCheckEnabled,
bool useProxy,
string proxyHost,
string proxyPort,
string proxyUser,
Expand All @@ -32,6 +33,7 @@ public HttpClientConfig(
bool includeRetryReason = true)
{
CrlCheckEnabled = crlCheckEnabled;
UseProxy = useProxy;
ProxyHost = proxyHost;
ProxyPort = proxyPort;
ProxyUser = proxyUser;
Expand All @@ -45,6 +47,7 @@ public HttpClientConfig(
ConfKey = string.Join(";",
new string[] {
crlCheckEnabled.ToString(),
useProxy.ToString(),
proxyHost,
proxyPort,
proxyUser,
Expand All @@ -57,6 +60,7 @@ public HttpClientConfig(
}

public readonly bool CrlCheckEnabled;
public readonly bool UseProxy;
public readonly string ProxyHost;
public readonly string ProxyPort;
public readonly string ProxyUser;
Expand Down Expand Up @@ -87,7 +91,7 @@ public sealed class HttpUtil

private HttpUtil()
{
// This value is used by AWS SDK and can cause deadlock,
// This value is used by AWS SDK and can cause deadlock,
// so we need to increase the default value of 2
// See: https://github.com/aws/aws-sdk-net/issues/152
ServicePointManager.DefaultConnectionLimit = 50;
Expand Down Expand Up @@ -130,7 +134,7 @@ private HttpClient RegisterNewHttpClientIfNecessary(HttpClientConfig config)

internal HttpMessageHandler SetupCustomHttpHandler(HttpClientConfig config)
{
HttpMessageHandler httpHandler;
HttpClientHandler httpHandler;
try
{
httpHandler = new HttpClientHandler()
Expand All @@ -140,8 +144,7 @@ internal HttpMessageHandler SetupCustomHttpHandler(HttpClientConfig config)
// Enforce tls v1.2
SslProtocols = SslProtocols.Tls12,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
UseCookies = false, // Disable cookies
UseProxy = false
UseCookies = false // Disable cookies
};
}
// special logic for .NET framework 4.7.1 that
Expand All @@ -151,56 +154,62 @@ internal HttpMessageHandler SetupCustomHttpHandler(HttpClientConfig config)
httpHandler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
UseCookies = false, // Disable cookies
UseProxy = false
UseCookies = false // Disable cookies
};
}

// Add a proxy if necessary
if (null != config.ProxyHost)
if (!config.UseProxy)
{
httpHandler.UseProxy = false;
}
else
{
// Proxy needed
WebProxy proxy = new WebProxy(config.ProxyHost, int.Parse(config.ProxyPort));
httpHandler.UseProxy = true;

// Add credential if provided
if (!String.IsNullOrEmpty(config.ProxyUser))
if (!String.IsNullOrEmpty(config.ProxyHost))
{
ICredentials credentials = new NetworkCredential(config.ProxyUser, config.ProxyPassword);
proxy.Credentials = credentials;
}
// Host explicitly specified, do not use default proxy
WebProxy proxy = new WebProxy(config.ProxyHost, int.Parse(config.ProxyPort));

// 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++)
// 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))
{
// 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("*", ".*");

entry = entry.StartsWith("^") ? entry : $"^{entry}";

entry = entry.EndsWith("$") ? entry : $"{entry}$";

// Replace with the valid entry syntax
bypassList[i] = entry;
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("*", ".*");

entry = entry.StartsWith("^") ? entry : $"^{entry}";

entry = entry.EndsWith("$") ? entry : $"{entry}$";

// Replace with the valid entry syntax
bypassList[i] = entry;

}
proxy.BypassList = bypassList;
}
proxy.BypassList = bypassList;
}

HttpClientHandler httpHandlerWithProxy = (HttpClientHandler)httpHandler;
httpHandlerWithProxy.UseProxy = true;
httpHandlerWithProxy.Proxy = proxy;
return httpHandlerWithProxy;
httpHandler.Proxy = proxy;
}
}
return httpHandler;
}
Expand Down Expand Up @@ -384,7 +393,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
if (httpTimeout.Ticks == 0)
childCts.Cancel();
else
childCts.CancelAfter(httpTimeout);
childCts.CancelAfter(httpTimeout);
}
response = await base.SendAsync(requestMessage, childCts == null ?
cancellationToken : childCts.Token).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ internal HttpClientConfig BuildHttpClientConfig()
{
return new HttpClientConfig(
!insecureMode,
proxyProperties.useProxy,
proxyProperties.proxyHost,
proxyProperties.proxyPort,
proxyProperties.proxyUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Snowflake.Data.Core

internal class SFSessionHttpClientProxyProperties
{
internal bool useProxy = false;
internal string proxyHost = null;
internal string proxyPort = null;
internal string nonProxyHosts = null;
Expand All @@ -22,7 +23,13 @@ internal class Extractor : IExtractor
public SFSessionHttpClientProxyProperties ExtractProperties(SFSessionProperties propertiesDictionary)
{
var properties = new SFSessionHttpClientProxyProperties();
if (Boolean.Parse(propertiesDictionary[SFSessionProperty.USEPROXY]))

if (propertiesDictionary.TryGetValue(SFSessionProperty.USEPROXY, out string stringUseProxy))
{
properties.useProxy = Boolean.Parse(stringUseProxy);
}

if (properties.useProxy)
{
// Let's try to get the associated RestRequester
propertiesDictionary.TryGetValue(SFSessionProperty.PROXYHOST, out properties.proxyHost);
Expand Down
Loading