public void ContentEncodingNegotiation_Fails(string requestHeaders, bool preferCompression)
        {
            var list       = new QValueList(true, requestHeaders);
            var negotiated = list.TryNegotiateContentEncoding(preferCompression, out var actualCompressionMethod, out var actualCompressionMethodName);

            Assert.AreEqual(false, negotiated);
        }
예제 #2
0
파일: CssResponse.cs 프로젝트: ahem/dotless
        /// <summary>
        ///  deal with the request accept encoding and add the necessary filter to the response
        /// </summary>
        protected void HandleCompression()
        {
            var context = Http.Context;

            /// load encodings from header
            QValueList encodings = new QValueList(context.Request.Headers["Accept-Encoding"]);

            /// get the types we can handle, can be accepted and
            /// in the defined client preference
            QValue preferred = encodings.FindPreferred("gzip", "deflate", "identity");

            /// if none of the preferred values were found, but the
            /// client can accept wildcard encodings, we'll default
            /// to Gzip.
            if (preferred.IsEmpty && encodings.AcceptWildcard && encodings.Find("gzip").IsEmpty)
            {
                preferred = new QValue("gzip");
            }

            // handle the preferred encoding
            switch (preferred.Name.ToLowerInvariant())
            {
                case "gzip":
                    context.Response.AppendHeader("Content-Encoding", "gzip");
                    context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
                    break;
                case "deflate":
                    context.Response.AppendHeader("Content-Encoding", "deflate");
                    context.Response.Filter = new DeflateStream(context.Response.Filter, CompressionMode.Compress);
                    break;
                case "identity":
                default:
                    break;
            }
        }
        public void QValueList_TryNegotiateContentEncoding_WhenPreferCompressionFalse_OnNoCompressionSpecified_YieldsIdentity()
        {
            var list = new QValueList(true, "gzip, deflate");

            list.TryNegotiateContentEncoding(false, out _, out var name);
            Assert.AreEqual(CompressionMethodNames.None, name);
        }
예제 #4
0
        public static void ChooseSuitableCompression(NameValueCollection requestHeaders, HttpResponseBase response)
        {
            if (requestHeaders == null) throw new ArgumentNullException(nameof(requestHeaders));
            if (response == null) throw new ArgumentNullException(nameof(response));


            /// load encodings from header
            QValueList encodings = new QValueList(requestHeaders[ACCEPT_ENCODING_HEADER]);

            /// get the types we can handle, can be accepted and
            /// in the defined client preference
            QValue preferred = encodings.FindPreferred("gzip", "deflate", "identity");

            /// if none of the preferred values were found, but the
            /// client can accept wildcard encodings, we'll default
            /// to Gzip.
            if (preferred.IsEmpty && encodings.AcceptWildcard && encodings.Find("gzip").IsEmpty)
                preferred = new QValue("gzip");

            // handle the preferred encoding
            switch (preferred.Name)
            {
                case "gzip":
                    response.AppendHeader(CONTENT_ENCODING_HEADER, "gzip");
                    response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                    break;
                case "deflate":
                    response.AppendHeader(CONTENT_ENCODING_HEADER, "deflate");
                    response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                    break;
                case "identity":
                default:
                    break;
            }
        }
예제 #5
0
        public static void AddCompressionFilter(HttpRequest request, HttpResponse response)
        {
            // load encodings from header
            QValueList encodings = new QValueList(request.Headers["Accept-Encoding"]);

            // get the types we can handle, can be accepted and
            // in the defined client preference
            QValue preferred = encodings.FindPreferred("gzip", "deflate", "identity");

            // if none of the preferred values were found, but the
            // client can accept wildcard encodings, we'll default
            // to Gzip.
            if (preferred.IsEmpty && encodings.AcceptWildcard && encodings.Find("gzip").IsEmpty)
                preferred = new QValue("gzip");

            // handle the preferred encoding
            switch (preferred.Name)
            {
                case "gzip":
                    response.AppendHeader("Content-Encoding", "gzip");
                    response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                    break;
                case "deflate":
                    response.AppendHeader("Content-Encoding", "deflate");
                    response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                    break;
                case "identity":
                default:
                    break;
            }
        }
        public void ContentEncodingNegotiation_Succeeds(
            string requestHeaders,
            bool preferCompression,
            CompressionMethod expectedCompressionMethod,
            string expectedCompressionMethodName)
        {
            var list       = new QValueList(true, requestHeaders);
            var negotiated = list.TryNegotiateContentEncoding(preferCompression, out var actualCompressionMethod, out var actualCompressionMethodName);

            Assert.AreEqual(true, negotiated);
            Assert.AreEqual(expectedCompressionMethod, actualCompressionMethod);
            Assert.AreEqual(expectedCompressionMethodName, actualCompressionMethodName);
        }
        /// <summary>
        /// <para>Attempts to proactively negotiate a compression method for a response,
        /// based on the contents of a <see cref="QValueList"/>.</para>
        /// </summary>
        /// <param name="this">The <see cref="QValueList"/> on which this method is called.</param>
        /// <param name="preferCompression"><see langword="true"/> if sending compressed data is preferred over
        /// sending non-compressed data; otherwise, <see langword="false"/>.</param>
        /// <param name="compressionMethod">When this method returns, the compression method to use for the response,
        /// if content negotiation is successful. This parameter is passed uninitialized.</param>
        /// <param name="compressionMethodName">When this method returns, the name of the compression method,
        /// if content negotiation is successful. This parameter is passed uninitialized.</param>
        /// <returns><see langword="true"/> if content negotiation is successful;
        /// otherwise, <see langword="false"/>.</returns>
        /// <remarks>
        /// <para>If <paramref name="this"/> is empty, this method always returns <see langword="true"/>,
        /// setting <paramref name="compressionMethod"/> to <see cref="CompressionMethod.None"/>
        /// and <paramref name="compressionMethodName"/> to <see cref="CompressionMethodNames.None"/>.</para>
        /// </remarks>
        public static bool TryNegotiateContentEncoding(
            this QValueList @this,
            bool preferCompression,
            out CompressionMethod compressionMethod,
            out string compressionMethodName)
        {
            if (@this.QValues.Count < 1)
            {
                compressionMethod     = CompressionMethod.None;
                compressionMethodName = CompressionMethodNames.None;
                return(true);
            }

            // https://tools.ietf.org/html/rfc7231#section-5.3.4
            // RFC7231, Section 5.3.4, rule #2:
            // If the representation has no content-coding, then it is
            // acceptable by default unless specifically excluded by the
            // Accept - Encoding field stating either "identity;q=0" or "*;q=0"
            // without a more specific entry for "identity".
            if (!preferCompression && ([email protected](CompressionMethodNames.None, out var weight) || weight > 0))
            {
                compressionMethod     = CompressionMethod.None;
                compressionMethodName = CompressionMethodNames.None;
                return(true);
            }

            var acceptableMethods = preferCompression
                ? new[] { CompressionMethod.Gzip, CompressionMethod.Deflate, CompressionMethod.None }
                : new[] { CompressionMethod.None, CompressionMethod.Gzip, CompressionMethod.Deflate };
            var acceptableMethodNames = preferCompression
                ? new[] { CompressionMethodNames.Gzip, CompressionMethodNames.Deflate, CompressionMethodNames.None }
                : new[] { CompressionMethodNames.None, CompressionMethodNames.Gzip, CompressionMethodNames.Deflate };

            var acceptableMethodIndex = @this.FindPreferredIndex(acceptableMethodNames);

            if (acceptableMethodIndex < 0)
            {
                compressionMethod     = default;
                compressionMethodName = default;
                return(false);
            }

            compressionMethod     = acceptableMethods[acceptableMethodIndex];
            compressionMethodName = acceptableMethodNames[acceptableMethodIndex];
            return(true);
        }
예제 #8
0
        public static void ChooseSuitableCompression(NameValueCollection requestHeaders, HttpResponseBase response)
        {
            if (requestHeaders == null)
            {
                throw new ArgumentNullException(nameof(requestHeaders));
            }
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }


            /// load encodings from header
            QValueList encodings = new QValueList(requestHeaders[ACCEPT_ENCODING_HEADER]);

            /// get the types we can handle, can be accepted and
            /// in the defined client preference
            QValue preferred = encodings.FindPreferred("gzip", "deflate", "identity");

            /// if none of the preferred values were found, but the
            /// client can accept wildcard encodings, we'll default
            /// to Gzip.
            if (preferred.IsEmpty && encodings.AcceptWildcard && encodings.Find("gzip").IsEmpty)
            {
                preferred = new QValue("gzip");
            }

            // handle the preferred encoding
            switch (preferred.Name)
            {
            case "gzip":
                response.AppendHeader(CONTENT_ENCODING_HEADER, "gzip");
                response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                break;

            case "deflate":
                response.AppendHeader(CONTENT_ENCODING_HEADER, "deflate");
                response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                break;

            case "identity":
            default:
                break;
            }
        }
예제 #9
0
        public static void ApplyCompression(HttpRequest Request, HttpResponse Response)
        {
            if (IsCompressEnabled(Request) == false)
            {
                return;
            }

            // load encodings from header
            QValueList encodings = new QValueList(Request.Headers["Accept-Encoding"]);

            // get the types we can handle, can be accepted and
            // in the defined client preference
            QValue preferred = encodings.FindPreferred("gzip", "deflate", "identity");

            // if none of the preferred values were found, but the
            // client can accept wildcard encodings, we'll default
            // to Gzip.
            if (preferred.IsEmpty && encodings.AcceptWildcard && encodings.Find("gzip").IsEmpty)
            {
                preferred = new QValue("gzip");
            }


            // handle the preferred encoding
            switch (preferred.Name)
            {
            case "gzip":
                Response.AppendHeader("Content-Encoding", "gzip");
                Response.Filter = new GZipStream(Response.Filter, CompressionMode.Compress);
                AddToCookie(Response, Request, "gzip");
                break;

            case "deflate":
                Response.AppendHeader("Content-Encoding", "deflate");
                Response.Filter = new DeflateStream(Response.Filter, CompressionMode.Compress);
                AddToCookie(Response, Request, "deflate");
                break;

            case "identity":
            default:
                break;
            }
        }
예제 #10
0
        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            if (filterContext == null)
                throw new ArgumentNullException("filterContext");

            if (filterContext.Exception != null)
                return;

            if (filterContext.IsChildAction)
                return;

            var request = filterContext.HttpContext.Request;
            var response = filterContext.HttpContext.Response;
            if (response.Filter == null)
                return;

            var encodings = new QValueList(request.Headers["Accept-Encoding"]);
            var preferred = encodings.FindPreferred("gzip", "deflate", "identity");

            // if none of the preferred values were found, but the
            // client can accept wildcard encodings, we'll default
            // to Gzip.
            if (preferred.IsEmpty && encodings.AcceptWildcard && encodings.Find("gzip").IsEmpty)
                preferred = new QValue("gzip");

            switch (preferred.Name) {
                case "gzip":
                    response.AppendHeader("Content-encoding", "gzip");
                    response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                    break;

                case "deflate":
                    response.AppendHeader("Content-encoding", "deflate");
                    response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                    break;

                case "identity":
                    break;
                default:
                    break;
            }
        }
예제 #11
0
        /// <summary>
        /// <para>Attempts to proactively negotiate a compression method for a response,
        /// based on a request's <c>Accept-Encoding</c> header (or lack of it).</para>
        /// </summary>
        /// <param name="this">The <see cref="IHttpRequest"/> on which this method is called.</param>
        /// <param name="preferCompression"><see langword="true"/> if sending compressed data is preferred over
        /// sending non-compressed data; otherwise, <see langword="false"/>.</param>
        /// <param name="compressionMethod">When this method returns, the compression method to use for the response,
        /// if content negotiation is successful. This parameter is passed uninitialized.</param>
        /// <param name="prepareResponse">When this method returns, a callback that prepares data in an <see cref="IHttpResponse"/>
        /// according to the result of content negotiation. This parameter is passed uninitialized.</param>
        /// <returns><see langword="true"/> if content negotiation is successful;
        /// otherwise, <see langword="false"/>.</returns>
        /// <remarks>
        /// <para>If this method returns <see langword="true"/>, the <paramref name="prepareResponse"/> callback
        /// will set appropriate response headers to reflect the results of content negotiation.</para>
        /// <para>If this method returns <see langword="false"/>, the <paramref name="prepareResponse"/> callback
        /// will throw a <see cref="HttpNotAcceptableException"/> to send a <c>406 Not Acceptable</c> response
        /// with the <c>Vary</c> header set to <c>Accept-Encoding</c>,
        /// so that the client may know the reason why the request has been rejected.</para>
        /// <para>If <paramref name="this"/> has no<c>Accept-Encoding</c> header, this method
        /// always returns <see langword="true"/> and sets <paramref name="compressionMethod"/>
        /// to <see cref="CompressionMethod.None"/>.</para>
        /// </remarks>
        /// <seealso cref="HttpNotAcceptableException(string)"/>
        public static bool TryNegotiateContentEncoding(
            this IHttpRequest @this,
            bool preferCompression,
            out CompressionMethod compressionMethod,
            out Action <IHttpResponse> prepareResponse)
        {
            var acceptedEncodings = new QValueList(true, @this.Headers.GetValues(HttpHeaderNames.AcceptEncoding));

            if (!acceptedEncodings.TryNegotiateContentEncoding(preferCompression, out compressionMethod, out var compressionMethodName))
            {
                prepareResponse = r => throw HttpException.NotAcceptable(HttpHeaderNames.AcceptEncoding);
                return(false);
            }

            prepareResponse = r => {
                r.Headers.Add(HttpHeaderNames.Vary, HttpHeaderNames.AcceptEncoding);
                r.Headers.Set(HttpHeaderNames.ContentEncoding, compressionMethodName);
            };
            return(true);
        }
        public void QValueList_TryNegotiateContentEncoding_WhenPreferCompressionFalse_OnNoCompressionSpecified_ReturnsTrue()
        {
            var list = new QValueList(true, "gzip, deflate");

            Assert.IsTrue(list.TryNegotiateContentEncoding(false, out _, out _));
        }
예제 #13
0
        private static async Task AddCompressionFilter(IOwinRequest request, IOwinResponse response, AssetData data)
        {
            // load encodings from header
            QValueList encodings = new QValueList(request.Headers["Accept-Encoding"]);

            // get the types we can handle, can be accepted and
            // in the defined client preference
            QValue preferred = encodings.FindPreferred("gzip", "deflate", "identity");

            // if none of the preferred values were found, but the
            // client can accept wildcard encodings, we'll default
            // to Gzip.
            if (preferred.IsEmpty && encodings.AcceptWildcard && encodings.Find("gzip").IsEmpty)
            {
                preferred = new QValue("gzip");
            }

            // handle the preferred encoding
            switch (preferred.Name)
            {
                case "deflate":
                    response.ContentLength = data.DeflateData.Length;
                    response.Headers.Add("Content-Encoding", new[] { "deflate" });
                    await response.WriteAsync(data.DeflateData).ConfigureAwait(false);
                    break;
                case "gzip":
                    response.ContentLength = data.ZipData.Length;
                    response.Headers.Add("Content-Encoding", new[] { "gzip" });
                    await response.WriteAsync(data.ZipData).ConfigureAwait(false);
                    break;
                default:
                    response.ContentLength = data.Data.Length;
                    await response.WriteAsync(data.Data).ConfigureAwait(false);
                    break;
            }
        }