diff --git a/SpotifyAPI.Web.Tests/Http/ProxyConfigTest.cs b/SpotifyAPI.Web.Tests/Http/ProxyConfigTest.cs new file mode 100644 index 00000000..86d459c6 --- /dev/null +++ b/SpotifyAPI.Web.Tests/Http/ProxyConfigTest.cs @@ -0,0 +1,7 @@ +namespace SpotifyAPI.Web +{ + public class ProxyConfigTest + { + + } +} diff --git a/SpotifyAPI.Web.Tests/ProxyConfigTest.cs b/SpotifyAPI.Web.Tests/ProxyConfigTest.cs deleted file mode 100644 index 3ab9897c..00000000 --- a/SpotifyAPI.Web.Tests/ProxyConfigTest.cs +++ /dev/null @@ -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(() => config.GetUri()); - } - - [Test] - public void GetUri_EmptyHost() - { - ProxyConfig config = new ProxyConfig { Host = string.Empty }; - Assert.Throws(() => config.GetUri()); - } - - [Test] - public void GetUri_NegativePort() - { - ProxyConfig config = new ProxyConfig - { - Host = "test-host.com", - Port = -10 - }; - Assert.Throws(() => 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); - } - } -} diff --git a/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs b/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs index 5588c55b..1458c1d7 100644 --- a/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs +++ b/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs @@ -23,7 +23,7 @@ namespace SpotifyAPI.Web /// /// /// - /// + /// public SpotifyClientConfig( Uri baseAddress, IAuthenticator authenticator, @@ -31,7 +31,7 @@ namespace SpotifyAPI.Web IHTTPClient httpClient, IRetryHandler retryHandler, IHTTPLogger httpLogger, - IPaginator paginator + IPaginator defaultPaginator ) { BaseAddress = baseAddress; @@ -40,7 +40,7 @@ namespace SpotifyAPI.Web HTTPClient = httpClient; RetryHandler = retryHandler; HTTPLogger = httpLogger; - DefaultPaginator = paginator; + DefaultPaginator = defaultPaginator; } 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( BaseAddress, @@ -141,7 +141,7 @@ namespace SpotifyAPI.Web HTTPClient, RetryHandler, HTTPLogger, - paginator + defaultPaginator ); } diff --git a/SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs b/SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs index 5d830c0d..78a74ef6 100644 --- a/SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs +++ b/SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs @@ -6,7 +6,6 @@ namespace SpotifyAPI.Web.Http public interface IHTTPClient : IDisposable { Task DoRequest(IRequest request); - void SetRequestTimeout(TimeSpan timeout); } } diff --git a/SpotifyAPI.Web/Http/Interfaces/IProxyConfig.cs b/SpotifyAPI.Web/Http/Interfaces/IProxyConfig.cs new file mode 100644 index 00000000..1076feb3 --- /dev/null +++ b/SpotifyAPI.Web/Http/Interfaces/IProxyConfig.cs @@ -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; } + /// + /// Whether to bypass the proxy server for local addresses. + /// + bool BypassProxyOnLocal { get; } + } +} diff --git a/SpotifyAPI.Web/Http/NetHttpClient.cs b/SpotifyAPI.Web/Http/NetHttpClient.cs index 0a922e74..dc860b12 100644 --- a/SpotifyAPI.Web/Http/NetHttpClient.cs +++ b/SpotifyAPI.Web/Http/NetHttpClient.cs @@ -1,3 +1,4 @@ +using System.Net; using System.Text; using System; using System.IO; @@ -9,6 +10,7 @@ namespace SpotifyAPI.Web.Http { public class NetHttpClient : IHTTPClient { + private readonly HttpMessageHandler _httpMessageHandler; private readonly HttpClient _httpClient; public NetHttpClient() @@ -16,6 +18,14 @@ namespace SpotifyAPI.Web.Http _httpClient = new HttpClient(); } + public NetHttpClient(IProxyConfig proxyConfig) + { + Ensure.ArgumentNotNull(proxyConfig, nameof(proxyConfig)); + + _httpMessageHandler = CreateMessageHandler(proxyConfig); + _httpClient = new HttpClient(_httpMessageHandler); + } + public async Task DoRequest(IRequest request) { Ensure.ArgumentNotNull(request, nameof(request)); @@ -84,6 +94,7 @@ namespace SpotifyAPI.Web.Http if (disposing) { _httpClient?.Dispose(); + _httpMessageHandler?.Dispose(); } } @@ -91,5 +102,35 @@ namespace SpotifyAPI.Web.Http { _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; + } } } diff --git a/SpotifyAPI.Web/Http/ProxyConfig.cs b/SpotifyAPI.Web/Http/ProxyConfig.cs new file mode 100644 index 00000000..5d08e9ee --- /dev/null +++ b/SpotifyAPI.Web/Http/ProxyConfig.cs @@ -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; } + } +} diff --git a/SpotifyAPI.Web/ProxyConfig.cs b/SpotifyAPI.Web/ProxyConfig.cs deleted file mode 100644 index eacf6a7d..00000000 --- a/SpotifyAPI.Web/ProxyConfig.cs +++ /dev/null @@ -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; } - - /// - /// Whether to bypass the proxy server for local addresses. - /// - 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; - } - - /// - /// Whether both and have valid values. - /// - /// - public bool IsValid() - { - return !string.IsNullOrWhiteSpace(Host) && Port > 0; - } - - /// - /// Create a from the host and port number - /// - /// A URI - public Uri GetUri() - { - UriBuilder uriBuilder = new UriBuilder(Host) - { - Port = Port - }; - return uriBuilder.Uri; - } - - /// - /// Creates a from the proxy details of this object. - /// - /// A or null if the proxy details are invalid. - 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; - } - } -}