@ -1,4 +1,5 @@
using MediaBrowser.Common.Configuration ;
using MediaBrowser.Common.Extensions ;
using MediaBrowser.Common.IO ;
using MediaBrowser.Common.Net ;
using MediaBrowser.Model.Logging ;
@ -156,6 +157,20 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
}
}
/// <summary>
/// The _semaphoreLocks
/// </summary>
private readonly ConcurrentDictionary < string , SemaphoreSlim > _semaphoreLocks = new ConcurrentDictionary < string , SemaphoreSlim > ( StringComparer . OrdinalIgnoreCase ) ;
/// <summary>
/// Gets the lock.
/// </summary>
/// <param name="url">The filename.</param>
/// <returns>System.Object.</returns>
private SemaphoreSlim GetLock ( string url )
{
return _semaphoreLocks . GetOrAdd ( url , key = > new SemaphoreSlim ( 1 , 1 ) ) ;
}
/// <summary>
/// Gets the response internal.
/// </summary>
@ -215,6 +230,107 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// <exception cref="HttpException">
/// </exception>
public async Task < HttpResponseInfo > SendAsync ( HttpRequestOptions options , string httpMethod )
{
if ( ! options . EnableUnconditionalCache )
{
return await SendAsyncInternal ( options , httpMethod ) . ConfigureAwait ( false ) ;
}
var url = options . Url ;
var urlHash = url . ToLower ( ) . GetMD5 ( ) . ToString ( "N" ) ;
var semaphore = GetLock ( url ) ;
var responseCachePath = Path . Combine ( _appPaths . CachePath , "httpclient" , urlHash ) ;
var response = await GetCachedResponse ( responseCachePath , options . CacheLength , url ) . ConfigureAwait ( false ) ;
if ( response ! = null )
{
return response ;
}
await semaphore . WaitAsync ( options . CancellationToken ) . ConfigureAwait ( false ) ;
try
{
response = await GetCachedResponse ( responseCachePath , options . CacheLength , url ) . ConfigureAwait ( false ) ;
if ( response ! = null )
{
return response ;
}
response = await SendAsyncInternal ( options , httpMethod ) . ConfigureAwait ( false ) ;
if ( response . StatusCode = = HttpStatusCode . OK )
{
await CacheResponse ( response , responseCachePath ) . ConfigureAwait ( false ) ;
}
return response ;
}
finally
{
semaphore . Release ( ) ;
}
}
private async Task < HttpResponseInfo > GetCachedResponse ( string responseCachePath , TimeSpan cacheLength , string url )
{
try
{
if ( _fileSystem . GetLastWriteTimeUtc ( responseCachePath ) . Add ( cacheLength ) > DateTime . UtcNow )
{
using ( var stream = _fileSystem . GetFileStream ( responseCachePath , FileMode . Open , FileAccess . Read , FileShare . Read , true ) )
{
var memoryStream = new MemoryStream ( ) ;
await stream . CopyToAsync ( memoryStream ) . ConfigureAwait ( false ) ;
memoryStream . Position = 0 ;
return new HttpResponseInfo
{
ResponseUrl = url ,
Content = memoryStream ,
StatusCode = HttpStatusCode . OK ,
Headers = new NameValueCollection ( ) ,
ContentLength = memoryStream . Length
} ;
}
}
}
catch ( FileNotFoundException )
{
}
catch ( DirectoryNotFoundException )
{
}
return null ;
}
private async Task CacheResponse ( HttpResponseInfo response , string responseCachePath )
{
Directory . CreateDirectory ( Path . GetDirectoryName ( responseCachePath ) ) ;
using ( var responseStream = response . Content )
{
using ( var fileStream = _fileSystem . GetFileStream ( responseCachePath , FileMode . Create , FileAccess . Write , FileShare . Read , true ) )
{
var memoryStream = new MemoryStream ( ) ;
await responseStream . CopyToAsync ( memoryStream ) . ConfigureAwait ( false ) ;
memoryStream . Position = 0 ;
await memoryStream . CopyToAsync ( fileStream ) . ConfigureAwait ( false ) ;
memoryStream . Position = 0 ;
response . Content = memoryStream ;
}
}
}
private async Task < HttpResponseInfo > SendAsyncInternal ( HttpRequestOptions options , string httpMethod )
{
ValidateParams ( options ) ;
@ -236,11 +352,11 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
! string . IsNullOrEmpty ( options . RequestContent ) | |
string . Equals ( httpMethod , "post" , StringComparison . OrdinalIgnoreCase ) )
{
var bytes = options . RequestContentBytes ? ?
var bytes = options . RequestContentBytes ? ?
Encoding . UTF8 . GetBytes ( options . RequestContent ? ? string . Empty ) ;
httpWebRequest . ContentType = options . RequestContentType ? ? "application/x-www-form-urlencoded" ;
httpWebRequest . ContentLength = bytes . Length ;
httpWebRequest . GetRequestStream ( ) . Write ( bytes , 0 , bytes . Length ) ;
}