using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.ApiInteraction
{
///
/// Class AsyncHttpClient
///
public class AsyncHttpClient : IAsyncHttpClient
{
///
/// Gets or sets the HTTP client.
///
/// The HTTP client.
private HttpClient HttpClient { get; set; }
///
/// Initializes a new instance of the class.
///
public AsyncHttpClient(HttpMessageHandler handler)
{
HttpClient = new HttpClient(handler);
}
///
/// Initializes a new instance of the class.
///
public AsyncHttpClient()
{
HttpClient = new HttpClient();
}
///
/// Gets the stream async.
///
/// The URL.
/// The logger.
/// The cancellation token.
/// Task{Stream}.
///
public async Task GetStreamAsync(string url, ILogger logger, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
logger.Debug("Sending Http Get to {0}", url);
try
{
var msg = await HttpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
EnsureSuccessStatusCode(msg);
return await msg.Content.ReadAsStreamAsync().ConfigureAwait(false);
}
catch (HttpRequestException ex)
{
logger.ErrorException("Error getting response from " + url, ex);
throw new HttpException(ex.Message, ex);
}
catch (OperationCanceledException ex)
{
throw GetCancellationException(url, cancellationToken, ex, logger);
}
catch (Exception ex)
{
logger.ErrorException("Error requesting {0}", ex, url);
throw;
}
}
///
/// Posts the async.
///
/// The URL.
/// Type of the content.
/// Content of the post.
/// The logger.
/// The cancellation token.
/// Task{Stream}.
///
public async Task PostAsync(string url, string contentType, string postContent, ILogger logger, CancellationToken cancellationToken)
{
logger.Debug("Sending Http Post to {0}", url);
var content = new StringContent(postContent, Encoding.UTF8, contentType);
try
{
var msg = await HttpClient.PostAsync(url, content).ConfigureAwait(false);
EnsureSuccessStatusCode(msg);
return await msg.Content.ReadAsStreamAsync().ConfigureAwait(false);
}
catch (HttpRequestException ex)
{
logger.ErrorException("Error getting response from " + url, ex);
throw new HttpException(ex.Message, ex);
}
catch (OperationCanceledException ex)
{
throw GetCancellationException(url, cancellationToken, ex, logger);
}
catch (Exception ex)
{
logger.ErrorException("Error posting {0}", ex, url);
throw;
}
}
///
/// Deletes the async.
///
/// The URL.
/// The logger.
/// The cancellation token.
/// Task.
public async Task DeleteAsync(string url, ILogger logger, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
logger.Debug("Sending Http Delete to {0}", url);
try
{
using (var msg = await HttpClient.DeleteAsync(url, cancellationToken).ConfigureAwait(false))
{
EnsureSuccessStatusCode(msg);
}
}
catch (HttpRequestException ex)
{
logger.ErrorException("Error getting response from " + url, ex);
throw new HttpException(ex.Message, ex);
}
catch (OperationCanceledException ex)
{
throw GetCancellationException(url, cancellationToken, ex, logger);
}
catch (Exception ex)
{
logger.ErrorException("Error requesting {0}", ex, url);
throw;
}
}
///
/// Throws the cancellation exception.
///
/// The URL.
/// The cancellation token.
/// The exception.
/// The logger.
/// Exception.
private Exception GetCancellationException(string url, CancellationToken cancellationToken, OperationCanceledException exception, ILogger logger)
{
// If the HttpClient's timeout is reached, it will cancel the Task internally
if (!cancellationToken.IsCancellationRequested)
{
var msg = string.Format("Connection to {0} timed out", url);
logger.Error(msg);
// Throw an HttpException so that the caller doesn't think it was cancelled by user code
return new HttpException(msg, exception) { IsTimedOut = true };
}
return exception;
}
///
/// Ensures the success status code.
///
/// The response.
///
private void EnsureSuccessStatusCode(HttpResponseMessage response)
{
if (!response.IsSuccessStatusCode)
{
throw new HttpException(response.ReasonPhrase) { StatusCode = response.StatusCode };
}
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose()
{
Dispose(true);
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
HttpClient.Dispose();
}
}
///
/// Sets the authorization header that should be supplied on every request
///
/// The header.
///
public void SetAuthorizationHeader(string header)
{
if (string.IsNullOrEmpty(header))
{
HttpClient.DefaultRequestHeaders.Remove("Authorization");
}
else
{
HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("MediaBrowser", header);
}
}
}
}