From 9417ad88245d4a2170c936afbf1059476a608d78 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Fri, 12 Apr 2024 00:00:04 +0200 Subject: [PATCH 1/8] ALWAYS include the Vary Accept-Encoding header when response compression is enabled --- .../src/ResponseCompressionProvider.cs | 8 -------- .../test/ResponseCompressionMiddlewareTest.cs | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs index 4b31aacfca68..79e2627b6d9f 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; @@ -80,7 +79,6 @@ public ResponseCompressionProvider(IServiceProvider services, IOptions public bool CheckRequestAcceptsCompression(HttpContext context) { - if (string.IsNullOrEmpty(context.Request.Headers.AcceptEncoding)) - { - _logger.NoAcceptEncoding(); - return false; - } - _logger.RequestAcceptsCompression(); // Trace, there will be more logs return true; } diff --git a/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs index 15e49559ab1c..fa7d9ce1a68a 100644 --- a/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs +++ b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs @@ -46,12 +46,15 @@ public void Options_HttpsDisabledByDefault() } [Fact] - public async Task Request_NoAcceptEncoding_Uncompressed() + public async Task Request_NoAcceptEncoding_Uncompressed_WithVaryHeader() { var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain); - CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false); - AssertLog(logMessages.Single(), LogLevel.Debug, "No response compression available, the Accept-Encoding header is missing or invalid."); + CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true); + Assert.Equal(3, logMessages.Count); + AssertLog(logMessages.First(), LogLevel.Trace, "This request accepts compression."); + AssertLog(logMessages.Skip(1).First(), LogLevel.Trace, "Response compression is available for this Content-Type."); + AssertLog(logMessages.Skip(2).First(), LogLevel.Debug, "No response compression available, the Accept-Encoding header is missing or invalid."); } [Fact] @@ -113,12 +116,15 @@ public async Task Request_AcceptUnknown_NotCompressed() } [Fact] - public async Task RequestHead_NoAcceptEncoding_Uncompressed() + public async Task RequestHead_NoAcceptEncoding_Uncompressed_WithVaryHeader() { var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain, httpMethod: HttpMethods.Head); - CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false); - AssertLog(logMessages.Single(), LogLevel.Debug, "No response compression available, the Accept-Encoding header is missing or invalid."); + CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true); + Assert.Equal(3, logMessages.Count); + AssertLog(logMessages.First(), LogLevel.Trace, "This request accepts compression."); + AssertLog(logMessages.Skip(1).First(), LogLevel.Trace, "Response compression is available for this Content-Type."); + AssertLog(logMessages.Skip(2).First(), LogLevel.Debug, "No response compression available, the Accept-Encoding header is missing or invalid."); } [Fact] From bc980c7b2596ecf2c5dbf2289140c1d0870f8a26 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sun, 22 Mar 2026 18:21:22 +0100 Subject: [PATCH 2/8] fix remarks --- .../src/ResponseCompressionMiddleware.cs | 47 +++++++++++++++++-- .../src/ResponseCompressionProvider.cs | 8 ++++ .../test/ResponseCompressionMiddlewareTest.cs | 12 ++--- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs index 22a9677d6e10..b04138d38b03 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs @@ -4,6 +4,8 @@ using System.Diagnostics; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression; @@ -34,13 +36,52 @@ public ResponseCompressionMiddleware(RequestDelegate next, IResponseCompressionP /// /// The . /// A task that represents the execution of this middleware. - public Task Invoke(HttpContext context) + public async Task Invoke(HttpContext context) { if (!_provider.CheckRequestAcceptsCompression(context)) { - return _next(context); + var originalResponseFeature = context.Features.Get(); + Debug.Assert(originalResponseFeature != null); + originalResponseFeature.OnStarting(OnStartingResponseHandler, context); + + try + { + await _next(context); + } + finally + { + context.Features.Set(originalResponseFeature); + } + return; + } + + await InvokeCore(context); + } + + private async Task OnStartingResponseHandler(object state) + { + HttpContext context = (HttpContext)state; + + if (_provider.ShouldCompressResponse(context)) + { + var headers = context.Response.Headers; + var varyValues = headers.GetCommaSeparatedValues(HeaderNames.Vary); + var varyByAcceptEncoding = false; + + for (var i = 0; i < varyValues.Length; i++) + { + if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) + { + varyByAcceptEncoding = true; + break; + } + } + + if (!varyByAcceptEncoding) + { + headers.Vary = StringValues.Concat(headers.Vary, HeaderNames.AcceptEncoding); + } } - return InvokeCore(context); } private async Task InvokeCore(HttpContext context) diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs index 006177672a43..caeb42414089 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; @@ -80,6 +81,7 @@ public ResponseCompressionProvider(IServiceProvider services, IOptions public bool CheckRequestAcceptsCompression(HttpContext context) { + if (string.IsNullOrEmpty(context.Request.Headers.AcceptEncoding)) + { + _logger.NoAcceptEncoding(); + return false; + } + _logger.RequestAcceptsCompression(); // Trace, there will be more logs return true; } diff --git a/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs index 189c0d592e24..c1b4ee346431 100644 --- a/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs +++ b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs @@ -46,10 +46,9 @@ public async Task Request_NoAcceptEncoding_Uncompressed_WithVaryHeader() var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain); CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true); - Assert.Equal(3, logMessages.Count); - AssertLog(logMessages.First(), LogLevel.Trace, "This request accepts compression."); + Assert.Equal(2, logMessages.Count); + AssertLog(logMessages.First(), LogLevel.Debug, "No response compression available, the Accept-Encoding header is missing or invalid."); AssertLog(logMessages.Skip(1).First(), LogLevel.Trace, "Response compression is available for this Content-Type."); - AssertLog(logMessages.Skip(2).First(), LogLevel.Debug, "No response compression available, the Accept-Encoding header is missing or invalid."); } [Fact] @@ -140,10 +139,9 @@ public async Task RequestHead_NoAcceptEncoding_Uncompressed_WithVaryHeader() var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain, httpMethod: HttpMethods.Head); CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true); - Assert.Equal(3, logMessages.Count); - AssertLog(logMessages.First(), LogLevel.Trace, "This request accepts compression."); + Assert.Equal(2, logMessages.Count); + AssertLog(logMessages.First(), LogLevel.Debug, "No response compression available, the Accept-Encoding header is missing or invalid."); AssertLog(logMessages.Skip(1).First(), LogLevel.Trace, "Response compression is available for this Content-Type."); - AssertLog(logMessages.Skip(2).First(), LogLevel.Debug, "No response compression available, the Accept-Encoding header is missing or invalid."); } [Fact] @@ -1273,7 +1271,7 @@ public async Task Dispose_SyncWriteOrFlushNotCalled(string encoding) Assert.True(read > 0); } - private static async Task<(HttpResponseMessage, List)> InvokeMiddleware( + private async Task<(HttpResponseMessage, List)> InvokeMiddleware( int uncompressedBodyLength, string[] requestAcceptEncodings, string responseType, From 72a296eee8db31ba8f6b6ab3dd6a1f68358eaaf7 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sun, 22 Mar 2026 18:23:09 +0100 Subject: [PATCH 3/8] readd static --- .../test/ResponseCompressionMiddlewareTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs index c1b4ee346431..156ad4ae22a3 100644 --- a/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs +++ b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs @@ -1271,7 +1271,7 @@ public async Task Dispose_SyncWriteOrFlushNotCalled(string encoding) Assert.True(read > 0); } - private async Task<(HttpResponseMessage, List)> InvokeMiddleware( + private static async Task<(HttpResponseMessage, List)> InvokeMiddleware( int uncompressedBodyLength, string[] requestAcceptEncodings, string responseType, From 6078eb823205656d347276b147226d16df6391be Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 28 Mar 2026 17:04:17 +0100 Subject: [PATCH 4/8] fix remarks --- .../src/IResponseCompressionProvider.cs | 7 +++++ .../src/PublicAPI.Unshipped.txt | 2 ++ .../src/ResponseCompressionBody.cs | 22 +------------- .../src/ResponseCompressionMiddleware.cs | 24 +-------------- .../src/ResponseCompressionProvider.cs | 29 ++++++++++++++++++ .../test/ResponseCompressionBodyTest.cs | 30 +++++++++++++++++++ 6 files changed, 70 insertions(+), 44 deletions(-) diff --git a/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs index 7353fbdfab0a..fb1a6b0ed0cf 100644 --- a/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs +++ b/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs @@ -30,4 +30,11 @@ public interface IResponseCompressionProvider /// The . /// if the request accepts compression, otherwise . bool CheckRequestAcceptsCompression(HttpContext context); + + /// + /// Examines the response on first write to see if compression should be used and if true sets the Vary Accept-Encoding header. + /// + /// The . + /// if the response should be compressed, otherwise . + bool ShouldCompressResponseCommon(HttpContext context); } diff --git a/src/Middleware/ResponseCompression/src/PublicAPI.Unshipped.txt b/src/Middleware/ResponseCompression/src/PublicAPI.Unshipped.txt index ba82101f2962..898f4d9574ea 100644 --- a/src/Middleware/ResponseCompression/src/PublicAPI.Unshipped.txt +++ b/src/Middleware/ResponseCompression/src/PublicAPI.Unshipped.txt @@ -8,3 +8,5 @@ Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions.CompressionOptions.get -> System.IO.Compression.ZstandardCompressionOptions! Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions.CompressionOptions.set -> void Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions.ZstandardCompressionProviderOptions() -> void +Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider.ShouldCompressResponseCommon(Microsoft.AspNetCore.Http.HttpContext! context) -> bool +Microsoft.AspNetCore.ResponseCompression.ResponseCompressionProvider.ShouldCompressResponseCommon(Microsoft.AspNetCore.Http.HttpContext! context) -> bool diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs index 2eefdb6482b8..34b521d5f09c 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs @@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Primitives; -using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression; @@ -201,28 +200,9 @@ public override async ValueTask WriteAsync(ReadOnlyMemory buffer, Cancella /// The compression provider to use if compression is enabled, otherwise null. private ICompressionProvider? InitializeCompressionHeaders() { - if (_provider.ShouldCompressResponse(_context)) + if (_provider.ShouldCompressResponseCommon(_context)) { var headers = _context.Response.Headers; - // If the MIME type indicates that the response could be compressed, caches will need to vary by the Accept-Encoding header - var varyValues = headers.GetCommaSeparatedValues(HeaderNames.Vary); - var varyByAcceptEncoding = false; - - for (var i = 0; i < varyValues.Length; i++) - { - if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) - { - varyByAcceptEncoding = true; - break; - } - } - - if (!varyByAcceptEncoding) - { - // Can't use += as StringValues does not override operator+ - // and the implict conversions will cause an incorrect string concat https://github.com/dotnet/runtime/issues/52507 - headers.Vary = StringValues.Concat(headers.Vary, HeaderNames.AcceptEncoding); - } var compressionProvider = ResolveCompressionProvider(); if (compressionProvider != null) diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs index b04138d38b03..5cf357ae8a76 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs @@ -4,8 +4,6 @@ using System.Diagnostics; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.Primitives; -using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression; @@ -61,27 +59,7 @@ public async Task Invoke(HttpContext context) private async Task OnStartingResponseHandler(object state) { HttpContext context = (HttpContext)state; - - if (_provider.ShouldCompressResponse(context)) - { - var headers = context.Response.Headers; - var varyValues = headers.GetCommaSeparatedValues(HeaderNames.Vary); - var varyByAcceptEncoding = false; - - for (var i = 0; i < varyValues.Length; i++) - { - if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) - { - varyByAcceptEncoding = true; - break; - } - } - - if (!varyByAcceptEncoding) - { - headers.Vary = StringValues.Concat(headers.Vary, HeaderNames.AcceptEncoding); - } - } + _provider.ShouldCompressResponseCommon(context); } private async Task InvokeCore(HttpContext context) diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs index caeb42414089..d9f256ed3d0b 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs @@ -160,6 +160,35 @@ public ResponseCompressionProvider(IServiceProvider services, IOptions + public bool ShouldCompressResponseCommon(HttpContext context) + { + var result = ShouldCompressResponse(context); + + if (result) + { + var headers = context.Response.Headers; + var varyValues = headers.GetCommaSeparatedValues(HeaderNames.Vary); + var varyByAcceptEncoding = false; + + for (var i = 0; i < varyValues.Length; i++) + { + if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) + { + varyByAcceptEncoding = true; + break; + } + } + + if (!varyByAcceptEncoding) + { + headers.Vary = StringValues.Concat(headers.Vary, HeaderNames.AcceptEncoding); + } + } + + return result; + } + /// public virtual bool ShouldCompressResponse(HttpContext context) { diff --git a/src/Middleware/ResponseCompression/test/ResponseCompressionBodyTest.cs b/src/Middleware/ResponseCompression/test/ResponseCompressionBodyTest.cs index 0999ddd07b8e..9ac8a73d9dae 100644 --- a/src/Middleware/ResponseCompression/test/ResponseCompressionBodyTest.cs +++ b/src/Middleware/ResponseCompression/test/ResponseCompressionBodyTest.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression.Tests; @@ -109,6 +111,34 @@ public bool ShouldCompressResponse(HttpContext context) return true; } + public bool ShouldCompressResponseCommon(HttpContext context) + { + var result = ShouldCompressResponse(context); + + if (result) + { + var headers = context.Response.Headers; + var varyValues = headers.GetCommaSeparatedValues(HeaderNames.Vary); + var varyByAcceptEncoding = false; + + for (var i = 0; i < varyValues.Length; i++) + { + if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) + { + varyByAcceptEncoding = true; + break; + } + } + + if (!varyByAcceptEncoding) + { + headers.Vary = StringValues.Concat(headers.Vary, HeaderNames.AcceptEncoding); + } + } + + return result; + } + public bool CheckRequestAcceptsCompression(HttpContext context) { return true; From 8da83e745ea075002c473d6eb41a6c78d5315c81 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 2 Apr 2026 11:10:07 +0200 Subject: [PATCH 5/8] fix remarks --- .../src/IResponseCompressionProvider.cs | 7 ---- .../src/PublicAPI.Unshipped.txt | 2 - .../src/ResponseCompressionBody.cs | 37 ++++++++++++++++++- .../src/ResponseCompressionMiddleware.cs | 2 +- .../src/ResponseCompressionProvider.cs | 29 --------------- 5 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs index fb1a6b0ed0cf..7353fbdfab0a 100644 --- a/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs +++ b/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs @@ -30,11 +30,4 @@ public interface IResponseCompressionProvider /// The . /// if the request accepts compression, otherwise . bool CheckRequestAcceptsCompression(HttpContext context); - - /// - /// Examines the response on first write to see if compression should be used and if true sets the Vary Accept-Encoding header. - /// - /// The . - /// if the response should be compressed, otherwise . - bool ShouldCompressResponseCommon(HttpContext context); } diff --git a/src/Middleware/ResponseCompression/src/PublicAPI.Unshipped.txt b/src/Middleware/ResponseCompression/src/PublicAPI.Unshipped.txt index 898f4d9574ea..ba82101f2962 100644 --- a/src/Middleware/ResponseCompression/src/PublicAPI.Unshipped.txt +++ b/src/Middleware/ResponseCompression/src/PublicAPI.Unshipped.txt @@ -8,5 +8,3 @@ Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions.CompressionOptions.get -> System.IO.Compression.ZstandardCompressionOptions! Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions.CompressionOptions.set -> void Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions.ZstandardCompressionProviderOptions() -> void -Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider.ShouldCompressResponseCommon(Microsoft.AspNetCore.Http.HttpContext! context) -> bool -Microsoft.AspNetCore.ResponseCompression.ResponseCompressionProvider.ShouldCompressResponseCommon(Microsoft.AspNetCore.Http.HttpContext! context) -> bool diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs index 34b521d5f09c..671c81231043 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression; @@ -194,13 +195,47 @@ public override async ValueTask WriteAsync(ReadOnlyMemory buffer, Cancella } } + /// + /// Examines the response on first write to see if compression should be used and if true sets the Vary Accept-Encoding header. + /// + /// current response compression provider + /// The . + /// if the response should be compressed, otherwise . + internal static bool ShouldCompressResponseCommon(IResponseCompressionProvider provider, HttpContext context) + { + var result = provider.ShouldCompressResponse(context); + + if (result) + { + var headers = context.Response.Headers; + var varyValues = headers.GetCommaSeparatedValues(HeaderNames.Vary); + var varyByAcceptEncoding = false; + + for (var i = 0; i < varyValues.Length; i++) + { + if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) + { + varyByAcceptEncoding = true; + break; + } + } + + if (!varyByAcceptEncoding) + { + headers.Vary = StringValues.Concat(headers.Vary, HeaderNames.AcceptEncoding); + } + } + + return result; + } + /// /// Checks if the response should be compressed and sets the response headers. /// /// The compression provider to use if compression is enabled, otherwise null. private ICompressionProvider? InitializeCompressionHeaders() { - if (_provider.ShouldCompressResponseCommon(_context)) + if (ShouldCompressResponseCommon(_provider, _context)) { var headers = _context.Response.Headers; diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs index 5cf357ae8a76..829734db680e 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs @@ -59,7 +59,7 @@ public async Task Invoke(HttpContext context) private async Task OnStartingResponseHandler(object state) { HttpContext context = (HttpContext)state; - _provider.ShouldCompressResponseCommon(context); + ResponseCompressionBody.ShouldCompressResponseCommon(_provider, context); } private async Task InvokeCore(HttpContext context) diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs index d9f256ed3d0b..caeb42414089 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs @@ -160,35 +160,6 @@ public ResponseCompressionProvider(IServiceProvider services, IOptions - public bool ShouldCompressResponseCommon(HttpContext context) - { - var result = ShouldCompressResponse(context); - - if (result) - { - var headers = context.Response.Headers; - var varyValues = headers.GetCommaSeparatedValues(HeaderNames.Vary); - var varyByAcceptEncoding = false; - - for (var i = 0; i < varyValues.Length; i++) - { - if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) - { - varyByAcceptEncoding = true; - break; - } - } - - if (!varyByAcceptEncoding) - { - headers.Vary = StringValues.Concat(headers.Vary, HeaderNames.AcceptEncoding); - } - } - - return result; - } - /// public virtual bool ShouldCompressResponse(HttpContext context) { From 745dad2b84542ef374331911f5e26858c249eb28 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 2 Apr 2026 11:14:39 +0200 Subject: [PATCH 6/8] delete leftovers --- .../test/ResponseCompressionBodyTest.cs | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/src/Middleware/ResponseCompression/test/ResponseCompressionBodyTest.cs b/src/Middleware/ResponseCompression/test/ResponseCompressionBodyTest.cs index 9ac8a73d9dae..0999ddd07b8e 100644 --- a/src/Middleware/ResponseCompression/test/ResponseCompressionBodyTest.cs +++ b/src/Middleware/ResponseCompression/test/ResponseCompressionBodyTest.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; -using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression.Tests; @@ -111,34 +109,6 @@ public bool ShouldCompressResponse(HttpContext context) return true; } - public bool ShouldCompressResponseCommon(HttpContext context) - { - var result = ShouldCompressResponse(context); - - if (result) - { - var headers = context.Response.Headers; - var varyValues = headers.GetCommaSeparatedValues(HeaderNames.Vary); - var varyByAcceptEncoding = false; - - for (var i = 0; i < varyValues.Length; i++) - { - if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) - { - varyByAcceptEncoding = true; - break; - } - } - - if (!varyByAcceptEncoding) - { - headers.Vary = StringValues.Concat(headers.Vary, HeaderNames.AcceptEncoding); - } - } - - return result; - } - public bool CheckRequestAcceptsCompression(HttpContext context) { return true; From e8a5fb780a87a9eaf40b67fdcfcda6bfe4c819ff Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Fri, 3 Apr 2026 10:27:14 +0200 Subject: [PATCH 7/8] fix remarks --- .../src/ResponseCompressionMiddleware.cs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs index 829734db680e..a33a345c944e 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs @@ -34,26 +34,16 @@ public ResponseCompressionMiddleware(RequestDelegate next, IResponseCompressionP /// /// The . /// A task that represents the execution of this middleware. - public async Task Invoke(HttpContext context) + public Task Invoke(HttpContext context) { if (!_provider.CheckRequestAcceptsCompression(context)) { - var originalResponseFeature = context.Features.Get(); - Debug.Assert(originalResponseFeature != null); + var originalResponseFeature = context.Features.GetRequiredFeature(); originalResponseFeature.OnStarting(OnStartingResponseHandler, context); - - try - { - await _next(context); - } - finally - { - context.Features.Set(originalResponseFeature); - } - return; + return _next(context); } - await InvokeCore(context); + return InvokeCore(context); } private async Task OnStartingResponseHandler(object state) From d4a322fd88510e4f1d64ba19560249ea43921b0a Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Fri, 3 Apr 2026 10:27:56 +0200 Subject: [PATCH 8/8] delete leftovers --- .../ResponseCompression/src/ResponseCompressionMiddleware.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs index a33a345c944e..519c508f5187 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs @@ -42,7 +42,6 @@ public Task Invoke(HttpContext context) originalResponseFeature.OnStarting(OnStartingResponseHandler, context); return _next(context); } - return InvokeCore(context); }