using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using ServiceStack;
using ServiceStack.Web;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using CommonIO;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Server.Implementations.HttpServer
{
///
/// Class HttpResultFactory
///
public class HttpResultFactory : IHttpResultFactory
{
///
/// The _logger
///
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
///
/// Initializes a new instance of the class.
///
/// The log manager.
/// The file system.
/// The json serializer.
public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
{
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
_logger = logManager.GetLogger("HttpResultFactory");
}
///
/// Gets the result.
///
/// The content.
/// Type of the content.
/// The response headers.
/// System.Object.
public object GetResult(object content, string contentType, IDictionary responseHeaders = null)
{
return GetHttpResult(content, contentType, responseHeaders);
}
///
/// Gets the HTTP result.
///
/// The content.
/// Type of the content.
/// The response headers.
/// IHasOptions.
private IHasOptions GetHttpResult(object content, string contentType, IDictionary responseHeaders = null)
{
IHasOptions result;
var stream = content as Stream;
if (stream != null)
{
result = new StreamWriter(stream, contentType, _logger);
}
else
{
var bytes = content as byte[];
if (bytes != null)
{
result = new StreamWriter(bytes, contentType, _logger);
}
else
{
var text = content as string;
if (text != null)
{
result = new StreamWriter(Encoding.UTF8.GetBytes(text), contentType, _logger);
}
else
{
result = new HttpResult(content, contentType);
}
}
}
if (responseHeaders == null)
{
responseHeaders = new Dictionary();
}
responseHeaders["Expires"] = "-1";
AddResponseHeaders(result, responseHeaders);
return result;
}
///
/// Gets the optimized result.
///
///
/// The request context.
/// The result.
/// The response headers.
/// System.Object.
/// result
public object GetOptimizedResult(IRequest requestContext, T result, IDictionary responseHeaders = null)
where T : class
{
return GetOptimizedResultInternal(requestContext, result, true, responseHeaders);
}
private object GetOptimizedResultInternal(IRequest requestContext, T result, bool addCachePrevention, IDictionary responseHeaders = null)
where T : class
{
if (result == null)
{
throw new ArgumentNullException("result");
}
var optimizedResult = requestContext.ToOptimizedResult(result);
if (responseHeaders == null)
{
responseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase);
}
if (addCachePrevention)
{
responseHeaders["Expires"] = "-1";
}
// Apply headers
var hasOptions = optimizedResult as IHasOptions;
if (hasOptions != null)
{
AddResponseHeaders(hasOptions, responseHeaders);
}
return optimizedResult;
}
///
/// Gets the optimized result using cache.
///
///
/// The request context.
/// The cache key.
/// The last date modified.
/// Duration of the cache.
/// The factory fn.
/// The response headers.
/// System.Object.
/// cacheKey
/// or
/// factoryFn
public object GetOptimizedResultUsingCache(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func factoryFn, IDictionary responseHeaders = null)
where T : class
{
if (cacheKey == Guid.Empty)
{
throw new ArgumentNullException("cacheKey");
}
if (factoryFn == null)
{
throw new ArgumentNullException("factoryFn");
}
var key = cacheKey.ToString("N");
if (responseHeaders == null)
{
responseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase);
}
// See if the result is already cached in the browser
var result = GetCachedResult(requestContext, responseHeaders, cacheKey, key, lastDateModified, cacheDuration, null);
if (result != null)
{
return result;
}
return GetOptimizedResultInternal(requestContext, factoryFn(), false, responseHeaders);
}
///
/// To the cached result.
///
///
/// The request context.
/// The cache key.
/// The last date modified.
/// Duration of the cache.
/// The factory fn.
/// Type of the content.
/// The response headers.
/// System.Object.
/// cacheKey
public object GetCachedResult(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType, IDictionary responseHeaders = null)
where T : class
{
if (cacheKey == Guid.Empty)
{
throw new ArgumentNullException("cacheKey");
}
if (factoryFn == null)
{
throw new ArgumentNullException("factoryFn");
}
var key = cacheKey.ToString("N");
if (responseHeaders == null)
{
responseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase);
}
// See if the result is already cached in the browser
var result = GetCachedResult(requestContext, responseHeaders, cacheKey, key, lastDateModified, cacheDuration, contentType);
if (result != null)
{
return result;
}
result = factoryFn();
// Apply caching headers
var hasOptions = result as IHasOptions;
if (hasOptions != null)
{
AddResponseHeaders(hasOptions, responseHeaders);
return hasOptions;
}
IHasOptions httpResult;
var stream = result as Stream;
if (stream != null)
{
httpResult = new StreamWriter(stream, contentType, _logger);
}
else
{
// Otherwise wrap into an HttpResult
httpResult = new HttpResult(result, contentType ?? "text/html", HttpStatusCode.NotModified);
}
AddResponseHeaders(httpResult, responseHeaders);
return httpResult;
}
///
/// Pres the process optimized result.
///
/// The request context.
/// The responseHeaders.
/// The cache key.
/// The cache key string.
/// The last date modified.
/// Duration of the cache.
/// Type of the content.
/// System.Object.
private object GetCachedResult(IRequest requestContext, IDictionary responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType)
{
responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString);
if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
{
AddAgeHeader(responseHeaders, lastDateModified);
AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration);
var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified);
AddResponseHeaders(result, responseHeaders);
return result;
}
AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration);
return null;
}
public Task