Add Vary: Accept-Encoding if response MIME type is compressible
This commit is contained in:
parent
0a95102f5a
commit
6855f9bca1
|
|
@ -211,6 +211,24 @@ namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
_compressionChecked = true;
|
_compressionChecked = true;
|
||||||
if (_provider.ShouldCompressResponse(_context))
|
if (_provider.ShouldCompressResponse(_context))
|
||||||
{
|
{
|
||||||
|
// If the MIME type indicates that the response could be compressed, caches will need to vary by the Accept-Encoding header
|
||||||
|
var varyValues = _context.Response.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)
|
||||||
|
{
|
||||||
|
_context.Response.Headers.Append(HeaderNames.Vary, HeaderNames.AcceptEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
var compressionProvider = ResolveCompressionProvider();
|
var compressionProvider = ResolveCompressionProvider();
|
||||||
if (compressionProvider != null)
|
if (compressionProvider != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -14,6 +15,25 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
{
|
{
|
||||||
public class BodyWrapperStreamTests
|
public class BodyWrapperStreamTests
|
||||||
{
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(null, "Accept-Encoding")]
|
||||||
|
[InlineData("", "Accept-Encoding")]
|
||||||
|
[InlineData("AnotherHeader", "AnotherHeader,Accept-Encoding")]
|
||||||
|
[InlineData("Accept-Encoding", "Accept-Encoding")]
|
||||||
|
[InlineData("accepT-encodinG", "accepT-encodinG")]
|
||||||
|
[InlineData("accept-encoding,AnotherHeader", "accept-encoding,AnotherHeader")]
|
||||||
|
public void OnWrite_AppendsAcceptEncodingToVaryHeader_IfNotPresent(string providedVaryHeader, string expectedVaryHeader)
|
||||||
|
{
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Response.Headers[HeaderNames.Vary] = providedVaryHeader;
|
||||||
|
var stream = new BodyWrapperStream(httpContext, new MemoryStream(), new MockResponseCompressionProvider(flushable: true), null, null);
|
||||||
|
|
||||||
|
stream.Write(new byte[] { }, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
Assert.Equal(expectedVaryHeader, httpContext.Response.Headers[HeaderNames.Vary]);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(true)]
|
[InlineData(true)]
|
||||||
[InlineData(false)]
|
[InlineData(false)]
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
{
|
{
|
||||||
var response = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain);
|
var response = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain);
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: 100);
|
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
{
|
{
|
||||||
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "unknown" }, responseType: TextPlain);
|
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "unknown" }, responseType: TextPlain);
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: 100);
|
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
|
|
||||||
var response = await client.SendAsync(request);
|
var response = await client.SendAsync(request);
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: 100);
|
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
|
|
||||||
var response = await client.SendAsync(request);
|
var response = await client.SendAsync(request);
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: 0);
|
CheckResponseNotCompressed(response, expectedBodyLength: 0, sendVaryHeader: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -201,7 +201,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
{
|
{
|
||||||
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "identity" }, responseType: TextPlain);
|
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "identity" }, responseType: TextPlain);
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: 100);
|
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -221,7 +221,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
{
|
{
|
||||||
var response = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain);
|
var response = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain);
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: expectedBodyLength);
|
CheckResponseNotCompressed(response, expectedBodyLength: expectedBodyLength, sendVaryHeader: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -229,7 +229,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
{
|
{
|
||||||
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip" }, responseType: "text/custom");
|
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip" }, responseType: "text/custom");
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: 100);
|
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -240,7 +240,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
r.Headers[HeaderNames.ContentRange] = "1-2/*";
|
r.Headers[HeaderNames.ContentRange] = "1-2/*";
|
||||||
});
|
});
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: 50);
|
CheckResponseNotCompressed(response, expectedBodyLength: 50, sendVaryHeader: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -446,7 +446,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
request.Headers.AcceptEncoding.ParseAdd("gzip");
|
request.Headers.AcceptEncoding.ParseAdd("gzip");
|
||||||
|
|
||||||
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
|
||||||
IEnumerable<string> contentMD5 = null;
|
IEnumerable<string> contentMD5 = null;
|
||||||
Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5));
|
Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5));
|
||||||
Assert.Single(response.Content.Headers.ContentEncoding, "gzip");
|
Assert.Single(response.Content.Headers.ContentEncoding, "gzip");
|
||||||
|
|
@ -662,7 +662,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
|
|
||||||
var response = await client.SendAsync(request);
|
var response = await client.SendAsync(request);
|
||||||
|
|
||||||
CheckResponseNotCompressed(response, expectedBodyLength: 1024);
|
CheckResponseNotCompressed(response, expectedBodyLength: 1024, sendVaryHeader: false);
|
||||||
|
|
||||||
Assert.True(fakeSendFile.Invoked);
|
Assert.True(fakeSendFile.Invoked);
|
||||||
}
|
}
|
||||||
|
|
@ -793,13 +793,40 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
{
|
{
|
||||||
IEnumerable<string> contentMD5 = null;
|
IEnumerable<string> contentMD5 = null;
|
||||||
|
|
||||||
|
var containsVaryAcceptEncoding = false;
|
||||||
|
foreach (var value in response.Headers.GetValues(HeaderNames.Vary))
|
||||||
|
{
|
||||||
|
if (value.Contains(HeaderNames.AcceptEncoding))
|
||||||
|
{
|
||||||
|
containsVaryAcceptEncoding = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.True(containsVaryAcceptEncoding);
|
||||||
Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5));
|
Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5));
|
||||||
Assert.Single(response.Content.Headers.ContentEncoding, "gzip");
|
Assert.Single(response.Content.Headers.ContentEncoding, "gzip");
|
||||||
Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength);
|
Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckResponseNotCompressed(HttpResponseMessage response, int expectedBodyLength)
|
private void CheckResponseNotCompressed(HttpResponseMessage response, int expectedBodyLength, bool sendVaryHeader)
|
||||||
{
|
{
|
||||||
|
if (sendVaryHeader)
|
||||||
|
{
|
||||||
|
var containsVaryAcceptEncoding = false;
|
||||||
|
foreach (var value in response.Headers.GetValues(HeaderNames.Vary))
|
||||||
|
{
|
||||||
|
if (value.Contains(HeaderNames.AcceptEncoding))
|
||||||
|
{
|
||||||
|
containsVaryAcceptEncoding = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.True(containsVaryAcceptEncoding);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.False(response.Headers.Contains(HeaderNames.Vary));
|
||||||
|
}
|
||||||
Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5));
|
Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5));
|
||||||
Assert.Empty(response.Content.Headers.ContentEncoding);
|
Assert.Empty(response.Content.Headers.ContentEncoding);
|
||||||
Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength);
|
Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue