Added proxy config

This commit is contained in:
Jonas Dellinger 2020-05-12 20:33:25 +02:00
parent 80fb19e688
commit 43a07de960
8 changed files with 89 additions and 228 deletions

View File

@ -0,0 +1,7 @@
namespace SpotifyAPI.Web
{
public class ProxyConfigTest
{
}
}

View File

@ -1,116 +0,0 @@
using System;
using NUnit.Framework;
namespace SpotifyAPI.Web.Tests
{
[TestFixture]
public class ProxyConfigTest
{
#region GetUri
[Test]
public void GetUri_HostNameWithScheme()
{
ProxyConfig config = new ProxyConfig { Host = "https://test-host.com" };
CheckUri(config.GetUri(), "https", "test-host.com", 80);
}
[Test]
public void GetUri_HostNameWithoutScheme()
{
ProxyConfig config = new ProxyConfig { Host = "test-host.com" };
CheckUri(config.GetUri(), "http", "test-host.com", 80);
}
[Test]
public void GetUri_HostNameWithSchemeAndPort()
{
ProxyConfig config = new ProxyConfig
{
Host = "https://test-host.com",
Port = 8080
};
CheckUri(config.GetUri(), "https", "test-host.com", 8080);
}
[Test]
public void GetUri_HostAddressWithScheme()
{
ProxyConfig config = new ProxyConfig { Host = "https://192.168.0.1" };
CheckUri(config.GetUri(), "https", "192.168.0.1", 80);
}
[Test]
public void GetUri_HostAddressWithoutScheme()
{
ProxyConfig config = new ProxyConfig { Host = "192.168.0.1" };
CheckUri(config.GetUri(), "http", "192.168.0.1", 80);
}
[Test]
public void GetUri_HostAddressWithSchemeAndPort()
{
ProxyConfig config = new ProxyConfig
{
Host = "https://192.168.0.1",
Port = 8080
};
CheckUri(config.GetUri(), "https", "192.168.0.1", 8080);
}
[Test]
public void GetUri_NullHost()
{
ProxyConfig config = new ProxyConfig { Host = null };
Assert.Throws<ArgumentNullException>(() => config.GetUri());
}
[Test]
public void GetUri_EmptyHost()
{
ProxyConfig config = new ProxyConfig { Host = string.Empty };
Assert.Throws<UriFormatException>(() => config.GetUri());
}
[Test]
public void GetUri_NegativePort()
{
ProxyConfig config = new ProxyConfig
{
Host = "test-host.com",
Port = -10
};
Assert.Throws<ArgumentOutOfRangeException>(() => config.GetUri());
}
#endregion GetUri
[Test]
public void Set_Null()
{
ProxyConfig config = new ProxyConfig
{
Host = "https://test-host.com",
Port = 1234,
Username = "admin",
Password = "password",
BypassProxyOnLocal = true
};
config.Set(null);
Assert.NotNull(config);
Assert.Null(config.Host);
Assert.AreEqual(80, config.Port);
Assert.Null(config.Username);
Assert.Null(config.Password);
Assert.False(config.BypassProxyOnLocal);
}
private static void CheckUri(Uri uri, string expectedScheme, string expectedHost, int expectedPort)
{
Assert.AreEqual(expectedScheme, uri.Scheme);
Assert.AreEqual(expectedHost, uri.Host);
Assert.AreEqual(expectedPort, uri.Port);
}
}
}

View File

