-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
Currently, the response compression middleware only adds a Vary: Accept-Encoding header to the response, if and only if the request contains an Accept-Encoding header.
This is wrong. The Vary: Accept-Encoding header should be included in the response regardless of whether or not Accept-Encoding was part of the original request. This is because otherwise, if the very first request is one without the Accept-Encoding header (and by extension there is no Vary: Accept-Encoding in the response), an HTTP cache would not know that if a subsequent request came in that did include an Accept-Encoding header, it should NOT use the previous cache entry to satisfy that request.
The value of the Vary header shouldn't be 'conditional' (for a request to the same URL). That's incorrect behavior and would cause issues especially with proxy caches (e.g. CDNs).
This principle is something that was explicitly pointed out in this article by Fastly — which is also mentioned in the MDN page for Vary.
Expected Behavior
The Vary: Accept-Encoding header should be included in every response whose Content-Type MIME type is supported by the response compression middleware, regardless of the presence of Accept-Encoding in the request.
This same principle also applies to any middleware that might add a value to the Vary header of the response, there could be some others in the ASP.NET Core codebase as well, although the response compression middleware is the one I stumbled into.
The relevant piece of code seems to be the following:
aspnetcore/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs
Lines 202 to 225 in 86817b0
| private ICompressionProvider? InitializeCompressionHeaders() | |
| { | |
| if (_provider.ShouldCompressResponse(_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); | |
| } |
Steps To Reproduce
No response
Exceptions (if any)
No response
.NET Version
No response
Anything else?
No response