public static void AppendList <T>(this IHeaderDictionary Headers, string name, IList <T> values)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            switch (values.Count)
            {
            case 0:
                Headers.Append(name, StringValues.Empty);
                break;

            case 1:
                Headers.Append(name, new StringValues(values[0].ToString()));
                break;

            default:
                var newValues = new string[values.Count];
                for (var i = 0; i < values.Count; i++)
                {
                    newValues[i] = values[i].ToString();
                }
                Headers.Append(name, new StringValues(newValues));
                break;
            }
        }
Ejemplo n.º 2
0
    public void GlobalSetup()
    {
        _knownSingleValueResponseHeaders = new HttpResponseHeaders();

        _knownSingleValueResponseHeaders.Server      = "Value";
        _knownSingleValueResponseHeaders.Date        = "Value";
        _knownSingleValueResponseHeaders.ContentType = "Value";
        _knownSingleValueResponseHeaders.SetCookie   = "Value";

        _knownMultipleValueResponseHeaders = new HttpResponseHeaders();

        _knownMultipleValueResponseHeaders.Server      = new StringValues(new[] { "One", "Two" });
        _knownMultipleValueResponseHeaders.Date        = new StringValues(new[] { "One", "Two" });
        _knownMultipleValueResponseHeaders.ContentType = new StringValues(new[] { "One", "Two" });
        _knownMultipleValueResponseHeaders.SetCookie   = new StringValues(new[] { "One", "Two" });

        _unknownSingleValueResponseHeaders = new HttpResponseHeaders();
        _unknownSingleValueResponseHeaders.Append("One", "Value");
        _unknownSingleValueResponseHeaders.Append("Two", "Value");
        _unknownSingleValueResponseHeaders.Append("Three", "Value");
        _unknownSingleValueResponseHeaders.Append("Four", "Value");

        _unknownMultipleValueResponseHeaders = new HttpResponseHeaders();
        _unknownMultipleValueResponseHeaders.Append("One", new StringValues(new[] { "One", "Two" }));
        _unknownMultipleValueResponseHeaders.Append("Two", new StringValues(new[] { "One", "Two" }));
        _unknownMultipleValueResponseHeaders.Append("Three", new StringValues(new[] { "One", "Two" }));
        _unknownMultipleValueResponseHeaders.Append("Four", new StringValues(new[] { "One", "Two" }));

        _enumerator = new Http2HeadersEnumerator();
    }
Ejemplo n.º 3
0
        public void GlobalSetup()
        {
            _http2HeadersEnumerator = new Http2HeadersEnumerator();
            _hpackEncoder           = new DynamicHPackEncoder();
            _buffer = new byte[1024 * 1024];

            _knownResponseHeaders = new HttpResponseHeaders();

            _knownResponseHeaders.Server           = "Kestrel";
            _knownResponseHeaders.ContentType      = "application/json";
            _knownResponseHeaders.Date             = "Date!";
            _knownResponseHeaders.ContentLength    = 0;
            _knownResponseHeaders.AcceptRanges     = "Ranges!";
            _knownResponseHeaders.TransferEncoding = "Encoding!";
            _knownResponseHeaders.Via             = "Via!";
            _knownResponseHeaders.Vary            = "Vary!";
            _knownResponseHeaders.WWWAuthenticate = "Authenticate!";
            _knownResponseHeaders.LastModified    = "Modified!";
            _knownResponseHeaders.Expires         = "Expires!";
            _knownResponseHeaders.Age             = "Age!";

            _unknownResponseHeaders = new HttpResponseHeaders();
            for (var i = 0; i < 10; i++)
            {
                _unknownResponseHeaders.Append("Unknown" + i, "Value" + i);
            }
        }
Ejemplo n.º 4
0
        public void Append_MergesAndAppends()
        {
            IHeaderDictionary headers = CreateHeaders(CustomHeaderRawValues);

            headers.Append(CustomHeaderKey, "vA, vB");
            IList <string> values = headers.GetValues(CustomHeaderKey);

            Assert.Equal(new[] { CustomHeaderJoinedValues + ",vA, vB" }, values);
        }
Ejemplo n.º 5
0
        internal void WriteHeaders(
            IHeaderDictionary headers,
            bool includeDescription,
            IReadOnlyList <IMetric> metrics)
        {
            if (metrics.Count == 0)
            {
                return;
            }

            if (_timingAllowOriginValue != null)
            {
                headers.Append(TimingAllowOriginHeaderName, _timingAllowOriginValue);
            }

            var serverTimingValue = BuildServerTimingHeader(metrics, includeDescription);

            headers.Append(ServerTimingHeaderName, serverTimingValue);
        }
Ejemplo n.º 6
0
 private static void CopyResponseHeaders(HttpHeaders source, IHeaderDictionary destination)
 {
     foreach (var header in source)
     {
         var headerName = header.Key;
         if (RequestUtilities.ResponseHeadersToSkip.Contains(headerName))
         {
             continue;
         }
         destination.Append(headerName, header.Value.ToArray());
     }
 }
Ejemplo n.º 7
0
 private void ModifyHttpHeadersForCompressionOnce()
 {
     if (_httpHeadersModifiedForCompressionFlag.Set())
     {
         IHeaderDictionary responseHeaders = _context.Response.Headers;
         _currentCompressor.AppendHttpHeaders((key, value) =>
         {
             responseHeaders.Append(key, new StringValues(value));
         });
         responseHeaders.Remove(HeaderNames.ContentMD5);
         responseHeaders.Remove(HeaderNames.ContentLength);
     }
 }
        private static void CopyResponseHeaders(HttpContext httpContext, HttpHeaders source, IHeaderDictionary destination)
        {
            var isHttp2OrGreater = ProtocolHelper.IsHttp2OrGreater(httpContext.Request.Protocol);

            foreach (var header in source)
            {
                var headerName = header.Key;
                if (RequestUtilities.ShouldSkipResponseHeader(headerName, isHttp2OrGreater))
                {
                    continue;
                }

                destination.Append(headerName, header.Value.ToArray());
            }
        }
Ejemplo n.º 9
0
        private static void RunRemainingResponseTransforms(HttpResponseMessage response, HttpContext context, IHeaderDictionary destination,
                                                           IReadOnlyDictionary <string, ResponseHeaderTransform> transforms, HashSet <string> transformsRun)
        {
            transformsRun ??= EmptyHash;

            // Run any transforms that weren't run yet.
            foreach (var(headerName, transform) in transforms)  // TODO: What about multiple transforms per header? Last wins?
            {
                if (!transformsRun.Contains(headerName))
                {
                    var headerValue = StringValues.Empty;
                    headerValue = transform.Apply(context, response, headerValue);
                    if (!StringValues.IsNullOrEmpty(headerValue))
                    {
                        destination.Append(headerName, headerValue);
                    }
                }
            }
        }
Ejemplo n.º 10
0
        private static void CopyResponseHeaders(HttpResponseMessage response, HttpHeaders source, HttpContext context, IHeaderDictionary destination,
                                                IReadOnlyDictionary <string, ResponseHeaderTransform> transforms, ref HashSet <string> transformsRun)
        {
            foreach (var header in source)
            {
                var headerName = header.Key;
                if (RequestUtilities.ResponseHeadersToSkip.Contains(headerName))
                {
                    continue;
                }

                var headerValue = new StringValues(header.Value.ToArray());

                if (transforms.TryGetValue(headerName, out var transform))
                {
                    (transformsRun ??= new HashSet <string>(StringComparer.OrdinalIgnoreCase)).Add(headerName);
                    headerValue = transform.Apply(context, response, headerValue);
                }
                if (!StringValues.IsNullOrEmpty(headerValue))
                {
                    destination.Append(headerName, headerValue);
                }
            }
        }
