Skip to content
This repository was archived by the owner on Dec 20, 2018. It is now read-only.

Commit 6855f9b

Browse files
committed
Add Vary: Accept-Encoding if response MIME type is compressible
1 parent 0a95102 commit 6855f9b

File tree

3 files changed

+76
-11
lines changed

3 files changed

+76
-11
lines changed

src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,24 @@ private void OnWrite()
211211
_compressionChecked = true;
212212
if (_provider.ShouldCompressResponse(_context))
213213
{
214+
// If the MIME type indicates that the response could be compressed, caches will need to vary by the Accept-Encoding header
215+
var varyValues = _context.Response.Headers.GetCommaSeparatedValues(HeaderNames.Vary);
216+
var varyByAcceptEncoding = false;
217+
218+
for (var i = 0; i < varyValues.Length; i++)
219+
{
220+
if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase))
221+
{
222+
varyByAcceptEncoding = true;
223+
break;
224+
}
225+
}
226+
227+
if (!varyByAcceptEncoding)
228+
{
229+
_context.Response.Headers.Append(HeaderNames.Vary, HeaderNames.AcceptEncoding);
230+
}
231+
214232
var compressionProvider = ResolveCompressionProvider();
215233
if (compressionProvider != null)
216234
{

test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,33 @@
77
using System.Threading;
88
using System.Threading.Tasks;
99
using Microsoft.AspNetCore.Http;
10+
using Microsoft.Net.Http.Headers;
1011
using Moq;
1112
using Xunit;
1213

1314
namespace Microsoft.AspNetCore.ResponseCompression.Tests
1415
{
1516
public class BodyWrapperStreamTests
1617
{
18+
[Theory]
19+
[InlineData(null, "Accept-Encoding")]
20+
[InlineData("", "Accept-Encoding")]
21+
[InlineData("AnotherHeader", "AnotherHeader,Accept-Encoding")]
22+
[InlineData("Accept-Encoding", "Accept-Encoding")]
23+
[InlineData("accepT-encodinG", "accepT-encodinG")]
24+
[InlineData("accept-encoding,AnotherHeader", "accept-encoding,AnotherHeader")]
25+
public void OnWrite_AppendsAcceptEncodingToVaryHeader_IfNotPresent(string providedVaryHeader, string expectedVaryHeader)
26+
{
27+
var httpContext = new DefaultHttpContext();
28+
httpContext.Response.Headers[HeaderNames.Vary] = providedVaryHeader;
29+
var stream = new BodyWrapperStream(httpContext, new MemoryStream(), new MockResponseCompressionProvider(flushable: true), null, null);
30+
31+
stream.Write(new byte[] { }, 0, 0);
32+
33+
34+
Assert.Equal(expectedVaryHeader, httpContext.Response.Headers[HeaderNames.Vary]);
35+
}
36+
1737
[Theory]
1838
[InlineData(true)]
1939
[InlineData(false)]

test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public async Task Request_NoAcceptEncoding_Uncompressed()
3636
{
3737
var response = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain);
3838

39-
CheckResponseNotCompressed(response, expectedBodyLength: 100);
39+
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false);
4040
}
4141

4242
[Fact]
@@ -52,7 +52,7 @@ public async Task Request_AcceptUnknown_NotCompressed()
5252
{
5353
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "unknown" }, responseType: TextPlain);
5454

55-
CheckResponseNotCompressed(response, expectedBodyLength: 100);
55+
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true);
5656
}
5757

5858
[Theory]
@@ -149,7 +149,7 @@ public async Task MimeTypes_OtherContentTypes_NoMatch(string contentType)
149149

150150
var response = await client.SendAsync(request);
151151

152-
CheckResponseNotCompressed(response, expectedBodyLength: 100);
152+
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false);
153153
}
154154

155155
[Theory]
@@ -185,7 +185,7 @@ public async Task NoBody_NotCompressed(string contentType)
185185

186186
var response = await client.SendAsync(request);
187187

