예제 #1
0
        /// <summary>
        /// Gets the HTTP result.
        /// </summary>
        private IHasHeaders GetHttpResult(IRequest requestContext, object content, string contentType, bool addCachePrevention, 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)
                    {
                        var compressionType = requestContext == null ? null : GetCompressionType(requestContext);

                        if (string.IsNullOrEmpty(compressionType))
                        {
                            result = new StreamWriter(Encoding.UTF8.GetBytes(text), contentType, _logger);
                        }
                        else
                        {
                            var isHeadRequest = string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase);

                            result = GetCompressedResult(Encoding.UTF8.GetBytes(text), compressionType, responseHeaders, isHeadRequest, contentType);
                        }
                    }
                    else
                    {
                        result = new HttpResult(content, contentType, HttpStatusCode.OK);
                    }
                }
            }
            if (responseHeaders == null)
            {
                responseHeaders = new Dictionary <string, string>();
            }

            string expires;

            if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out expires))
            {
                responseHeaders["Expires"] = "-1";
            }

            AddResponseHeaders(result, responseHeaders);

            return(result);
        }
예제 #2
0
        /// <summary>
        /// Pres the process optimized result.
        /// </summary>
        private object GetCachedResult(IRequest requestContext, IDictionary <string, string> responseHeaders, StaticResultOptions options)
        {
            bool noCache = (requestContext.Headers[HeaderNames.CacheControl].ToString()).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;

            AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified);

            if (!noCache)
            {
                if (!DateTime.TryParseExact(requestContext.Headers[HeaderNames.IfModifiedSince], HttpDateFormat, _enUSculture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var ifModifiedSinceHeader))
                {
                    _logger.LogDebug("Failed to parse If-Modified-Since header date: {0}", requestContext.Headers[HeaderNames.IfModifiedSince]);
                    return(null);
                }

                if (IsNotModified(ifModifiedSinceHeader, options.CacheDuration, options.DateLastModified))
                {
                    AddAgeHeader(responseHeaders, options.DateLastModified);

                    var result = new HttpResult(Array.Empty <byte>(), options.ContentType ?? "text/html", HttpStatusCode.NotModified);

                    AddResponseHeaders(result, responseHeaders);

                    return(result);
                }
            }

            return(null);
        }
예제 #3
0
        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);
        }
예제 #4
0
        /// <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)
        {
            var compressionType = GetCompressionType(request);

            if (compressionType == null)
            {
                var contentType = request.ResponseContentType;

                switch (GetRealContentType(contentType))
                {
                case "application/xml":
                case "text/xml":
                case "text/xml; charset=utf-8":     //"text/xml; charset=utf-8" also matches xml
                    return(SerializeToXmlString(dto));

                case "application/json":
                case "text/json":
                    return(_jsonSerializer.SerializeToString(dto));
                }
            }

            // Do not use the memoryStreamFactory here, they don't place nice with compression
            using (var ms = new MemoryStream())
            {
                ContentTypes.Instance.SerializeToStream(request, dto, ms);
                ms.Position = 0;

                var responseHeaders = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

                return(GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result);
            }
        }
예제 #5
0
        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);
        }
예제 #6
0
        /// <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));
        }
예제 #7
0
        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));
        }
예제 #8
0
 public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request)
 {
     _logger        = logger;
     this._response = response;
     Items          = new Dictionary <string, object>();
     Request        = request;
 }
예제 #9
0
        /// <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)
        {
            var contentType = request.ResponseContentType;

            switch (GetRealContentType(contentType))
            {
            case "application/xml":
            case "text/xml":
            case "text/xml; charset=utf-8":     //"text/xml; charset=utf-8" also matches xml
                return(SerializeToXmlString(dto));

            case "application/json":
            case "text/json":
                return(_jsonSerializer.SerializeToString(dto));

            default:
            {
                var ms       = new MemoryStream();
                var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);

                writerFn(dto, ms);

                ms.Position = 0;

                if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase))
                {
                    return(GetHttpResult(new byte[] { }, contentType, true));
                }

                return(GetHttpResult(ms, contentType, true));
            }
            }
        }
예제 #10
0
        /// <summary>
        /// Pres the process optimized result.
        /// </summary>
        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);

            var noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;

            if (!noCache)
            {
                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);
        }
예제 #11
0
        private object ToOptimizedResultInternal <T>(IRequest request, T dto, IDictionary <string, string> responseHeaders = null)
        {
            var contentType = request.ResponseContentType;

            switch (GetRealContentType(contentType))
            {
            case "application/xml":
            case "text/xml":
            case "text/xml; charset=utf-8":     //"text/xml; charset=utf-8" also matches xml
                return(GetHttpResult(request, SerializeToXmlString(dto), contentType, false, responseHeaders));

            case "application/json":
            case "text/json":
                return(GetHttpResult(request, _jsonSerializer.SerializeToString(dto), contentType, false, responseHeaders));

            default:
                break;
            }

            var isHeadRequest = string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase);

            var ms       = new MemoryStream();
            var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);

            writerFn(dto, ms);

            ms.Position = 0;

            if (isHeadRequest)
            {
                return(GetHttpResult(request, new byte[] { }, contentType, true, responseHeaders));
            }

            return(GetHttpResult(request, ms, contentType, true, responseHeaders));
        }
