diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs index 701855e913a3..ef7688e153aa 100644 --- a/src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs +++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs @@ -187,7 +187,8 @@ private RequestDelegate BuildErrorPageApplication(Exception exception) return context => { context.Response.StatusCode = 500; - context.Response.Headers[HeaderNames.CacheControl] = "no-cache"; + context.Response.Headers[HeaderNames.CacheControl] = "no-cache,no-store"; + context.Response.Headers[HeaderNames.Pragma] = "no-cache"; context.Response.ContentType = "text/html; charset=utf-8"; return errorPage.ExecuteAsync(context); }; diff --git a/src/Hosting/Hosting/src/Internal/WebHost.cs b/src/Hosting/Hosting/src/Internal/WebHost.cs index b016f751a887..060b3fd9a7e1 100644 --- a/src/Hosting/Hosting/src/Internal/WebHost.cs +++ b/src/Hosting/Hosting/src/Internal/WebHost.cs @@ -284,7 +284,8 @@ private RequestDelegate BuildApplication() return context => { context.Response.StatusCode = 500; - context.Response.Headers[HeaderNames.CacheControl] = "no-cache"; + context.Response.Headers[HeaderNames.CacheControl] = "no-cache,no-store"; + context.Response.Headers[HeaderNames.Pragma] = "no-cache"; return errorPage.ExecuteAsync(context); }; } diff --git a/src/Middleware/Diagnostics.EntityFrameworkCore/src/MigrationsEndPointMiddleware.cs b/src/Middleware/Diagnostics.EntityFrameworkCore/src/MigrationsEndPointMiddleware.cs index 0a37bf7f3e99..96606122fa63 100644 --- a/src/Middleware/Diagnostics.EntityFrameworkCore/src/MigrationsEndPointMiddleware.cs +++ b/src/Middleware/Diagnostics.EntityFrameworkCore/src/MigrationsEndPointMiddleware.cs @@ -28,8 +28,8 @@ public class MigrationsEndPointMiddleware /// The to write messages to. /// The options to control the behavior of the middleware. public MigrationsEndPointMiddleware( - RequestDelegate next, - ILogger logger, + RequestDelegate next, + ILogger logger, IOptions options) { if (next == null) @@ -80,7 +80,7 @@ public virtual async Task Invoke(HttpContext context) context.Response.StatusCode = (int)HttpStatusCode.NoContent; context.Response.Headers.Add("Pragma", new[] { "no-cache" }); - context.Response.Headers.Add("Cache-Control", new[] { "no-cache" }); + context.Response.Headers.Add("Cache-Control", new[] { "no-cache,no-store" }); _logger.MigrationsApplied(db.GetType().FullName); } @@ -147,7 +147,7 @@ private static async Task WriteErrorToResponse(HttpResponse response, string err { response.StatusCode = (int)HttpStatusCode.BadRequest; response.Headers.Add("Pragma", new[] { "no-cache" }); - response.Headers.Add("Cache-Control", new[] { "no-cache" }); + response.Headers.Add("Cache-Control", new[] { "no-cache,no-store" }); response.ContentType = "text/plain"; // Padding to >512 to ensure IE doesn't hide the message diff --git a/src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerMiddleware.cs b/src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerMiddleware.cs index 5d280b5f43a8..65564cbd5926 100644 --- a/src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerMiddleware.cs +++ b/src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerMiddleware.cs @@ -153,7 +153,7 @@ private static void ClearHttpContext(HttpContext context) private static Task ClearCacheHeaders(object state) { var headers = ((HttpResponse)state).Headers; - headers[HeaderNames.CacheControl] = "no-cache"; + headers[HeaderNames.CacheControl] = "no-cache,no-store"; headers[HeaderNames.Pragma] = "no-cache"; headers[HeaderNames.Expires] = "-1"; headers.Remove(HeaderNames.ETag); diff --git a/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs b/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs index b63eaa4a9892..d24965b760d6 100644 --- a/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs +++ b/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs @@ -164,9 +164,8 @@ public async Task ClearsResponseBuffer_BeforeRequestIsReexecuted() Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(expectedResponseBody, await response.Content.ReadAsStringAsync()); IEnumerable values; - Assert.True(response.Headers.TryGetValues("Cache-Control", out values)); - Assert.Single(values); - Assert.Equal("no-cache", values.First()); + Assert.True(response.Headers.CacheControl.NoCache); + Assert.True(response.Headers.CacheControl.NoStore); Assert.True(response.Headers.TryGetValues("Pragma", out values)); Assert.Single(values); Assert.Equal("no-cache", values.First()); @@ -214,9 +213,8 @@ public async Task ClearsCacheHeaders_SetByReexecutionPathHandlers() Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(expectedResponseBody, await response.Content.ReadAsStringAsync()); IEnumerable values; - Assert.True(response.Headers.TryGetValues("Cache-Control", out values)); - Assert.Single(values); - Assert.Equal("no-cache", values.First()); + Assert.True(response.Headers.CacheControl.NoCache); + Assert.True(response.Headers.CacheControl.NoStore); Assert.True(response.Headers.TryGetValues("Pragma", out values)); Assert.Single(values); Assert.Equal("no-cache", values.First()); diff --git a/src/Middleware/Session/src/SessionMiddleware.cs b/src/Middleware/Session/src/SessionMiddleware.cs index fd7fd6532407..5810de51bca0 100644 --- a/src/Middleware/Session/src/SessionMiddleware.cs +++ b/src/Middleware/Session/src/SessionMiddleware.cs @@ -161,7 +161,7 @@ private void SetCookie() response.Cookies.Append(_options.Cookie.Name, _cookieValue, cookieOptions); var responseHeaders = response.Headers; - responseHeaders[HeaderNames.CacheControl] = "no-cache"; + responseHeaders[HeaderNames.CacheControl] = "no-cache,no-store"; responseHeaders[HeaderNames.Pragma] = "no-cache"; responseHeaders[HeaderNames.Expires] = "-1"; } diff --git a/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs b/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs index 25e0e3d0398b..5a0d63d95d13 100644 --- a/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs +++ b/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies public class CookieAuthenticationHandler : SignInAuthenticationHandler { private const string HeaderValueNoCache = "no-cache"; + private const string HeaderValueNoCacheNoStore = "no-cache,no-store"; private const string HeaderValueEpocDate = "Thu, 01 Jan 1970 00:00:00 GMT"; private const string SessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId"; @@ -374,7 +375,7 @@ protected async override Task HandleSignOutAsync(AuthenticationProperties proper private async Task ApplyHeaders(bool shouldRedirectToReturnUrl, AuthenticationProperties properties) { - Response.Headers[HeaderNames.CacheControl] = HeaderValueNoCache; + Response.Headers[HeaderNames.CacheControl] = HeaderValueNoCacheNoStore; Response.Headers[HeaderNames.Pragma] = HeaderValueNoCache; Response.Headers[HeaderNames.Expires] = HeaderValueEpocDate; diff --git a/src/Security/Authentication/test/CookieTests.cs b/src/Security/Authentication/test/CookieTests.cs index 44775187129f..e1a3840e193e 100644 --- a/src/Security/Authentication/test/CookieTests.cs +++ b/src/Security/Authentication/test/CookieTests.cs @@ -138,6 +138,9 @@ public async Task SignInCausesDefaultCookieToBeCreated() Assert.DoesNotContain("; expires=", setCookie); Assert.DoesNotContain("; domain=", setCookie); Assert.DoesNotContain("; secure", setCookie); + Assert.True(transaction.Response.Headers.CacheControl.NoCache); + Assert.True(transaction.Response.Headers.CacheControl.NoStore); + Assert.Equal("no-cache", transaction.Response.Headers.Pragma.ToString()); } [Fact] diff --git a/src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs b/src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs index 3d5e1f6f4bd5..450299bda302 100644 --- a/src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs +++ b/src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs @@ -35,7 +35,8 @@ public ServerSentEventsServerTransport(PipeReader application, string connection public async Task ProcessRequestAsync(HttpContext context, CancellationToken token) { context.Response.ContentType = "text/event-stream"; - context.Response.Headers[HeaderNames.CacheControl] = "no-cache"; + context.Response.Headers[HeaderNames.CacheControl] = "no-cache,no-store"; + context.Response.Headers[HeaderNames.Pragma] = "no-cache"; // Make sure we disable all response buffering for SSE var bufferingFeature = context.Features.Get(); diff --git a/src/SignalR/common/Http.Connections/test/ServerSentEventsTests.cs b/src/SignalR/common/Http.Connections/test/ServerSentEventsTests.cs index 4d53761699c1..85d929e8b9c6 100644 --- a/src/SignalR/common/Http.Connections/test/ServerSentEventsTests.cs +++ b/src/SignalR/common/Http.Connections/test/ServerSentEventsTests.cs @@ -31,7 +31,8 @@ public async Task SSESetsContentType() await sse.ProcessRequestAsync(context, context.RequestAborted); Assert.Equal("text/event-stream", context.Response.ContentType); - Assert.Equal("no-cache", context.Response.Headers["Cache-Control"]); + Assert.Equal("no-cache,no-store", context.Response.Headers["Cache-Control"]); + Assert.Equal("no-cache", context.Response.Headers["Pragma"]); } }