188-
CheckResponseNotCompressed(response, expectedBodyLength: 0);
188+
CheckResponseNotCompressed(response, expectedBodyLength: 0, sendVaryHeader: false);
189189
}
190190

191191
[Fact]
@@ -201,7 +201,7 @@ public async Task Request_AcceptIdentity_NotCompressed()
201201
{
202202
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "identity" }, responseType: TextPlain);
203203

204-
CheckResponseNotCompressed(response, expectedBodyLength: 100);
204+
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true);
205205
}
206206

207207
[Theory]
@@ -221,15 +221,15 @@ public async Task Request_AcceptWithhigherIdentityQuality_NotCompressed(string[]
221221
{
222222
var response = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain);
223223

224-
CheckResponseNotCompressed(response, expectedBodyLength: expectedBodyLength);
224+
CheckResponseNotCompressed(response, expectedBodyLength: expectedBodyLength, sendVaryHeader: true);
225225
}
226226

227227
[Fact]
228228
public async Task Response_UnknownMimeType_NotCompressed()
229229
{
230230
var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip" }, responseType: "text/custom");
231231

232-
CheckResponseNotCompressed(response, expectedBodyLength: 100);
232+
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false);
233233
}
234234

235235
[Fact]
@@ -240,7 +240,7 @@ public async Task Response_WithContentRange_NotCompressed()
240240
r.Headers[HeaderNames.ContentRange] = "1-2/*";
241241
});
242242

243-
CheckResponseNotCompressed(response, expectedBodyLength: 50);
243+
CheckResponseNotCompressed(response, expectedBodyLength: 50, sendVaryHeader: false);
244244
}
245245

246246
[Fact]
@@ -446,7 +446,7 @@ public async Task FlushAsyncBody_CompressesAndFlushes()
446446
request.Headers.AcceptEncoding.ParseAdd("gzip");
447447

448448
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
449-
449+
450450
IEnumerable<string> contentMD5 = null;
451451
Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5));
452452
Assert.Single(response.Content.Headers.ContentEncoding, "gzip");
@@ -662,7 +662,7 @@ public async Task SendFileAsync_DifferentContentType_NotBypassed()
662662

663663
var response = await client.SendAsync(request);
664664

665-
CheckResponseNotCompressed(response, expectedBodyLength: 1024);
665+
CheckResponseNotCompressed(response, expectedBodyLength: 1024, sendVaryHeader: false);
666666

667667
Assert.True(fakeSendFile.Invoked);
668668
}
@@ -793,13 +793,40 @@ private void CheckResponseCompressed(HttpResponseMessage response, int expectedB
793793
{
794794
IEnumerable<string> contentMD5 = null;
795795

796+
var containsVaryAcceptEncoding = false;
797+
foreach (var value in response.Headers.GetValues(HeaderNames.Vary))
798+
{
799+
if (value.Contains(HeaderNames.AcceptEncoding))
800+
{
801+
containsVaryAcceptEncoding = true;
802+
break;
803+
}
804+
}
805+
Assert.True(containsVaryAcceptEncoding);
796806
Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5));
797807
Assert.Single(response.Content.Headers.ContentEncoding, "gzip");
798808
Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength);
799809
}
800810

801-
private void CheckResponseNotCompressed(HttpResponseMessage response, int expectedBodyLength)
811+
private void CheckResponseNotCompressed(HttpResponseMessage response, int expectedBodyLength, bool sendVaryHeader)
802812
{
813+
if (sendVaryHeader)
814+
{
815+
var containsVaryAcceptEncoding = false;
816+
foreach (var value in response.Headers.GetValues(HeaderNames.Vary))
817+
{
818+
if (value.Contains(HeaderNames.AcceptEncoding))
819+
{
820+
containsVaryAcceptEncoding = true;
821+
break;
822+
}
823+
}
824+
Assert.True(containsVaryAcceptEncoding);
825+
}
826+
else
827+
{
828+
Assert.False(response.Headers.Contains(HeaderNames.Vary));
829+
}
803830
Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5));
804831
Assert.Empty(response.Content.Headers.ContentEncoding);
805832
Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength);

0 commit comments

Comments
 (0)