Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ dotnet_diagnostic.CA1310.severity = none
# JSON002: Probable JSON string detected
dotnet_diagnostic.JSON002.severity = none

# S4830: Server certificates should be verified during SSL/TLS connection
dotnet_diagnostic.S4830.severity = none

[*.vb]
###############################
# VB Coding Conventions #
Expand Down
8 changes: 7 additions & 1 deletion APIMatic.Core.Test/Http/CoreHttpClientConfigurationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public void Builder_BuildWithPrameters_CoreHttpClientConfiguration()
{
// Arrange
var timeout = 180;
var skipSslCertVerification = true;
var numberOfRetries = 3;
var backoffFactor = 3;
var retryInterval = 4.5;
Expand All @@ -32,6 +33,7 @@ public void Builder_BuildWithPrameters_CoreHttpClientConfiguration()
// Act
var config = _config.ToBuilder()
.Timeout(TimeSpan.FromSeconds(timeout))
.SkipSslCertVerification(skipSslCertVerification)
.NumberOfRetries(numberOfRetries)
.BackoffFactor(backoffFactor)
.RetryInterval(retryInterval)
Expand All @@ -43,6 +45,7 @@ public void Builder_BuildWithPrameters_CoreHttpClientConfiguration()
// Assert
Assert.NotNull(config);
Assert.AreEqual(config.Timeout, TimeSpan.FromSeconds(timeout));
Assert.AreEqual(config.SkipSslCertVerification, skipSslCertVerification);
Assert.AreEqual(config.NumberOfRetries, numberOfRetries);
Assert.AreEqual(config.BackoffFactor, backoffFactor);
Assert.AreEqual(config.RetryInterval, retryInterval);
Expand All @@ -60,10 +63,12 @@ public void Builder_BuildWithInvalidPrameters_CoreHttpClientConfiguration()
var backoffFactor = 0;
var retryInterval = -1;
var maximumRetryWaitTime = -1;
var skipSslCertVerification = false;

var config = _config.ToBuilder()
.HttpClientInstance(null)
.Timeout(TimeSpan.FromSeconds(timeout))
.SkipSslCertVerification(skipSslCertVerification)
.NumberOfRetries(numberOfRetries)
.BackoffFactor(backoffFactor)
.RetryInterval(retryInterval)
Expand All @@ -83,6 +88,7 @@ public void Builder_BuildWithInvalidPrameters_CoreHttpClientConfiguration()
Assert.NotNull(config);
Assert.NotNull(config.HttpClientInstance);
Assert.AreEqual(config.Timeout, TimeSpan.FromSeconds(defaultTimeout));
Assert.AreEqual(config.SkipSslCertVerification, skipSslCertVerification);
Assert.AreEqual(config.NumberOfRetries, defaultNumberOfRetries);
Assert.AreEqual(config.BackoffFactor, defaultBackoffFactor);
Assert.AreEqual(config.RetryInterval, defaultRetryInterval);
Expand All @@ -98,7 +104,7 @@ public void ToString_Default_CoreHttpClientConfiguration()
var actual = _config.ToString();

// Assert
var expected = "HttpClientConfiguration: 00:01:40 , 0 , 2 , 1 , 00:02:00 , System.Collections.Immutable.ImmutableList`1[System.Int32] , System.Collections.Immutable.ImmutableList`1[System.Net.Http.HttpMethod] , System.Net.Http.HttpClient , True ";
var expected = "HttpClientConfiguration: 00:01:40 , False , 0 , 2 , 1 , 00:02:00 , System.Collections.Immutable.ImmutableList`1[System.Int32] , System.Collections.Immutable.ImmutableList`1[System.Net.Http.HttpMethod] , System.Net.Http.HttpClient , True ";
Assert.AreEqual(expected, actual);
}
}
Expand Down
71 changes: 71 additions & 0 deletions APIMatic.Core.Test/Http/HttpClientWrapperSSLTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using APIMatic.Core.Http.Configuration;
using NUnit.Framework;