@ -23,7 +23,7 @@ namespace SpotifyAPI.Web
/// <param name="httpClient"></param> /// <param name="httpClient"></param>
/// <param name="retryHandler"></param> /// <param name="retryHandler"></param>
/// <param name="httpLogger"></param> /// <param name="httpLogger"></param>
/// <param name="paginator"></param> /// <param name="defaultPaginator"></param>
public SpotifyClientConfig( public SpotifyClientConfig(
Uri baseAddress, Uri baseAddress,
IAuthenticator authenticator, IAuthenticator authenticator,
@ -31,7 +31,7 @@ namespace SpotifyAPI.Web
IHTTPClient httpClient, IHTTPClient httpClient,
IRetryHandler retryHandler, IRetryHandler retryHandler,
IHTTPLogger httpLogger, IHTTPLogger httpLogger,
IPaginator paginator IPaginator defaultPaginator
) )
{ {
BaseAddress = baseAddress; BaseAddress = baseAddress;
@ -40,7 +40,7 @@ namespace SpotifyAPI.Web
HTTPClient = httpClient; HTTPClient = httpClient;
RetryHandler = retryHandler; RetryHandler = retryHandler;
HTTPLogger = httpLogger; HTTPLogger = httpLogger;
DefaultPaginator = paginator; DefaultPaginator = defaultPaginator;
} }
public SpotifyClientConfig WithToken(string token, string tokenType = "Bearer") public SpotifyClientConfig WithToken(string token, string tokenType = "Bearer")
@ -130,9 +130,9 @@ namespace SpotifyAPI.Web
} }
public SpotifyClientConfig WithDefaultPaginator(IPaginator paginator) public SpotifyClientConfig WithDefaultPaginator(IPaginator defaultPaginator)
{ {
Ensure.ArgumentNotNull(paginator, nameof(paginator)); Ensure.ArgumentNotNull(defaultPaginator, nameof(defaultPaginator));
return new SpotifyClientConfig( return new SpotifyClientConfig(
BaseAddress, BaseAddress,
@ -141,7 +141,7 @@ namespace SpotifyAPI.Web
HTTPClient, HTTPClient,
RetryHandler, RetryHandler,
HTTPLogger, HTTPLogger,
paginator defaultPaginator
); );
} }

View File

@ -6,7 +6,6 @@ namespace SpotifyAPI.Web.Http
public interface IHTTPClient : IDisposable public interface IHTTPClient : IDisposable
{ {
Task<IResponse> DoRequest(IRequest request); Task<IResponse> DoRequest(IRequest request);
void SetRequestTimeout(TimeSpan timeout); void SetRequestTimeout(TimeSpan timeout);
} }
} }

View File

@ -0,0 +1,15 @@
namespace SpotifyAPI.Web
{
public interface IProxyConfig
{
string Host { get; }
int Port { get; }
string User { get; }
string Password { get; }
bool SkipSSLCheck { get; }
/// <summary>
/// Whether to bypass the proxy server for local addresses.
/// </summary>
bool BypassProxyOnLocal { get; }
}
}

View File

@ -1,3 +1,4 @@
using System.Net;
using System.Text; using System.Text;
using System; using System;
using System.IO; using System.IO;
@ -9,6 +10,7 @@ namespace SpotifyAPI.Web.Http
{ {
public class NetHttpClient : IHTTPClient public class NetHttpClient : IHTTPClient
{ {
private readonly HttpMessageHandler _httpMessageHandler;
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
public NetHttpClient() public NetHttpClient()
@ -16,6 +18,14 @@ namespace SpotifyAPI.Web.Http
_httpClient = new HttpClient(); _httpClient = new HttpClient();
} }
public NetHttpClient(IProxyConfig proxyConfig)
{
Ensure.ArgumentNotNull(proxyConfig, nameof(proxyConfig));
_httpMessageHandler = CreateMessageHandler(proxyConfig);
_httpClient = new HttpClient(_httpMessageHandler);
}
public async Task<IResponse> DoRequest(IRequest request) public async Task<IResponse> DoRequest(IRequest request)
{ {
Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(request, nameof(request));
@ -84,6 +94,7 @@ namespace SpotifyAPI.Web.Http
if (disposing) if (disposing)
{ {
_httpClient?.Dispose(); _httpClient?.Dispose();
_httpMessageHandler?.Dispose();
} }
} }
@ -91,5 +102,35 @@ namespace SpotifyAPI.Web.Http
{ {
_httpClient.Timeout = timeout; _httpClient.Timeout = timeout;
} }
private static HttpMessageHandler CreateMessageHandler(IProxyConfig proxyConfig)
{
var proxy = new WebProxy
{
Address = new UriBuilder(proxyConfig.Host) { Port = proxyConfig.Port }.Uri,
UseDefaultCredentials = true,
BypassProxyOnLocal = proxyConfig.BypassProxyOnLocal
};
if (!string.IsNullOrEmpty(proxyConfig.User) || !string.IsNullOrEmpty(proxyConfig.Password))
{
proxy.UseDefaultCredentials = false;
proxy.Credentials = new NetworkCredential(proxyConfig.User, proxyConfig.Password);
}
var httpClientHandler = new HttpClientHandler
{
PreAuthenticate = proxy.UseDefaultCredentials,
UseDefaultCredentials = proxy.UseDefaultCredentials,
UseProxy = true,
Proxy = proxy,
};
if (proxyConfig.SkipSSLCheck)
{
httpClientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
}
return httpClientHandler;
}
} }
} }

