Merge pull request #11428 from alefranz/responsecaching-304-headers
ResponseCaching: include required headers in 304
This commit is contained in:
commit
3c0fb1a3f8
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
@ -19,6 +19,10 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
|||
{
|
||||
private static readonly TimeSpan DefaultExpirationTimeSpan = TimeSpan.FromSeconds(10);
|
||||
|
||||
// see https://tools.ietf.org/html/rfc7232#section-4.1
|
||||
private static readonly string[] HeadersToIncludeIn304 =
|
||||
new[] { "Cache-Control", "Content-Location", "Date", "ETag", "Expires", "Vary" };
|
||||
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ResponseCachingOptions _options;
|
||||
private readonly ILogger _logger;
|
||||
|
|
@ -156,6 +160,17 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
|||
{
|
||||
_logger.NotModifiedServed();
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status304NotModified;
|
||||
|
||||
if (context.CachedResponseHeaders != null)
|
||||
{
|
||||
foreach (var key in HeadersToIncludeIn304)
|
||||
{
|
||||
if (context.CachedResponseHeaders.TryGetValue(key, out var values))
|
||||
{
|
||||
context.HttpContext.Response.Headers[key] = values;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
@ -592,19 +592,25 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
|||
[Fact]
|
||||
public async Task Serves304_IfIfModifiedSince_Satisfied()
|
||||
{
|
||||
var builders = TestUtils.CreateBuildersWithResponseCaching();
|
||||
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context =>
|
||||
{
|
||||
context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\"");
|
||||
context.Response.Headers[HeaderNames.ContentLocation] = "/";
|
||||
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
|
||||
});
|
||||
|
||||
foreach (var builder in builders)
|
||||
{
|
||||
using (var server = new TestServer(builder))
|
||||
{
|
||||
var client = server.CreateClient();
|
||||
var initialResponse = await client.GetAsync("");
|
||||
var initialResponse = await client.GetAsync("?Expires=90");
|
||||
client.DefaultRequestHeaders.IfModifiedSince = DateTimeOffset.MaxValue;
|
||||
var subsequentResponse = await client.GetAsync("");
|
||||
|
||||
initialResponse.EnsureSuccessStatusCode();
|
||||
Assert.Equal(System.Net.HttpStatusCode.NotModified, subsequentResponse.StatusCode);
|
||||
Assert304Headers(initialResponse, subsequentResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -631,19 +637,25 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
|||
[Fact]
|
||||
public async Task Serves304_IfIfNoneMatch_Satisfied()
|
||||
{
|
||||
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\""));
|
||||
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context =>
|
||||
{
|
||||
context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\"");
|
||||
context.Response.Headers[HeaderNames.ContentLocation] = "/";
|
||||
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
|
||||
});
|
||||
|
||||
foreach (var builder in builders)
|
||||
{
|
||||
using (var server = new TestServer(builder))
|
||||
{
|
||||
var client = server.CreateClient();
|
||||
var initialResponse = await client.GetAsync("");
|
||||
var initialResponse = await client.GetAsync("?Expires=90");
|
||||
client.DefaultRequestHeaders.IfNoneMatch.Add(new System.Net.Http.Headers.EntityTagHeaderValue("\"E1\""));
|
||||
var subsequentResponse = await client.GetAsync("");
|
||||
|
||||
initialResponse.EnsureSuccessStatusCode();
|
||||
Assert.Equal(System.Net.HttpStatusCode.NotModified, subsequentResponse.StatusCode);
|
||||
Assert304Headers(initialResponse, subsequentResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -814,6 +826,22 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
|||
}
|
||||
}
|
||||
|
||||
private static void Assert304Headers(HttpResponseMessage initialResponse, HttpResponseMessage subsequentResponse)
|
||||
{
|
||||
// https://tools.ietf.org/html/rfc7232#section-4.1
|
||||
// The server generating a 304 response MUST generate any of the
|
||||
// following header fields that would have been sent in a 200 (OK)
|
||||
// response to the same request: Cache-Control, Content-Location, Date,
|
||||
// ETag, Expires, and Vary.
|
||||
|
||||
Assert.Equal(initialResponse.Headers.CacheControl, subsequentResponse.Headers.CacheControl);
|
||||
Assert.Equal(initialResponse.Content.Headers.ContentLocation, subsequentResponse.Content.Headers.ContentLocation);
|
||||
Assert.Equal(initialResponse.Headers.Date, subsequentResponse.Headers.Date);
|
||||
Assert.Equal(initialResponse.Headers.ETag, subsequentResponse.Headers.ETag);
|
||||
Assert.Equal(initialResponse.Content.Headers.Expires, subsequentResponse.Content.Headers.Expires);
|
||||
Assert.Equal(initialResponse.Headers.Vary, subsequentResponse.Headers.Vary);
|
||||
}
|
||||
|
||||
private static async Task AssertCachedResponseAsync(HttpResponseMessage initialResponse, HttpResponseMessage subsequentResponse)
|
||||
{
|
||||
initialResponse.EnsureSuccessStatusCode();
|
||||
|
|
|
|||
Loading…
Reference in New Issue