2020-05-01 19:05:28 +01:00
|
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
2022-11-27 12:29:35 +00:00
|
|
|
using System.Net;
|
2020-05-01 19:05:28 +01:00
|
|
|
using System.Net.Http;
|
2022-11-27 12:29:35 +00:00
|
|
|
using System.Text;
|
2022-11-18 11:30:09 +00:00
|
|
|
using System.Threading;
|
2022-11-27 12:29:35 +00:00
|
|
|
using System.Threading.Tasks;
|
2020-05-01 19:05:28 +01:00
|
|
|
|
|
|
|
namespace SpotifyAPI.Web.Http
|
|
|
|
{
|
|
|
|
public class NetHttpClient : IHTTPClient
|
|
|
|
{
|
2020-05-25 17:00:38 +01:00
|
|
|
private readonly HttpMessageHandler? _httpMessageHandler;
|
2020-05-02 12:04:26 +01:00
|
|
|
private readonly HttpClient _httpClient;
|
2020-05-01 19:05:28 +01:00
|
|
|
|
|
|
|
public NetHttpClient()
|
|
|
|
{
|
|
|
|
_httpClient = new HttpClient();
|
|
|
|
}
|
|
|
|
|
2020-05-22 11:23:25 +01:00
|
|
|
public NetHttpClient(HttpClient httpClient)
|
|
|
|
{
|
|
|
|
_httpClient = httpClient;
|
|
|
|
}
|
|
|
|
|
2020-05-12 19:33:25 +01:00
|
|
|
public NetHttpClient(IProxyConfig proxyConfig)
|
|
|
|
{
|
|
|
|
Ensure.ArgumentNotNull(proxyConfig, nameof(proxyConfig));
|
|
|
|
|
|
|
|
_httpMessageHandler = CreateMessageHandler(proxyConfig);
|
|
|
|
_httpClient = new HttpClient(_httpMessageHandler);
|
|
|
|
}
|
2022-11-18 11:30:09 +00:00
|
|
|
public async Task<IResponse> DoRequest(IRequest request, CancellationToken cancel)
|
2020-05-01 19:05:28 +01:00
|
|
|
{
|
|
|
|
Ensure.ArgumentNotNull(request, nameof(request));
|
|
|
|
|
2020-12-26 17:28:44 +00:00
|
|
|
using HttpRequestMessage requestMsg = BuildRequestMessage(request);
|
|
|
|
var responseMsg = await _httpClient
|
2022-11-18 11:30:09 +00:00
|
|
|
.SendAsync(requestMsg, HttpCompletionOption.ResponseContentRead, cancel)
|
2020-12-26 17:28:44 +00:00
|
|
|
.ConfigureAwait(false);
|
2020-05-01 19:05:28 +01:00
|
|
|
|
2022-11-18 11:30:09 +00:00
|
|
|
return await BuildResponse(responseMsg, cancel).ConfigureAwait(false);
|
2020-05-01 19:05:28 +01:00
|
|
|
}
|
|
|
|
|
2022-11-18 11:30:09 +00:00
|
|
|
private static async Task<IResponse> BuildResponse(HttpResponseMessage responseMsg, CancellationToken cancel)
|
2020-05-01 19:05:28 +01:00
|
|
|
{
|
|
|
|
Ensure.ArgumentNotNull(responseMsg, nameof(responseMsg));
|
|
|
|
|
|
|
|
// We only support text stuff for now
|
2020-12-26 17:28:44 +00:00
|
|
|
using var content = responseMsg.Content;
|
|
|
|
var headers = responseMsg.Headers.ToDictionary(header => header.Key, header => header.Value.First());
|
2023-11-03 22:23:54 +00:00
|
|
|
#if NET5_0_OR_GREATER
|
2022-11-18 11:30:09 +00:00
|
|
|
var body = await responseMsg.Content.ReadAsStringAsync(cancel).ConfigureAwait(false);
|
2023-11-03 22:23:54 +00:00
|
|
|
#else
|
|
|
|
var body = await responseMsg.Content.ReadAsStringAsync().ConfigureAwait(false);
|
2022-11-18 11:30:09 +00:00
|
|
|
#endif
|
2020-12-26 17:28:44 +00:00
|
|
|
var contentType = content.Headers?.ContentType?.MediaType;
|
2020-05-16 17:48:32 +01:00
|
|
|
|
2020-12-26 17:28:44 +00:00
|
|
|
return new Response(headers)
|
|
|
|
{
|
|
|
|
ContentType = contentType,
|
|
|
|
StatusCode = responseMsg.StatusCode,
|
|
|
|
Body = body
|
|
|
|
};
|
2020-05-01 19:05:28 +01:00
|
|
|
}
|
|
|
|
|
2020-05-05 14:30:00 +01:00
|
|
|
private static HttpRequestMessage BuildRequestMessage(IRequest request)
|
2020-05-01 19:05:28 +01:00
|
|
|
{
|
|
|
|
Ensure.ArgumentNotNull(request, nameof(request));
|
|
|
|
|
|
|
|
var fullUri = new Uri(request.BaseAddress, request.Endpoint).ApplyParameters(request.Parameters);
|
|
|
|
var requestMsg = new HttpRequestMessage(request.Method, fullUri);
|
|
|
|
foreach (var header in request.Headers)
|
|
|
|
{
|
|
|
|
requestMsg.Headers.Add(header.Key, header.Value);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (request.Body)
|
|
|
|
{
|
|
|
|
case HttpContent body:
|
|
|
|
requestMsg.Content = body;
|
|
|
|
break;
|
|
|
|
case string body:
|
2020-05-03 00:00:35 +01:00
|
|
|
requestMsg.Content = new StringContent(body, Encoding.UTF8, "application/json");
|
2020-05-01 19:05:28 +01:00
|
|
|
break;
|
|
|
|
case Stream body:
|
|
|
|
requestMsg.Content = new StreamContent(body);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return requestMsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
Dispose(true);
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
}
|
|
|
|
|
2020-05-05 14:30:00 +01:00
|
|
|
protected virtual void Dispose(bool disposing)
|
2020-05-01 19:05:28 +01:00
|
|
|
{
|
|
|
|
if (disposing)
|
|
|
|
{
|
|
|
|
_httpClient?.Dispose();
|
2020-05-12 19:33:25 +01:00
|
|
|
_httpMessageHandler?.Dispose();
|
2020-05-01 19:05:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetRequestTimeout(TimeSpan timeout)
|
|
|
|
{
|
|
|
|
_httpClient.Timeout = timeout;
|
|
|
|
}
|
2020-05-12 19:33:25 +01:00
|
|
|
|
2024-02-10 10:56:20 +00:00
|
|
|
private static HttpClientHandler CreateMessageHandler(IProxyConfig proxyConfig)
|
2020-05-12 19:33:25 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2020-05-01 19:05:28 +01:00
|
|
|
}
|
|
|
|
}
|