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"); } 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); } // TODO: We don't really need the option value var isHeadRequest = options.IsHeadRequest || string.Equals(requestContext.Verb, "HEAD", StringComparison.OrdinalIgnoreCase); var factoryFn = options.ContentFactory; var responseHeaders = options.ResponseHeaders; //var requestedCompressionType = GetCompressionType(requestContext); var rangeHeader = requestContext.Headers.Get("Range"); if (!isHeadRequest && !string.IsNullOrEmpty(options.Path)) { var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem) { OnComplete = options.OnComplete, OnError = options.OnError, FileShare = options.FileShare }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); return(hasHeaders); } if (!string.IsNullOrWhiteSpace(rangeHeader)) { var stream = await factoryFn().ConfigureAwait(false); var hasHeaders = new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger) { OnComplete = options.OnComplete }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); return(hasHeaders); } else { var stream = await factoryFn().ConfigureAwait(false); responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture); if (isHeadRequest) { stream.Dispose(); return(GetHttpResult(requestContext, new byte[] { }, contentType, true, responseHeaders)); } var hasHeaders = new StreamWriter(stream, contentType, _logger) { OnComplete = options.OnComplete, OnError = options.OnError }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); return(hasHeaders); } }
public async Task <object> GetStaticResult(IRequest requestContext, StaticResultOptions options) { options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); var contentType = options.ContentType; if (!StringValues.IsNullOrEmpty(requestContext.Headers[HeaderNames.IfModifiedSince])) { // See if the result is already cached in the browser var result = GetCachedResult(requestContext, options.ResponseHeaders, options); if (result != null) { return(result); } } // TODO: We don't really need the option value var isHeadRequest = options.IsHeadRequest || string.Equals(requestContext.Verb, "HEAD", StringComparison.OrdinalIgnoreCase); var factoryFn = options.ContentFactory; var responseHeaders = options.ResponseHeaders; AddCachingHeaders(responseHeaders, options.CacheDuration, false, options.DateLastModified); AddAgeHeader(responseHeaders, options.DateLastModified); var rangeHeader = requestContext.Headers[HeaderNames.Range]; if (!isHeadRequest && !string.IsNullOrEmpty(options.Path)) { var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem, _streamHelper) { OnComplete = options.OnComplete, OnError = options.OnError, FileShare = options.FileShare }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); return(hasHeaders); } var stream = await factoryFn().ConfigureAwait(false); var totalContentLength = options.ContentLength; if (!totalContentLength.HasValue) { try { totalContentLength = stream.Length; } catch (NotSupportedException) { } } if (!string.IsNullOrWhiteSpace(rangeHeader) && totalContentLength.HasValue) { var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest, _logger) { OnComplete = options.OnComplete }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); return(hasHeaders); } else { if (totalContentLength.HasValue) { responseHeaders["Content-Length"] = totalContentLength.Value.ToString(CultureInfo.InvariantCulture); } if (isHeadRequest) { using (stream) { return(GetHttpResult(requestContext, Array.Empty <byte>(), contentType, true, responseHeaders)); } } var hasHeaders = new StreamWriter(stream, contentType) { OnComplete = options.OnComplete, OnError = options.OnError }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); return(hasHeaders); } }
public async Task <object> GetStaticResult(IRequest requestContext, StaticResultOptions options) { options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); var contentType = options.ContentType; var etag = requestContext.Headers.Get("If-None-Match"); var cacheKey = etag != null ? new Guid(etag.Trim('\"')) : Guid.Empty; if (!cacheKey.Equals(Guid.Empty)) { 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); } } // TODO: We don't really need the option value var isHeadRequest = options.IsHeadRequest || string.Equals(requestContext.Verb, "HEAD", StringComparison.OrdinalIgnoreCase); var factoryFn = options.ContentFactory; var responseHeaders = options.ResponseHeaders; var rangeHeader = requestContext.Headers.Get("Range"); if (!isHeadRequest && !string.IsNullOrEmpty(options.Path)) { var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem) { OnComplete = options.OnComplete, OnError = options.OnError, FileShare = options.FileShare }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); // Generate an ETag based on identifying information - TODO read contents from filesystem instead? var responseId = $"{hasHeaders.ContentType}{options.Path}{hasHeaders.TotalContentLength}"; var hashedId = MD5.Create().ComputeHash(Encoding.Default.GetBytes(responseId)); hasHeaders.Headers["ETag"] = new Guid(hashedId).ToString("N"); return(hasHeaders); } var stream = await factoryFn().ConfigureAwait(false); // Generate an etag based on stream content var streamHash = MD5.Create().ComputeHash(stream); var newEtag = new Guid(streamHash).ToString("N"); // reset position so the response can re-use it -- TODO is this ok? stream.Position = 0; var totalContentLength = options.ContentLength; if (!totalContentLength.HasValue) { try { totalContentLength = stream.Length; } catch (NotSupportedException) { } } if (!string.IsNullOrWhiteSpace(rangeHeader) && totalContentLength.HasValue) { var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest, _logger) { OnComplete = options.OnComplete }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); hasHeaders.Headers["ETag"] = newEtag; return(hasHeaders); } else { if (totalContentLength.HasValue) { responseHeaders["Content-Length"] = totalContentLength.Value.ToString(UsCulture); } if (isHeadRequest) { using (stream) { return(GetHttpResult(requestContext, Array.Empty <byte>(), contentType, true, responseHeaders)); } } var hasHeaders = new StreamWriter(stream, contentType, _logger) { OnComplete = options.OnComplete, OnError = options.OnError }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); hasHeaders.Headers["ETag"] = newEtag; return(hasHeaders); } }