View File

@ -0,0 +1,20 @@
namespace SpotifyAPI.Web
{
public class ProxyConfig : IProxyConfig
{
public ProxyConfig(string host, int port)
{
Ensure.ArgumentNotNullOrEmptyString(host, nameof(host));
Host = host;
Port = port;
}
public string Host { get; }
public int Port { get; }
public string User { get; set; }
public string Password { get; set; }
public bool BypassProxyOnLocal { get; set; }
public bool SkipSSLCheck { get; set; }
}
}

View File

@ -1,105 +0,0 @@
using System;
using System.Net;
using System.Net.Http;
namespace SpotifyAPI.Web
{
public class ProxyConfig
{
public string Host { get; set; }
public int Port { get; set; } = 80;
public string Username { get; set; }
public string Password { get; set; }
/// <summary>
/// Whether to bypass the proxy server for local addresses.
/// </summary>
public bool BypassProxyOnLocal { get; set; }
public void Set(ProxyConfig proxyConfig)
{
Host = proxyConfig?.Host;
Port = proxyConfig?.Port ?? 80;
Username = proxyConfig?.Username;
Password = proxyConfig?.Password;
BypassProxyOnLocal = proxyConfig?.BypassProxyOnLocal ?? false;
}
/// <summary>
/// Whether both <see cref="Host"/> and <see cref="Port"/> have valid values.
/// </summary>
/// <returns></returns>
public bool IsValid()
{
return !string.IsNullOrWhiteSpace(Host) && Port > 0;
}
/// <summary>
/// Create a <see cref="Uri"/> from the host and port number
/// </summary>
/// <returns>A URI</returns>
public Uri GetUri()
{
UriBuilder uriBuilder = new UriBuilder(Host)
{
Port = Port
};
return uriBuilder.Uri;
}
/// <summary>
/// Creates a <see cref="WebProxy"/> from the proxy details of this object.
/// </summary>
/// <returns>A <see cref="WebProxy"/> or <code>null</code> if the proxy details are invalid.</returns>
public WebProxy CreateWebProxy()
{
if (!IsValid())
{
return null;
}
WebProxy proxy = new WebProxy
{
Address = GetUri(),
UseDefaultCredentials = true,
BypassProxyOnLocal = BypassProxyOnLocal
};
if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
{
return proxy;
}
proxy.UseDefaultCredentials = false;
proxy.Credentials = new NetworkCredential(Username, Password);
return proxy;
}
public static HttpClientHandler CreateClientHandler(ProxyConfig proxyConfig = null)
{
HttpClientHandler clientHandler = new HttpClientHandler
{
PreAuthenticate = false,
UseDefaultCredentials = true,
UseProxy = false
};
if (string.IsNullOrWhiteSpace(proxyConfig?.Host))
{
return clientHandler;
}
WebProxy proxy = proxyConfig.CreateWebProxy();
clientHandler.UseProxy = true;
clientHandler.Proxy = proxy;
clientHandler.UseDefaultCredentials = proxy.UseDefaultCredentials;
clientHandler.PreAuthenticate = proxy.UseDefaultCredentials;
return clientHandler;
}
}
}