diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs | 835 |
1 files changed, 0 insertions, 835 deletions
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs deleted file mode 100644 index b013a0952..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ /dev/null @@ -1,835 +0,0 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Net; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using Emby.Server.Implementations.HttpServer; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Services; -using ServiceStack; -using ServiceStack.Host; -using IRequest = MediaBrowser.Model.Services.IRequest; -using MimeTypes = MediaBrowser.Model.Net.MimeTypes; -using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class HttpResultFactory - /// </summary> - public class HttpResultFactory : IHttpResultFactory - { - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - private readonly IFileSystem _fileSystem; - private readonly IJsonSerializer _jsonSerializer; - private readonly IXmlSerializer _xmlSerializer; - - /// <summary> - /// Initializes a new instance of the <see cref="HttpResultFactory" /> class. - /// </summary> - /// <param name="logManager">The log manager.</param> - /// <param name="fileSystem">The file system.</param> - /// <param name="jsonSerializer">The json serializer.</param> - public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer) - { - _fileSystem = fileSystem; - _jsonSerializer = jsonSerializer; - _xmlSerializer = xmlSerializer; - _logger = logManager.GetLogger("HttpResultFactory"); - } - - /// <summary> - /// Gets the result. - /// </summary> - /// <param name="content">The content.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - public object GetResult(object content, string contentType, IDictionary<string, string> responseHeaders = null) - { - return GetHttpResult(content, contentType, responseHeaders); - } - - /// <summary> - /// Gets the HTTP result. - /// </summary> - /// <param name="content">The content.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>IHasHeaders.</returns> - private IHasHeaders GetHttpResult(object content, string contentType, IDictionary<string, string> responseHeaders = null) - { - IHasHeaders 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<string, string>(); - } - - responseHeaders["Expires"] = "-1"; - AddResponseHeaders(result, responseHeaders); - - return result; - } - - /// <summary> - /// Gets the optimized result. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="requestContext">The request context.</param> - /// <param name="result">The result.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">result</exception> - public object GetOptimizedResult<T>(IRequest requestContext, T result, IDictionary<string, string> responseHeaders = null) - where T : class - { - return GetOptimizedResultInternal<T>(requestContext, result, true, responseHeaders); - } - - private object GetOptimizedResultInternal<T>(IRequest requestContext, T result, bool addCachePrevention, IDictionary<string, string> responseHeaders = null) - where T : class - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - var optimizedResult = ToOptimizedResult(requestContext, result); - - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - - if (addCachePrevention) - { - responseHeaders["Expires"] = "-1"; - } - - // Apply headers - var hasHeaders = optimizedResult as IHasHeaders; - - if (hasHeaders != null) - { - AddResponseHeaders(hasHeaders, responseHeaders); - } - - return optimizedResult; - } - - public static string GetCompressionType(IRequest request) - { - var prefs = new RequestPreferences(request); - - if (prefs.AcceptsDeflate) - return "deflate"; - - if (prefs.AcceptsGzip) - return "gzip"; - - return null; - } - - /// <summary> - /// Returns the optimized result for the IRequestContext. - /// Does not use or store results in any cache. - /// </summary> - /// <param name="request"></param> - /// <param name="dto"></param> - /// <returns></returns> - public object ToOptimizedResult<T>(IRequest request, T dto) - { - request.Response.Dto = dto; - - var compressionType = GetCompressionType(request); - if (compressionType == null) - { - var contentType = request.ResponseContentType; - var contentTypeAttr = ContentFormat.GetEndpointAttributes(contentType); - - switch (contentTypeAttr) - { - case RequestAttributes.Xml: - return SerializeToXmlString(dto); - - case RequestAttributes.Json: - return _jsonSerializer.SerializeToString(dto); - } - } - - using (var ms = new MemoryStream()) - { - using (var compressionStream = GetCompressionStream(ms, compressionType)) - { - ContentTypes.Instance.SerializeToStream(request, dto, compressionStream); - compressionStream.Close(); - - var compressedBytes = ms.ToArray(); - - var httpResult = new HttpResult(compressedBytes, request.ResponseContentType) - { - Status = request.Response.StatusCode - }; - - httpResult.Headers["Content-Length"] = compressedBytes.Length.ToString(UsCulture); - httpResult.Headers["Content-Encoding"] = compressionType; - - return httpResult; - } - } - } - - public static string SerializeToXmlString(object from) - { - using (var ms = new MemoryStream()) - { - var xwSettings = new XmlWriterSettings(); - xwSettings.Encoding = new UTF8Encoding(false); - xwSettings.OmitXmlDeclaration = false; - - using (var xw = XmlWriter.Create(ms, xwSettings)) - { - var serializer = new DataContractSerializer(from.GetType()); - serializer.WriteObject(xw, from); - xw.Flush(); - ms.Seek(0, SeekOrigin.Begin); - var reader = new StreamReader(ms); - return reader.ReadToEnd(); - } - } - } - - private static Stream GetCompressionStream(Stream outputStream, string compressionType) - { - if (compressionType == "deflate") - return new DeflateStream(outputStream, CompressionMode.Compress); - if (compressionType == "gzip") - return new GZipStream(outputStream, CompressionMode.Compress); - - throw new NotSupportedException(compressionType); - } - - /// <summary> - /// Gets the optimized result using cache. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="requestContext">The request context.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">cacheKey - /// or - /// factoryFn</exception> - public object GetOptimizedResultUsingCache<T>(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn, IDictionary<string, string> 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<string, string>(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); - } - - /// <summary> - /// To the cached result. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="requestContext">The request context.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">cacheKey</exception> - public object GetCachedResult<T>(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn, string contentType, IDictionary<string, string> 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<string, string>(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 hasHeaders = result as IHasHeaders; - - if (hasHeaders != null) - { - AddResponseHeaders(hasHeaders, responseHeaders); - return hasHeaders; - } - - IHasHeaders 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; - } - - /// <summary> - /// Pres the process optimized result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="cacheKeyString">The cache key string.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="contentType">Type of the content.</param> - /// <returns>System.Object.</returns> - private object GetCachedResult(IRequest requestContext, IDictionary<string, string> 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<object> GetStaticFileResult(IRequest requestContext, - string path, - FileShareMode fileShare = FileShareMode.Read) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - return GetStaticFileResult(requestContext, new StaticFileResultOptions - { - Path = path, - FileShare = fileShare - }); - } - - public Task<object> GetStaticFileResult(IRequest requestContext, - StaticFileResultOptions options) - { - var path = options.Path; - var fileShare = options.FileShare; - - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - if (fileShare != FileShareMode.Read && fileShare != FileShareMode.ReadWrite) - { - throw new ArgumentException("FileShare must be either Read or ReadWrite"); - } - - if (string.IsNullOrWhiteSpace(options.ContentType)) - { - options.ContentType = MimeTypes.GetMimeType(path); - } - - if (!options.DateLastModified.HasValue) - { - options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path); - } - - var cacheKey = path + options.DateLastModified.Value.Ticks; - - options.CacheKey = cacheKey.GetMD5(); - options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare)); - - return GetStaticResult(requestContext, options); - } - - /// <summary> - /// Gets the file stream. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="fileShare">The file share.</param> - /// <returns>Stream.</returns> - private Stream GetFileStream(string path, FileShareMode fileShare) - { - return _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShare); - } - - public Task<object> GetStaticResult(IRequest requestContext, - Guid cacheKey, - DateTime? lastDateModified, - TimeSpan? cacheDuration, - string contentType, - Func<Task<Stream>> factoryFn, - IDictionary<string, string> responseHeaders = null, - bool isHeadRequest = false) - { - return GetStaticResult(requestContext, new StaticResultOptions - { - CacheDuration = cacheDuration, - CacheKey = cacheKey, - ContentFactory = factoryFn, - ContentType = contentType, - DateLastModified = lastDateModified, - IsHeadRequest = isHeadRequest, - ResponseHeaders = responseHeaders - }); - } - - public async Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options) - { - var cacheKey = options.CacheKey; - options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - var contentType = options.ContentType; - - if (cacheKey == Guid.Empty) - { - throw new ArgumentNullException("cacheKey"); - } - if (options.ContentFactory == null) - { - throw new ArgumentNullException("factoryFn"); - } - - var key = cacheKey.ToString("N"); - - // See if the result is already cached in the browser - var result = GetCachedResult(requestContext, options.ResponseHeaders, cacheKey, key, options.DateLastModified, options.CacheDuration, contentType); - - if (result != null) - { - return result; - } - - var compress = ShouldCompressResponse(requestContext, contentType); - var hasHeaders = await GetStaticResult(requestContext, options, compress).ConfigureAwait(false); - AddResponseHeaders(hasHeaders, options.ResponseHeaders); - - return hasHeaders; - } - - /// <summary> - /// Shoulds the compress response. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="contentType">Type of the content.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - private bool ShouldCompressResponse(IRequest requestContext, string contentType) - { - // It will take some work to support compression with byte range requests - if (!string.IsNullOrEmpty(requestContext.GetHeader("Range"))) - { - return false; - } - - // Don't compress media - if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Don't compress images - if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - if (contentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(contentType, "application/x-javascript", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - if (string.Equals(contentType, "application/xml", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - return false; - } - - return true; - } - - /// <summary> - /// The us culture - /// </summary> - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - private async Task<IHasHeaders> GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress) - { - var isHeadRequest = options.IsHeadRequest; - var factoryFn = options.ContentFactory; - var contentType = options.ContentType; - var responseHeaders = options.ResponseHeaders; - - var requestedCompressionType = GetCompressionType(requestContext); - - if (!compress || string.IsNullOrEmpty(requestedCompressionType)) - { - var rangeHeader = requestContext.GetHeader("Range"); - - var stream = await factoryFn().ConfigureAwait(false); - - if (!string.IsNullOrEmpty(rangeHeader)) - { - return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger) - { - OnComplete = options.OnComplete - }; - } - - responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture); - - if (isHeadRequest) - { - stream.Dispose(); - - return GetHttpResult(new byte[] { }, contentType); - } - - return new StreamWriter(stream, contentType, _logger) - { - OnComplete = options.OnComplete, - OnError = options.OnError - }; - } - - string content; - - using (var stream = await factoryFn().ConfigureAwait(false)) - { - using (var reader = new StreamReader(stream)) - { - content = await reader.ReadToEndAsync().ConfigureAwait(false); - } - } - - var contents = Compress(content, requestedCompressionType); - - responseHeaders["Content-Length"] = contents.Length.ToString(UsCulture); - responseHeaders["Content-Encoding"] = requestedCompressionType; - - if (isHeadRequest) - { - return GetHttpResult(new byte[] { }, contentType); - } - - return GetHttpResult(contents, contentType, responseHeaders); - } - - public static byte[] Compress(string text, string compressionType) - { - if (compressionType == "deflate") - return Deflate(text); - - if (compressionType == "gzip") - return GZip(text); - - throw new NotSupportedException(compressionType); - } - - public static byte[] Deflate(string text) - { - return Deflate(Encoding.UTF8.GetBytes(text)); - } - - public static byte[] Deflate(byte[] bytes) - { - // In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream - // Which means we must use MemoryStream since you have to use ToArray() on a closed Stream - using (var ms = new MemoryStream()) - using (var zipStream = new DeflateStream(ms, CompressionMode.Compress)) - { - zipStream.Write(bytes, 0, bytes.Length); - zipStream.Close(); - - return ms.ToArray(); - } - } - - public static byte[] GZip(string text) - { - return GZip(Encoding.UTF8.GetBytes(text)); - } - - public static byte[] GZip(byte[] buffer) - { - using (var ms = new MemoryStream()) - using (var zipStream = new GZipStream(ms, CompressionMode.Compress)) - { - zipStream.Write(buffer, 0, buffer.Length); - zipStream.Close(); - - return ms.ToArray(); - } - } - - /// <summary> - /// Adds the caching responseHeaders. - /// </summary> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) - { - // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant - // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching - if (lastDateModified.HasValue && (string.IsNullOrEmpty(cacheKey) || cacheDuration.HasValue)) - { - AddAgeHeader(responseHeaders, lastDateModified); - responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r"); - } - - if (cacheDuration.HasValue) - { - responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds); - } - else if (!string.IsNullOrEmpty(cacheKey)) - { - responseHeaders["Cache-Control"] = "public"; - } - else - { - responseHeaders["Cache-Control"] = "no-cache, no-store, must-revalidate"; - responseHeaders["pragma"] = "no-cache, no-store, must-revalidate"; - } - - AddExpiresHeader(responseHeaders, cacheKey, cacheDuration); - } - - /// <summary> - /// Adds the expires header. - /// </summary> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration) - { - if (cacheDuration.HasValue) - { - responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r"); - } - else if (string.IsNullOrEmpty(cacheKey)) - { - responseHeaders["Expires"] = "-1"; - } - } - - /// <summary> - /// Adds the age header. - /// </summary> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="lastDateModified">The last date modified.</param> - private void AddAgeHeader(IDictionary<string, string> responseHeaders, DateTime? lastDateModified) - { - if (lastDateModified.HasValue) - { - responseHeaders["Age"] = Convert.ToInt64((DateTime.UtcNow - lastDateModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture); - } - } - /// <summary> - /// Determines whether [is not modified] [the specified cache key]. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <returns><c>true</c> if [is not modified] [the specified cache key]; otherwise, <c>false</c>.</returns> - private bool IsNotModified(IRequest requestContext, Guid? cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) - { - var isNotModified = true; - - var ifModifiedSinceHeader = requestContext.GetHeader("If-Modified-Since"); - - if (!string.IsNullOrEmpty(ifModifiedSinceHeader)) - { - DateTime ifModifiedSince; - - if (DateTime.TryParse(ifModifiedSinceHeader, out ifModifiedSince)) - { - isNotModified = IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified); - } - } - - var ifNoneMatchHeader = requestContext.GetHeader("If-None-Match"); - - // Validate If-None-Match - if (isNotModified && (cacheKey.HasValue || !string.IsNullOrEmpty(ifNoneMatchHeader))) - { - Guid ifNoneMatch; - - if (Guid.TryParse(ifNoneMatchHeader ?? string.Empty, out ifNoneMatch)) - { - if (cacheKey.HasValue && cacheKey.Value == ifNoneMatch) - { - return true; - } - } - } - - return false; - } - - /// <summary> - /// Determines whether [is not modified] [the specified if modified since]. - /// </summary> - /// <param name="ifModifiedSince">If modified since.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="dateModified">The date modified.</param> - /// <returns><c>true</c> if [is not modified] [the specified if modified since]; otherwise, <c>false</c>.</returns> - private bool IsNotModified(DateTime ifModifiedSince, TimeSpan? cacheDuration, DateTime? dateModified) - { - if (dateModified.HasValue) - { - var lastModified = NormalizeDateForComparison(dateModified.Value); - ifModifiedSince = NormalizeDateForComparison(ifModifiedSince); - - return lastModified <= ifModifiedSince; - } - - if (cacheDuration.HasValue) - { - var cacheExpirationDate = ifModifiedSince.Add(cacheDuration.Value); - - if (DateTime.UtcNow < cacheExpirationDate) - { - return true; - } - } - - return false; - } - - - /// <summary> - /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that - /// </summary> - /// <param name="date">The date.</param> - /// <returns>DateTime.</returns> - private DateTime NormalizeDateForComparison(DateTime date) - { - return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind); - } - - /// <summary> - /// Adds the response headers. - /// </summary> - /// <param name="hasHeaders">The has options.</param> - /// <param name="responseHeaders">The response headers.</param> - private void AddResponseHeaders(IHasHeaders hasHeaders, IEnumerable<KeyValuePair<string, string>> responseHeaders) - { - foreach (var item in responseHeaders) - { - hasHeaders.Headers[item.Key] = item.Value; - } - } - } -}
\ No newline at end of file |
