diff --git a/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCachingTests.cs index c867115dc4..f2a014b707 100644 --- a/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCachingTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -16,8 +17,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests { public class ResponseCachingTests { - [Fact] - public async void ServesCachedContent_IfAvailable() + [Theory] + [InlineData("GET")] + [InlineData("HEAD")] + public async void ServesCachedContent_IfAvailable(string method) { var builders = TestUtils.CreateBuildersWithResponseCaching(); @@ -26,16 +29,18 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests using (var server = new TestServer(builder)) { var client = server.CreateClient(); - var initialResponse = await client.GetAsync(""); - var subsequentResponse = await client.GetAsync(""); + var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); + var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); await AssertCachedResponseAsync(initialResponse, subsequentResponse); } } } - [Fact] - public async void ServesFreshContent_IfNotAvailable() + [Theory] + [InlineData("GET")] + [InlineData("HEAD")] + public async void ServesFreshContent_IfNotAvailable(string method) { var builders = TestUtils.CreateBuildersWithResponseCaching(); @@ -44,8 +49,169 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests using (var server = new TestServer(builder)) { var client = server.CreateClient(); - var initialResponse = await client.GetAsync(""); - var subsequentResponse = await client.GetAsync("/different"); + var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); + var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, "different")); + + await AssertFreshResponseAsync(initialResponse, subsequentResponse); + } + } + } + + [Fact] + public async void ServesFreshContent_Post() + { + var builders = TestUtils.CreateBuildersWithResponseCaching(); + + foreach (var builder in builders) + { + using (var server = new TestServer(builder)) + { + var client = server.CreateClient(); + var initialResponse = await client.PostAsync("", new StringContent(string.Empty)); + var subsequentResponse = await client.PostAsync("", new StringContent(string.Empty)); + + await AssertFreshResponseAsync(initialResponse, subsequentResponse); + } + } + } + + [Fact] + public async void ServesFreshContent_Head_Get() + { + var builders = TestUtils.CreateBuildersWithResponseCaching(); + + foreach (var builder in builders) + { + using (var server = new TestServer(builder)) + { + var client = server.CreateClient(); + var subsequentResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, "")); + var initialResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "")); + + await AssertFreshResponseAsync(initialResponse, subsequentResponse); + } + } + } + + [Fact] + public async void ServesFreshContent_Get_Head() + { + var builders = TestUtils.CreateBuildersWithResponseCaching(); + + foreach (var builder in builders) + { + using (var server = new TestServer(builder)) + { + var client = server.CreateClient(); + var initialResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "")); + var subsequentResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, "")); + + await AssertFreshResponseAsync(initialResponse, subsequentResponse); + } + } + } + + [Theory] + [InlineData("GET")] + [InlineData("HEAD")] + public async void ServesFreshContent_If_CacheControlNoCache(string method) + { + var builders = TestUtils.CreateBuildersWithResponseCaching(); + + foreach (var builder in builders) + { + using (var server = new TestServer(builder)) + { + var client = server.CreateClient(); + client.DefaultRequestHeaders.CacheControl = + new System.Net.Http.Headers.CacheControlHeaderValue { NoCache = true }; + + var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); + var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); + + await AssertFreshResponseAsync(initialResponse, subsequentResponse); + } + } + } + + [Theory] + [InlineData("GET")] + [InlineData("HEAD")] + public async void ServesFreshContent_If_PragmaNoCache(string method) + { + var builders = TestUtils.CreateBuildersWithResponseCaching(); + + foreach (var builder in builders) + { + using (var server = new TestServer(builder)) + { + var client = server.CreateClient(); + client.DefaultRequestHeaders.Pragma.Clear(); + client.DefaultRequestHeaders.Pragma.Add(new System.Net.Http.Headers.NameValueHeaderValue("no-cache")); + + var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); + var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); + + await AssertFreshResponseAsync(initialResponse, subsequentResponse); + } + } + } + + [Theory] + [InlineData("GET")] + [InlineData("HEAD")] + public async void ServesCachedContent_If_PathCasingDiffers(string method) + { + var builders = TestUtils.CreateBuildersWithResponseCaching(); + + foreach (var builder in builders) + { + using (var server = new TestServer(builder)) + { + var client = server.CreateClient(); + var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, "path")); + var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, "PATH")); + + await AssertCachedResponseAsync(initialResponse, subsequentResponse); + } + } + } + + [Theory] + [InlineData("GET")] + [InlineData("HEAD")] + public async void ServesFreshContent_If_ResponseExpired(string method) + { + var builders = TestUtils.CreateBuildersWithResponseCaching(); + + foreach (var builder in builders) + { + using (var server = new TestServer(builder)) + { + var client = server.CreateClient(); + var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, "?Expires=0")); + var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); + + await AssertFreshResponseAsync(initialResponse, subsequentResponse); + } + } + } + + [Theory] + [InlineData("GET")] + [InlineData("HEAD")] + public async void ServesFreshContent_If_Authorization_HeaderExists(string method) + { + var builders = TestUtils.CreateBuildersWithResponseCaching(); + + foreach (var builder in builders) + { + using (var server = new TestServer(builder)) + { + var client = server.CreateClient(); + client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("abc"); + var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); + var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, "")); await AssertFreshResponseAsync(initialResponse, subsequentResponse); } @@ -706,7 +872,17 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests subsequentResponse.EnsureSuccessStatusCode(); Assert.False(subsequentResponse.Headers.Contains(HeaderNames.Age)); - Assert.NotEqual(await initialResponse.Content.ReadAsStringAsync(), await subsequentResponse.Content.ReadAsStringAsync()); + + if (initialResponse.RequestMessage.Method == HttpMethod.Head && + subsequentResponse.RequestMessage.Method == HttpMethod.Head) + { + Assert.True(initialResponse.Headers.Contains("X-Value")); + Assert.NotEqual(initialResponse.Headers.GetValues("X-Value"), subsequentResponse.Headers.GetValues("X-Value")); + } + else + { + Assert.NotEqual(await initialResponse.Content.ReadAsStringAsync(), await subsequentResponse.Content.ReadAsStringAsync()); + } } } } diff --git a/test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs b/test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs index f4f9125e82..b50be5b175 100644 --- a/test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs +++ b/test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; @@ -30,18 +31,29 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests StreamUtilities.BodySegmentSize = 10; } - internal static RequestDelegate TestRequestDelegate = async (context) => + internal static RequestDelegate TestRequestDelegate = async context => { - var uniqueId = Guid.NewGuid().ToString(); var headers = context.Response.GetTypedHeaders(); - headers.CacheControl = new CacheControlHeaderValue() + + var expires = context.Request.Query["Expires"]; + if (!string.IsNullOrEmpty(expires)) + { + headers.Expires = DateTimeOffset.Now.AddSeconds(int.Parse(expires)); + } + + var uniqueId = Guid.NewGuid().ToString(); + headers.CacheControl = new CacheControlHeaderValue { Public = true, - MaxAge = TimeSpan.FromSeconds(10) + MaxAge = string.IsNullOrEmpty(expires) ? TimeSpan.FromSeconds(10) : (TimeSpan?)null }; headers.Date = DateTimeOffset.UtcNow; headers.Headers["X-Value"] = uniqueId; - await context.Response.WriteAsync(uniqueId); + + if (context.Request.Method != "HEAD") + { + await context.Response.WriteAsync(uniqueId); + } }; internal static IResponseCachingKeyProvider CreateTestKeyProvider() @@ -148,6 +160,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests Assert.Equal(expectedMessages[i].LogLevel, messages[i].LogLevel); } } + + public static HttpRequestMessage CreateRequest(string method, string requestUri) + { + return new HttpRequestMessage(new HttpMethod(method), requestUri); + } } internal class LoggedMessage