예제 #12
0
        /// <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.Headers.Get("If-Modified-Since");

            if (!string.IsNullOrEmpty(ifModifiedSinceHeader) &&
                DateTime.TryParse(ifModifiedSinceHeader, out DateTime ifModifiedSince) &&
                IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified))
            {
                return(true);
            }

            var ifNoneMatchHeader = requestContext.Headers.Get("If-None-Match");

            bool hasCacheKey = !cacheKey.Equals(Guid.Empty);

            // Validate If-None-Match
            if ((hasCacheKey && !string.IsNullOrEmpty(ifNoneMatchHeader)))
            {
                ifNoneMatchHeader = (ifNoneMatchHeader ?? string.Empty).Trim('\"');

                if (Guid.TryParse(ifNoneMatchHeader, out Guid ifNoneMatch) &&
                    cacheKey.Equals(ifNoneMatch))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #13
0
        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.Headers.Get("Range");

                if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
                {
                    return(new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
                    {
                        OnComplete = options.OnComplete,
                        OnError = options.OnError,
                        FileShare = options.FileShare
                    });
                }

                if (!string.IsNullOrEmpty(rangeHeader))
                {
                    var stream = await factoryFn().ConfigureAwait(false);

                    return(new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
                    {
                        OnComplete = options.OnComplete
                    });
                }
                else
                {
                    var stream = await factoryFn().ConfigureAwait(false);

                    responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);

                    if (isHeadRequest)
                    {
                        stream.Dispose();

                        return(GetHttpResult(new byte[] { }, contentType, true));
                    }

                    return(new StreamWriter(stream, contentType, _logger)
                    {
                        OnComplete = options.OnComplete,
                        OnError = options.OnError
                    });
                }
            }

            using (var stream = await factoryFn().ConfigureAwait(false))
            {
                return(await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false));
            }
        }
예제 #14
0
        /// <summary>
        /// Gets the optimized result.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public object GetResult <T>(IRequest requestContext, T result, IDictionary <string, string> responseHeaders = null)
            where T : class
        {
            if (result == null)
            {
                throw new ArgumentNullException(nameof(result));
            }

            if (responseHeaders == null)
            {
                responseHeaders = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            }

            responseHeaders[HeaderNames.Expires] = "0";

            return(ToOptimizedResultInternal(requestContext, result, responseHeaders));
        }
예제 #15
0
        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));

            options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            if (!options.ResponseHeaders.ContainsKey("Content-Disposition"))
            {
                // Quotes are valid in linux. They'll possibly cause issues here
                var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty);
                if (!string.IsNullOrWhiteSpace(filename))
                {
                    options.ResponseHeaders["Content-Disposition"] = "inline; filename=\"" + filename + "\"";
                }
            }

            return(GetStaticResult(requestContext, options));
        }
예제 #16
0
        /// <summary>
        /// Gets the HTTP result.
        /// </summary>
        private IHasHeaders GetHttpResult(IRequest requestContext, byte[] content, string contentType, bool addCachePrevention, IDictionary <string, string> responseHeaders = null)
        {
            string compressionType = null;
            bool   isHeadRequest   = false;

            if (requestContext != null)
            {
                compressionType = GetCompressionType(requestContext, content, contentType);
                isHeadRequest   = string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase);
            }

            IHasHeaders result;

            if (string.IsNullOrEmpty(compressionType))
            {
                var contentLength = content.Length;

                if (isHeadRequest)
                {
                    content = Array.Empty <byte>();
                }

                result = new StreamWriter(content, contentType, contentLength, _logger);
            }
            else
            {
                result = GetCompressedResult(content, compressionType, responseHeaders, isHeadRequest, contentType);
            }

            if (responseHeaders == null)
            {
                responseHeaders = new Dictionary <string, string>();
            }

            string expires;

            if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out expires))
            {
                responseHeaders["Expires"] = "-1";
            }

            AddResponseHeaders(result, responseHeaders);

            return(result);
        }