Ejemplo n.º 11
0
        public Task Invoke(HttpContext httpContext, Config config)
        {
            IHeaderDictionary headers = httpContext.Response.Headers;

            // Access Control
            headers.Append("Access-Control-Allow-Credentials", "true");
            headers.Append("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
            headers.Append("Access-Control-Allow-Headers", "Authorization, Accept, Origin, Content-Type, X-Requested-With, Connection, Transfer-Encoding");

            // HSTS
            headers.Append("strict-transport-security", "max-age=31536000; includeSubdomains; preload");

            // XSS Protection
            headers.Append("X-XSS-Protection", "1; mode=block");

            // Content Type Options
            headers.Append("X-Content-Type-Options", "nosniff");

            // Referrer Policy
            headers.Append("Referrer-Policy", "no-referrer, strict-origin-when-cross-origin");

            return(_next(httpContext));
        }
Ejemplo n.º 12
0
        public async Task Invoke(HttpContext context)
        {
            bool useMinification = _options.IsMinificationEnabled() && _minificationManagers.Count > 0;
            bool useCompression  = _options.IsCompressionEnabled() && _compressionManager != null;

            if (!useMinification && !useCompression)
            {
                await _next.Invoke(context);

                return;
            }

            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;

            using (var cachedStream = new MemoryStream())
            {
                Stream originalStream = response.Body;
                response.Body = cachedStream;

                try
                {
                    await _next.Invoke(context);
                }
                catch (Exception)
                {
                    response.Body = originalStream;
                    cachedStream.SetLength(0);

                    throw;
                }

                byte[] cachedBytes     = cachedStream.ToArray();
                int    cachedByteCount = cachedBytes.Length;
                bool   isProcessed     = false;

                response.Body = originalStream;
                cachedStream.SetLength(0);

                if (request.Method == "GET" && response.StatusCode == 200 &&
                    _options.IsAllowableResponseSize(cachedByteCount))
                {
                    string   contentType = response.ContentType;
                    string   mediaType   = null;
                    Encoding encoding    = null;

                    if (contentType != null)
                    {
                        MediaTypeHeaderValue mediaTypeHeader;

                        if (MediaTypeHeaderValue.TryParse(contentType, out mediaTypeHeader))
                        {
                            mediaType = mediaTypeHeader.MediaType.ToLowerInvariant();
                            encoding  = mediaTypeHeader.Encoding;
                        }
                    }

                    encoding = encoding ?? Encoding.GetEncoding(0);

                    string      currentUrl  = request.Path.Value;
                    QueryString queryString = request.QueryString;
                    if (queryString.HasValue)
                    {
                        currentUrl += queryString.Value;
                    }

                    string            content          = encoding.GetString(cachedBytes);
                    string            processedContent = content;
                    IHeaderDictionary responseHeaders  = response.Headers;
                    bool isEncodedContent = responseHeaders.IsEncodedContent();
                    Action <string, string> appendHttpHeader = (key, value) =>
                    {
                        responseHeaders.Append(key, new StringValues(value));
                    };

                    if (useMinification)
                    {
                        foreach (IMarkupMinificationManager minificationManager in _minificationManagers)
                        {
                            if (mediaType != null && minificationManager.IsSupportedMediaType(mediaType) &&
                                minificationManager.IsProcessablePage(currentUrl))
                            {
                                if (isEncodedContent)
                                {
                                    throw new InvalidOperationException(
                                              string.Format(
                                                  AspNetCommonStrings.MarkupMinificationIsNotApplicableToEncodedContent,
                                                  responseHeaders["Content-Encoding"]
                                                  )
                                              );
                                }

                                IMarkupMinifier minifier = minificationManager.CreateMinifier();

                                MarkupMinificationResult minificationResult = minifier.Minify(processedContent, currentUrl, encoding, false);
                                if (minificationResult.Errors.Count == 0)
                                {
                                    processedContent = minificationResult.MinifiedContent;
                                    if (_options.IsPoweredByHttpHeadersEnabled())
                                    {
                                        minificationManager.AppendPoweredByHttpHeader(appendHttpHeader);
                                    }

                                    isProcessed = true;
                                }
                            }

                            if (isProcessed)
                            {
                                break;
                            }
                        }
                    }

                    if (useCompression && !isEncodedContent &&
                        _compressionManager.IsSupportedMediaType(mediaType))
                    {
                        byte[] processedBytes = encoding.GetBytes(processedContent);

                        using (var inputStream = new MemoryStream(processedBytes))
                            using (var outputStream = new MemoryStream())
                            {
                                string      acceptEncoding = request.Headers["Accept-Encoding"];
                                ICompressor compressor     = _compressionManager.CreateCompressor(acceptEncoding);

                                using (Stream compressedStream = compressor.Compress(outputStream))
                                {
                                    await inputStream.CopyToAsync(compressedStream);
                                }

                                byte[] compressedBytes     = outputStream.ToArray();
                                int    compressedByteCount = compressedBytes.Length;

                                if (outputStream.CanWrite)
                                {
                                    outputStream.SetLength(0);
                                }
                                inputStream.SetLength(0);

                                responseHeaders["Content-Length"] = compressedByteCount.ToString();
                                compressor.AppendHttpHeaders(appendHttpHeader);
                                await originalStream.WriteAsync(compressedBytes, 0, compressedByteCount);
                            }

                        isProcessed = true;
                    }
                    else
                    {
                        if (isProcessed)
                        {
                            byte[] processedBytes     = encoding.GetBytes(processedContent);
                            int    processedByteCount = processedBytes.Length;

                            responseHeaders["Content-Length"] = processedByteCount.ToString();
                            await originalStream.WriteAsync(processedBytes, 0, processedByteCount);
                        }
                    }
                }

                if (!isProcessed)
                {
                    await originalStream.WriteAsync(cachedBytes, 0, cachedByteCount);
                }
            }
        }
Ejemplo n.º 13
0
 public void Append(string key, string value)
 {
     OriginalHeaders.Append(key, value);
 }
Ejemplo n.º 14
0
 private void SetNoCacheOnHeader(IHeaderDictionary headers, int expirationDays)
 {
     headers.Append("CacheControl", "no-cache, no-store, must-revalidate");
     headers.Append("Expires", expirationDays.ToString());
     headers.Append("Pragma", "no-cache");
 }
Ejemplo n.º 15
0
 private void SetCommonHeaders(IHeaderDictionary headers)
 {
     headers.Append("Cache-Control", "public, max-age=31536000");
 }
Ejemplo n.º 16
0
        public async Task Finish()
        {
            if (_minificationEnabled)
            {
                byte[] cachedBytes     = _cachedStream.ToArray();
                int    cachedByteCount = cachedBytes.Length;

                bool isMinified = false;

                if (cachedByteCount > 0 && _options.IsAllowableResponseSize(cachedByteCount))
                {
                    Encoding encoding = _encoding ?? Encoding.GetEncoding(0);
                    string   content  = encoding.GetString(cachedBytes);

                    IMarkupMinifier          minifier           = _currentMinificationManager.CreateMinifier();
                    MarkupMinificationResult minificationResult = minifier.Minify(content, _currentUrl,
                                                                                  _encoding, _currentMinificationManager.GenerateStatistics);

                    if (minificationResult.Errors.Count == 0)
                    {
                        IHeaderDictionary       responseHeaders  = _context.Response.Headers;
                        Action <string, string> appendHttpHeader = (key, value) =>
                        {
                            responseHeaders.Append(key, new StringValues(value));
                        };

                        if (_options.IsPoweredByHttpHeadersEnabled())
                        {
                            _currentMinificationManager.AppendPoweredByHttpHeader(appendHttpHeader);
                        }
                        responseHeaders.Remove(HeaderNames.ContentMD5);

                        string processedContent   = minificationResult.MinifiedContent;
                        byte[] processedBytes     = encoding.GetBytes(processedContent);
                        int    processedByteCount = processedBytes.Length;

                        if (_compressionEnabled)
                        {
                            _currentCompressor.AppendHttpHeaders(appendHttpHeader);
                            responseHeaders.Remove(HeaderNames.ContentLength);
                            await _compressionStream.WriteAsync(processedBytes, 0, processedByteCount);
                        }
                        else
                        {
                            responseHeaders[HeaderNames.ContentLength] = processedByteCount.ToString();
                            await _originalStream.WriteAsync(processedBytes, 0, processedByteCount);
                        }

                        isMinified = true;
                    }

                    if (!isMinified)
                    {
                        Stream outputStream = _compressionEnabled ? _compressionStream : _originalStream;

                        _cachedStream.Seek(0, SeekOrigin.Begin);
                        await _cachedStream.CopyToAsync(outputStream);
                    }
                }

                _cachedStream.Clear();
            }
        }
Ejemplo n.º 17
0
        private async Task Cache(HttpContext context)
        {
            //bool useMinification = _options.EnableMinification && _minificationManagers.Count > 0;
            //bool useCompression = _options.EnableCompression && _compressionManager != null;
            var useMinification = _options.EnableMinification;
            var useCompression  = _options.EnableCompression;
            var cacheSetting    = _options.Setting;
            var currentUrl      = context.Request.Path.Value;
            var accept          = $"{context.Request.Headers["Accept"]}";
            var isHtml          = context.Request.Method == "GET" && !string.IsNullOrEmpty(accept) && accept.Contains("text/html") && context.Request.Headers["X-Requested-With"] != "XMLHttpRequest";

            #region  做缓存处理
            if (!isHtml || (!useMinification && !useCompression) || !_options.EnableCache || !cacheSetting.IgnorePages.Contains(currentUrl))
            {
                await _next.Invoke(context);

                return;
            }
            #endregion

            var cachePage = cacheSetting.CachePages.FirstOrDefault(a => a.Url == currentUrl);
            if (cachePage == null)
            {
                cachePage = new CachePage()
                {
                    Url = currentUrl
                }
            }
            ;
            if (cachePage.CacheTime == 0)
            {
                cachePage.CacheTime = cacheSetting.CacheTime;
            }
            var cacheKey = GetKey(context.Request, cachePage.VaryByParams);

            #region 判断缓存是否存在
            var cacheContent = _cacheService.Get <CacheContent>(cacheKey);
            if (cacheContent != null)
            {
                context.Response.Headers.Add("C-Cache", "Hit");
                if (cacheContent.Headers != null && cacheContent.Headers.Count > 0)
                {
                    foreach (var ch in cacheContent.Headers)
                    {
                        context.Response.Headers.Add(ch.Key, ch.Value);
                    }
                }
                await context.Response.Body.WriteAsync(cacheContent.Content, 0, cacheContent.Content.Length);

                return;
            }
            #endregion

            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;

            using (var cachedStream = new MemoryStream())
            {
                Stream originalStream = response.Body;
                response.Body = cachedStream;

                try
                {
                    await _next.Invoke(context);
                }
                catch (Exception)
                {
                    response.Body = originalStream;
                    cachedStream.Clear();
                    throw;
                }

                byte[] cachedBytes     = cachedStream.ToArray();
                int    cachedByteCount = cachedBytes.Length;
                bool   isProcessed     = false;

                response.Body = originalStream;
                cachedStream.Clear();

                if (cachedByteCount == 0)
                {
                    return;
                }

                if (response.StatusCode == 200)
                {
                    string   httpMethod  = request.Method;
                    string   contentType = response.ContentType;
                    string   mediaType   = null;
                    Encoding encoding    = null;
                    if (contentType != null)
                    {
                        MediaTypeHeaderValue mediaTypeHeader;

                        if (MediaTypeHeaderValue.TryParse(contentType, out mediaTypeHeader))
                        {
                            mediaType = mediaTypeHeader.MediaType.Value;
                            encoding  = mediaTypeHeader.Encoding;
                        }
                    }
                    encoding = encoding ?? Encoding.GetEncoding(0);

                    string            content          = encoding.GetString(cachedBytes);
                    string            processedContent = content;
                    IHeaderDictionary responseHeaders  = response.Headers;
                    bool isEncodedContent = responseHeaders.IsEncodedContent();
                    Action <string, string> appendHttpHeader = (key, value) =>
                    {
                        responseHeaders.Append(key, new StringValues(value));
                    };

                    #region Html压缩
                    if (useMinification && _options.IsAllowableResponseSize(cachedByteCount))
                    {
                        var htmlMinifier = new HtmlMinifier();
                        var result       = htmlMinifier.Minify(processedContent);
                        if (result.Errors.Count == 0)
                        {
                            processedContent = result.MinifiedContent;
                            isProcessed      = true;
                        }
                        //foreach (IMarkupMinificationManager minificationManager in _minificationManagers)
                        //{
                        //    if (minificationManager.IsSupportedHttpMethod(httpMethod)
                        //        && mediaType != null && minificationManager.IsSupportedMediaType(mediaType)
                        //        && minificationManager.IsProcessablePage(currentUrl))
                        //    {
                        //        if (isEncodedContent)
                        //        {
                        //            throw new InvalidOperationException(
                        //                string.Format(
                        //                    AspNetCommonStrings.MarkupMinificationIsNotApplicableToEncodedContent,
                        //                    responseHeaders["Content-Encoding"]
                        //                )
                        //            );
                        //        }

                        //        IMarkupMinifier minifier = minificationManager.CreateMinifier();

                        //        MarkupMinificationResult minificationResult = minifier.Minify(processedContent,
                        //            currentUrl, encoding, minificationManager.GenerateStatistics);
                        //        if (minificationResult.Errors.Count == 0)
                        //        {
                        //            processedContent = minificationResult.MinifiedContent;
                        //            isProcessed = true;
                        //        }
                        //    }

                        //    if (isProcessed)
                        //    {
                        //        break;
                        //    }
                        //}
                    }
                    #endregion

                    byte[] processedBytes;
                    if (isProcessed)
                    {
                        processedBytes = encoding.GetBytes(processedContent);
                    }
                    else
                    {
                        processedBytes = cachedBytes;
                    }
                    #region GZip压缩
                    if (useCompression && !isEncodedContent)
                    {
                        string   acceptEncoding = request.Headers["Accept-Encoding"];
                        string[] encodingTokens = acceptEncoding
                                                  .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                                  .Select(e => e.Trim().ToLowerInvariant())
                                                  .ToArray();
                        ICompressor compressor = null;
                        foreach (var et in encodingTokens)
                        {
                            if (et == EncodingTokenConstants.Deflate)
                            {
                                compressor = new DeflateCompressor(new DeflateCompressionSettings()
                                {
                                    Level = System.IO.Compression.CompressionLevel.Fastest
                                });
                                break;
                            }
                            else if (et == EncodingTokenConstants.GZip)
                            {
                                compressor = new GZipCompressor(new GZipCompressionSettings()
                                {
                                    Level = System.IO.Compression.CompressionLevel.Fastest
                                });
                            }
                        }
                        if (compressor != null)
                        {
                            using (var inputStream = new MemoryStream(processedBytes))
                                using (var outputStream = new MemoryStream())
                                {
                                    using (Stream compressedStream = compressor.Compress(outputStream))
                                    {
                                        await inputStream.CopyToAsync(compressedStream);
                                    }
                                    byte[] compressedBytes = outputStream.ToArray();
                                    processedBytes = compressedBytes;
                                    outputStream.Clear();
                                    inputStream.Clear();
                                    responseHeaders["Content-Length"] = compressedBytes.Length.ToString();
                                    compressor.AppendHttpHeaders(appendHttpHeader);
                                    await originalStream.WriteAsync(compressedBytes, 0, compressedBytes.Length);
                                }
                        }
                        //using (var inputStream = new MemoryStream(processedBytes))
                        //using (var outputStream = new MemoryStream())
                        //{
                        //    string acceptEncoding = request.Headers["Accept-Encoding"];
                        //    ICompressor compressor = _compressionManager.CreateCompressor(acceptEncoding);

                        //    using (Stream compressedStream = compressor.Compress(outputStream))
                        //    {
                        //        await inputStream.CopyToAsync(compressedStream);
                        //    }

                        //    byte[] compressedBytes = outputStream.ToArray();
                        //    processedBytes = compressedBytes;
                        //    int compressedByteCount = compressedBytes.Length;

                        //    outputStream.Clear();
                        //    inputStream.Clear();

                        //    responseHeaders["Content-Length"] = compressedByteCount.ToString();
                        //    compressor.AppendHttpHeaders(appendHttpHeader);
                        //    await originalStream.WriteAsync(compressedBytes, 0, compressedByteCount);
                        //}
                        isProcessed = true;
                    }
                    #endregion
                    else
                    {
                        if (isProcessed)
                        {
                            int processedByteCount = processedBytes.Length;

                            responseHeaders["Content-Length"] = processedByteCount.ToString();
                            await originalStream.WriteAsync(processedBytes, 0, processedByteCount);
                        }
                    }

                    #region 保存到缓存中
                    cacheContent = new CacheContent()
                    {
                        Content     = processedBytes,
                        ContentType = contentType,
                        Headers     = new Dictionary <string, string>()
                    };
                    foreach (var rh in responseHeaders)
                    {
                        cacheContent.Headers.Add(rh.Key, rh.Value);
                    }
                    await _cacheService.SetAsync(cacheKey, cacheContent, TimeSpan.FromSeconds(cachePage.CacheTime));

                    context.Response.Headers.Add("C-Cache", "Cached");
                    //Task.Factory.StartNew(obj =>
                    //{
                    //    var cc = (CacheContent)obj;

                    //}, cacheContent);
                    #endregion
                }
                if (!isProcessed)
                {
                    await originalStream.WriteAsync(cachedBytes, 0, cachedByteCount);
                }
            }
        }
        protected async Task InternalFinishAsync()
        {
            if (_minificationEnabled)
            {
                bool isMinified      = false;
                int  cachedByteCount = (int)_cachedStream.Length;
                IHeaderDictionary       responseHeaders  = _context.Response.Headers;
                Action <string, string> appendHttpHeader = (key, value) =>
                {
                    responseHeaders.Append(key, new StringValues(value));
                };

                if (cachedByteCount > 0 && _options.IsAllowableResponseSize(cachedByteCount))
                {
                    Encoding encoding = _encoding ?? _options.DefaultEncoding;
#if NETSTANDARD1_3
                    byte[] cachedBytes = _cachedStream.ToArray();
                    string content     = encoding.GetString(cachedBytes);
#else
                    byte[] cachedBytes = _cachedStream.GetBuffer();
                    string content     = encoding.GetString(cachedBytes, 0, cachedByteCount);
#endif

                    IMarkupMinifier          minifier           = _currentMinificationManager.CreateMinifier();
                    MarkupMinificationResult minificationResult = minifier.Minify(content, _currentUrl,
                                                                                  _encoding, _currentMinificationManager.GenerateStatistics);

                    if (minificationResult.Errors.Count == 0)
                    {
                        if (_options.IsPoweredByHttpHeadersEnabled())
                        {
                            _currentMinificationManager.AppendPoweredByHttpHeader(appendHttpHeader);
                        }
                        responseHeaders.Remove(HeaderNames.ContentMD5);

                        string processedContent   = minificationResult.MinifiedContent;
                        var    byteArrayPool      = ArrayPool <byte> .Shared;
                        int    processedByteCount = encoding.GetByteCount(processedContent);
                        byte[] processedBytes     = byteArrayPool.Rent(processedByteCount);

                        try
                        {
                            encoding.GetBytes(processedContent, 0, processedContent.Length, processedBytes, 0);

                            if (_compressionEnabled)
                            {
                                _currentCompressor.AppendHttpHeaders(appendHttpHeader);
                                responseHeaders.Remove(HeaderNames.ContentLength);
                                await _compressionStream.WriteAsync(processedBytes, 0, processedByteCount);
                            }
                            else
                            {
                                responseHeaders[HeaderNames.ContentLength] = processedByteCount.ToString();
                                await _originalStream.WriteAsync(processedBytes, 0, processedByteCount);
                            }
                        }
                        finally
                        {
                            byteArrayPool.Return(processedBytes);
                        }

                        isMinified = true;
                    }
                }

                if (!isMinified)
                {
                    Stream outputStream;

                    if (_compressionEnabled)
                    {
                        outputStream = _compressionStream;
                        _currentCompressor.AppendHttpHeaders(appendHttpHeader);
                    }
                    else
                    {
                        outputStream = _originalStream;
                    }

                    _cachedStream.Seek(0, SeekOrigin.Begin);
                    await _cachedStream.CopyToAsync(outputStream);
                }

                _cachedStream.Clear();
            }
        }