namespace APIMatic.Core.Test.Http
{
[TestFixture]
public class HttpClientWrapperSSLTest : TestBase
{
private readonly string expiredSSLCertUrl = "https://expired.badssl.com/";

[Test]
public void TestHttpClientSSLCertificateVerification_ExceptionResponse()
{
var expectedValue = "The SSL connection could not be established, see inner exception.";
var clientConfiguration = new CoreHttpClientConfiguration.Builder()
.Build();

var config = new GlobalConfiguration.Builder()
.ServerUrls(new Dictionary<Enum, string>
{
{ MockServer.Server1, expiredSSLCertUrl },
}, MockServer.Server1)
.HttpConfiguration(clientConfiguration)
.ApiCallback(ApiCallBack)
.Build();

var client = config.HttpClient;

var request = config.GlobalRequestBuilder()
.Setup(HttpMethod.Get, string.Empty)
.Build();

// Act
var ex = Assert.ThrowsAsync<HttpRequestException>(() => client.ExecuteAsync(request));
Assert.AreEqual(expectedValue, ex.Message);
}

[Test]
public async Task TestHttpClientSkipSSLCertificateVerification_OKResponse()
{
var clientConfiguration = new CoreHttpClientConfiguration.Builder()
.SkipSslCertVerification(true)
.Build();

var config = new GlobalConfiguration.Builder()
.ServerUrls(new Dictionary<Enum, string>
{
{ MockServer.Server1, expiredSSLCertUrl },
}, MockServer.Server1)
.HttpConfiguration(clientConfiguration)
.ApiCallback(ApiCallBack)
.Build();

var client = config.HttpClient;

var request = config.GlobalRequestBuilder()
.Setup(HttpMethod.Get, string.Empty)
.Build();

// Act
var actual = await client.ExecuteAsync(request);

Assert.AreEqual(actual.StatusCode, (int)HttpStatusCode.OK);
}
}
}
53 changes: 50 additions & 3 deletions APIMatic.Core/Http/Configuration/CoreHttpClientConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class CoreHttpClientConfiguration : ICoreHttpClientConfiguration
/// </summary>
private CoreHttpClientConfiguration(
TimeSpan timeout,
bool skipSslCertVerification,
int numberOfRetries,
int backoffFactor,
double retryInterval,
Expand All @@ -30,6 +31,7 @@ private CoreHttpClientConfiguration(
bool overrideHttpClientConfiguration)
{
Timeout = timeout;
SkipSslCertVerification = skipSslCertVerification;
NumberOfRetries = numberOfRetries;
BackoffFactor = backoffFactor;
RetryInterval = retryInterval;
Expand All @@ -45,6 +47,11 @@ private CoreHttpClientConfiguration(
/// </summary>
public TimeSpan Timeout { get; }

/// <summary>
/// Gets Whether to skip verification of SSL certificates.
/// </summary>
public bool SkipSslCertVerification { get; }

/// <summary>
/// Gets Number of times the request is retried.
/// </summary>
Expand Down Expand Up @@ -90,6 +97,7 @@ public override string ToString()
{
return "HttpClientConfiguration: " +
$"{Timeout} , " +
$"{SkipSslCertVerification} , " +
$"{NumberOfRetries} , " +
$"{BackoffFactor} , " +
$"{RetryInterval} , " +
Expand All @@ -108,6 +116,7 @@ public Builder ToBuilder()
{
var builder = new Builder()
.Timeout(Timeout)
.SkipSslCertVerification(SkipSslCertVerification)
.NumberOfRetries(NumberOfRetries)
.BackoffFactor(BackoffFactor)
.RetryInterval(RetryInterval)
Expand All @@ -125,6 +134,7 @@ public Builder ToBuilder()
public class Builder
{
private TimeSpan timeout = TimeSpan.FromSeconds(100);
private bool skipSslCertVerification = false;
private int numberOfRetries = 0;
private int backoffFactor = 2;
private double retryInterval = 1;
Expand All @@ -137,7 +147,7 @@ public class Builder
{
"GET", "PUT"
}.Select(val => new HttpMethod(val)).ToImmutableList();
private HttpClient httpClientInstance = new HttpClient();
private HttpClient httpClientInstance = null;
private bool overrideHttpClientConfiguration = true;

/// <summary>
Expand All @@ -151,6 +161,17 @@ public Builder Timeout(TimeSpan timeout)
return this;
}

/// <summary>
/// Sets the SkipSslCertVerification.
/// </summary>
/// <param name="skipSslCertVerification">Bool for skipping (or not) SSL certificate verification</param>
/// <returns>Builder.</returns>
public Builder SkipSslCertVerification(bool skipSslCertVerification)
{
this.skipSslCertVerification = skipSslCertVerification;
return this;
}

/// <summary>
/// Sets the NumberOfRetries.
/// </summary>
Expand Down Expand Up @@ -225,7 +246,7 @@ public Builder RequestMethodsToRetry(IList<HttpMethod> requestMethodsToRetry)
/// <returns>Builder.</returns>
public Builder HttpClientInstance(HttpClient httpClientInstance, bool overrideHttpClientConfiguration = true)
{
this.httpClientInstance = httpClientInstance ?? new HttpClient();
this.httpClientInstance = httpClientInstance;
this.overrideHttpClientConfiguration = overrideHttpClientConfiguration;
return this;
}
Expand All @@ -238,15 +259,41 @@ public CoreHttpClientConfiguration Build()
{
return new CoreHttpClientConfiguration(
timeout,
skipSslCertVerification,
numberOfRetries,
backoffFactor,
retryInterval,
maximumRetryWaitTime,
statusCodesToRetry,
requestMethodsToRetry,
httpClientInstance,
GetInitializedHttpClientInstance(),
overrideHttpClientConfiguration);
}

private HttpClient GetInitializedHttpClientInstance()
{
if (overrideHttpClientConfiguration)
{
if (skipSslCertVerification)
{
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }
};
return new HttpClient(httpClientHandler, disposeHandler: true)
{
Timeout = timeout,
};
}

var httpClient = httpClientInstance ?? new HttpClient();
httpClient.Timeout = timeout;

return httpClient;
}

return httpClientInstance ?? new HttpClient();
}
}
}
}
2 changes: 0 additions & 2 deletions APIMatic.Core/Http/HttpClientWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ public HttpClientWrapper(ICoreHttpClientConfiguration httpClientConfig)
_backoffFactor = httpClientConfig.BackoffFactor;
_retryInterval = httpClientConfig.RetryInterval;
_maximumRetryWaitTime = httpClientConfig.MaximumRetryWaitTime;
_client.Timeout = httpClientConfig.Timeout;
}
}

Expand Down Expand Up @@ -292,7 +291,6 @@ private double GetExponentialWaitTime(int retryAttempt)
{
double noise = new Random().NextDouble() * 100;
return (1000 * _retryInterval * Math.Pow(_backoffFactor, retryAttempt - 1)) + noise;

}

private static Dictionary<string, string> GetCombinedResponseHeaders(HttpResponseMessage responseMessage)
Expand Down