예제 #17
0
        /// <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)
        {
            var ifNoneMatchHeader = requestContext.Headers.Get("If-None-Match");

            bool hasCacheKey = !cacheKey.Equals(Guid.Empty);

            // Validate If-None-Match
            if (hasCacheKey && !string.IsNullOrEmpty(ifNoneMatchHeader))
            {
                if (Guid.TryParse(ifNoneMatchHeader, out var ifNoneMatch) &&
                    cacheKey.Equals(ifNoneMatch))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #18
0
        public static string GetCompressionType(IRequest request)
        {
            var acceptEncoding = request.Headers["Accept-Encoding"];

            if (!string.IsNullOrWhiteSpace(acceptEncoding))
            {
                if (acceptEncoding.Contains("deflate"))
                {
                    return("deflate");
                }

                if (acceptEncoding.Contains("gzip"))
                {
                    return("gzip");
                }
            }

            return(null);
        }
예제 #19
0
        /// <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);
        }
예제 #20
0
        private IHasHeaders GetCompressedResult(IRequest requestContext, byte[] content,
                                                string requestedCompressionType,
                                                IDictionary <string, string> responseHeaders,
                                                bool isHeadRequest,
                                                string contentType)
        {
            if (responseHeaders == null)
            {
                responseHeaders = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            }

            try
            {
                content = Compress(content, requestedCompressionType);
                responseHeaders["Content-Encoding"] = requestedCompressionType;

                //var url = requestContext == null ? string.Empty : requestContext.RawUrl;
                //_logger.Debug("Compressed to {0} {1}!", requestedCompressionType, url);
            }
            catch (Exception ex)
            {
                //_logger.Error("Error compressing: " + ex.Message);
            }

            responseHeaders["Vary"] = "Accept-Encoding";

            var contentLength = content.Length;

            if (isHeadRequest)
            {
                var result = new StreamWriter(Array.Empty <byte>(), contentType, contentLength, _logger);
                AddResponseHeaders(result, responseHeaders);
                return(result);
            }
            else
            {
                var result = new StreamWriter(content, contentType, contentLength, _logger);
                AddResponseHeaders(result, responseHeaders);
                return(result);
            }
        }
예제 #21
0
        /// <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);
            }

            return(GetHttpResult(result, contentType, false, responseHeaders));
        }
예제 #22
0
        /// <summary>
        /// Gets the HTTP result.
        /// </summary>
        private IHasHeaders GetHttpResult(IRequest requestContext, string content, string contentType, bool addCachePrevention, IDictionary <string, string> responseHeaders = null)
        {
            IHasHeaders result;

            var bytes = Encoding.UTF8.GetBytes(content);

            var compressionType = requestContext == null ? null : GetCompressionType(requestContext, bytes, contentType);

            var isHeadRequest = requestContext == null ? false : string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase);

            if (string.IsNullOrEmpty(compressionType))
            {
                var contentLength = bytes.Length;

                if (isHeadRequest)
                {
                    bytes = Array.Empty <byte>();
                }

                result = new StreamWriter(bytes, contentType, contentLength);
            }
            else
            {
                result = GetCompressedResult(bytes, compressionType, responseHeaders, isHeadRequest, contentType);
            }

            if (responseHeaders == null)
            {
                responseHeaders = new Dictionary <string, string>();
            }

            if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out string _))
            {
                responseHeaders[HeaderNames.Expires] = "0";
            }

            AddResponseHeaders(result, responseHeaders);

            return(result);
        }
예제 #23
0
        private static string GetCompressionType(IRequest request)
        {
            var acceptEncoding = request.Headers[HeaderNames.AcceptEncoding].ToString();

            if (string.IsNullOrEmpty(acceptEncoding))
            {
                //if (_brotliCompressor != null && acceptEncoding.IndexOf("br", StringComparison.OrdinalIgnoreCase) != -1)
                //    return "br";

                if (acceptEncoding.IndexOf("deflate", StringComparison.OrdinalIgnoreCase) != -1)
                {
                    return("deflate");
                }

                if (acceptEncoding.IndexOf("gzip", StringComparison.OrdinalIgnoreCase) != -1)
                {
                    return("gzip");
                }
            }

            return(null);
        }
예제 #24
0
        /// <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.Headers.Get("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);
        }
예제 #25
0
        /// <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.Headers.Get("If-Modified-Since");

            if (!string.IsNullOrEmpty(ifModifiedSinceHeader))
            {
                DateTime ifModifiedSince;

                if (DateTime.TryParse(ifModifiedSinceHeader, out ifModifiedSince))
                {
                    if (IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified))
                    {
                        return(true);
                    }
                }
            }

            var ifNoneMatchHeader = requestContext.Headers.Get("If-None-Match");

            // Validate If-None-Match
            if ((cacheKey.HasValue || !string.IsNullOrEmpty(ifNoneMatchHeader)))
            {
                Guid ifNoneMatch;

                ifNoneMatchHeader = (ifNoneMatchHeader ?? string.Empty).Trim('\"');

                if (Guid.TryParse(ifNoneMatchHeader, out ifNoneMatch))
                {
                    if (cacheKey.HasValue && cacheKey.Value == ifNoneMatch)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }