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); }
/// <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); }
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; } }
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); }
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; } }
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; } }
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; } }
/// <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 _)); }
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; } }