First attempt to reuse HttpClient

This commit is contained in:
Darrel
2015-05-13 12:17:35 -04:00
committed by Brendan Forster
parent e6e7c3d393
commit 14fe8bcbcd
+100 -22
View File
@@ -18,12 +18,21 @@ namespace Octokit.Internal
public class HttpClientAdapter : IHttpClient
{
readonly IWebProxy _webProxy;
HttpClient _http;
public HttpClientAdapter() { }
public HttpClientAdapter(IWebProxy webProxy)
public HttpClientAdapter(IWebProxy webProxy, HttpMessageHandler handler = null)
{
_webProxy = webProxy;
if (handler == null)
{
handler = GetHandler();
}
_http = new HttpClient(new RedirectHandler() { InnerHandler = handler});
}
/// <summary>
@@ -36,9 +45,38 @@ namespace Octokit.Internal
{
Ensure.ArgumentNotNull(request, "request");
var cancellationTokenForRequest = GetCancellationTokenForRequest(request, cancellationToken);
using (var requestMessage = BuildRequestMessage(request))
{
// Make the request
var responseMessage = await _http.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, cancellationTokenForRequest)
.ConfigureAwait(false);
return await BuildResponse(responseMessage).ConfigureAwait(false);
}
}
static CancellationToken GetCancellationTokenForRequest(IRequest request, CancellationToken cancellationToken)
{
var cancellationTokenForRequest = cancellationToken;
if (request.Timeout != TimeSpan.Zero)
{
var timeoutCancellation = new CancellationTokenSource(request.Timeout);
var unifiedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellation.Token);
cancellationTokenForRequest = unifiedCancellationToken.Token;
}
return cancellationTokenForRequest;
}
private HttpClientHandler GetHandler()
{
var httpOptions = new HttpClientHandler
{
AllowAutoRedirect = request.AllowAutoRedirect
AllowAutoRedirect = false
};
if (httpOptions.SupportsAutomaticDecompression)
{
@@ -49,25 +87,7 @@ namespace Octokit.Internal
httpOptions.UseProxy = true;
httpOptions.Proxy = _webProxy;
}
var http = new HttpClient(httpOptions);
var cancellationTokenForRequest = cancellationToken;
if (request.Timeout != TimeSpan.Zero)
{
var timeoutCancellation = new CancellationTokenSource(request.Timeout);
var unifiedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellation.Token);
cancellationTokenForRequest = unifiedCancellationToken.Token;
}
using (var requestMessage = BuildRequestMessage(request))
{
// Make the request
var responseMessage = await http.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, cancellationTokenForRequest)
.ConfigureAwait(false);
return await BuildResponse(responseMessage).ConfigureAwait(false);
}
return httpOptions;
}
protected async virtual Task<IResponse> BuildResponse(HttpResponseMessage responseMessage)
@@ -109,6 +129,8 @@ namespace Octokit.Internal
{
var fullUri = new Uri(request.BaseAddress, request.Endpoint);
requestMessage = new HttpRequestMessage(request.Method, fullUri);
requestMessage.Properties["AllowAutoRedirect"] = request.AllowAutoRedirect;
foreach (var header in request.Headers)
{
requestMessage.Headers.Add(header.Key, header.Value);
@@ -153,4 +175,60 @@ namespace Octokit.Internal
return null;
}
}
public class RedirectHandler : DelegatingHandler
{
public bool Enabled { get; set; }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
var allowAutoRedirect = (bool)request.Properties["AllowAutoRedirect"];
if (!allowAutoRedirect) return response;
if (response.StatusCode == HttpStatusCode.MovedPermanently
|| response.StatusCode == HttpStatusCode.Moved
|| response.StatusCode == HttpStatusCode.Redirect
|| response.StatusCode == HttpStatusCode.Found
|| response.StatusCode == HttpStatusCode.SeeOther
|| response.StatusCode == HttpStatusCode.RedirectKeepVerb
|| response.StatusCode == HttpStatusCode.TemporaryRedirect
|| (int)response.StatusCode == 308)
{
var newRequest = CopyRequest(response.RequestMessage);
if (response.StatusCode == HttpStatusCode.Redirect
|| response.StatusCode == HttpStatusCode.Found
|| response.StatusCode == HttpStatusCode.SeeOther)
{
newRequest.Content = null;
newRequest.Method = HttpMethod.Get;
}
newRequest.RequestUri = response.Headers.Location;
response = await base.SendAsync(newRequest, cancellationToken);
}
return response;
}
private static HttpRequestMessage CopyRequest(HttpRequestMessage oldRequest)
{
var newrequest = new HttpRequestMessage(oldRequest.Method, oldRequest.RequestUri);
foreach (var header in oldRequest.Headers)
{
newrequest.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
foreach (var property in oldRequest.Properties)
{
newrequest.Properties.Add(property);
}
if (oldRequest.Content != null) newrequest.Content = new StreamContent(oldRequest.Content.ReadAsStreamAsync().Result);
return newrequest;
}
}
}