Add options to configure case sensitivity of request paths

This commit is contained in:
John Luo 2016-09-02 16:03:07 -07:00
parent 0f711ce279
commit 411681e8d6
3 changed files with 53 additions and 7 deletions

View File

@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Internal for testing // Internal for testing
internal ResponseCachingContext( internal ResponseCachingContext(
HttpContext httpContext, HttpContext httpContext,
IResponseCache cache, IResponseCache cache,
ResponseCachingOptions options, ResponseCachingOptions options,
ObjectPool<StringBuilder> builderPool, ObjectPool<StringBuilder> builderPool,
@ -149,11 +149,11 @@ namespace Microsoft.AspNetCore.ResponseCaching
.Append(KeyDelimiter); .Append(KeyDelimiter);
} }
// Default key // Default key
builder builder
.Append(request.Method.ToUpperInvariant()) .Append(request.Method.ToUpperInvariant())
.Append(KeyDelimiter) .Append(KeyDelimiter)
.Append(request.Path.Value.ToUpperInvariant()); .Append(_options.CaseSensitivePaths ? request.Path.Value : request.Path.Value.ToUpperInvariant());
// Vary by headers // Vary by headers
if (varyBy?.Headers.Count > 0) if (varyBy?.Headers.Count > 0)
@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
} }
// TODO: public MAY override the cacheability checks for private and status codes // TODO: public MAY override the cacheability checks for private and status codes
// Check private // Check private
if (ResponseCacheControl.Private) if (ResponseCacheControl.Private)
{ {
@ -365,7 +365,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
internal bool EntryIsFresh(ResponseHeaders responseHeaders, TimeSpan age, bool verifyAgainstRequest) internal bool EntryIsFresh(ResponseHeaders responseHeaders, TimeSpan age, bool verifyAgainstRequest)
{ {
var responseCacheControl = responseHeaders.CacheControl ?? EmptyCacheControl; var responseCacheControl = responseHeaders.CacheControl ?? EmptyCacheControl;
// Add min-fresh requirements // Add min-fresh requirements
if (verifyAgainstRequest) if (verifyAgainstRequest)
{ {

View File

@ -9,10 +9,15 @@ namespace Microsoft.AspNetCore.Builder
public class ResponseCachingOptions public class ResponseCachingOptions
{ {
/// <summary> /// <summary>
/// The largest cacheable size for the response body in bytes. /// The largest cacheable size for the response body in bytes. The default is set to 1 MB.
/// </summary> /// </summary>
public long MaximumCachedBodySize { get; set; } = 1024 * 1024; public long MaximumCachedBodySize { get; set; } = 1024 * 1024;
/// <summary>
/// <c>true</c> if request paths are case-sensitive; otherwise <c>false</c>. The default is to treat paths as case-insensitive.
/// </summary>
public bool CaseSensitivePaths { get; set; } = false;
/// <summary> /// <summary>
/// For testing purposes only. /// For testing purposes only.
/// </summary> /// </summary>

View File

@ -280,6 +280,34 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
})); }));
} }
[Fact]
public void CreateCacheKey_CaseInsensitivePath_NormalizesPath()
{
var httpContext = new DefaultHttpContext();
httpContext.Request.Method = "GET";
httpContext.Request.Path = "/Path";
var context = CreateTestContext(httpContext, new ResponseCachingOptions()
{
CaseSensitivePaths = false
});
Assert.Equal($"GET{KeyDelimiter}/PATH", context.CreateCacheKey());
}
[Fact]
public void CreateCacheKey_CaseSensitivePath_PreservesPathCase()
{
var httpContext = new DefaultHttpContext();
httpContext.Request.Method = "GET";
httpContext.Request.Path = "/Path";
var context = CreateTestContext(httpContext, new ResponseCachingOptions()
{
CaseSensitivePaths = true
});
Assert.Equal($"GET{KeyDelimiter}/Path", context.CreateCacheKey());
}
[Fact] [Fact]
public void ResponseIsCacheable_NoPublic_NotAllowed() public void ResponseIsCacheable_NoPublic_NotAllowed()
{ {
@ -832,6 +860,16 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{ {
return CreateTestContext( return CreateTestContext(
httpContext, httpContext,
new ResponseCachingOptions(),
new NoopCacheKeyModifier(),
new NoopCacheabilityValidator());
}
private static ResponseCachingContext CreateTestContext(HttpContext httpContext, ResponseCachingOptions options)
{
return CreateTestContext(
httpContext,
options,
new NoopCacheKeyModifier(), new NoopCacheKeyModifier(),
new NoopCacheabilityValidator()); new NoopCacheabilityValidator());
} }
@ -840,6 +878,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{ {
return CreateTestContext( return CreateTestContext(
httpContext, httpContext,
new ResponseCachingOptions(),
cacheKeyModifier, cacheKeyModifier,
new NoopCacheabilityValidator()); new NoopCacheabilityValidator());
} }
@ -848,19 +887,21 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{ {
return CreateTestContext( return CreateTestContext(
httpContext, httpContext,
new ResponseCachingOptions(),
new NoopCacheKeyModifier(), new NoopCacheKeyModifier(),
cacheabilityValidator); cacheabilityValidator);
} }
private static ResponseCachingContext CreateTestContext( private static ResponseCachingContext CreateTestContext(
HttpContext httpContext, HttpContext httpContext,
ResponseCachingOptions options,
IResponseCachingCacheKeyModifier cacheKeyModifier, IResponseCachingCacheKeyModifier cacheKeyModifier,
IResponseCachingCacheabilityValidator cacheabilityValidator) IResponseCachingCacheabilityValidator cacheabilityValidator)
{ {
return new ResponseCachingContext( return new ResponseCachingContext(
httpContext, httpContext,
new TestResponseCache(), new TestResponseCache(),
new ResponseCachingOptions(), options,
new DefaultObjectPool<StringBuilder>(new StringBuilderPooledObjectPolicy()), new DefaultObjectPool<StringBuilder>(new StringBuilderPooledObjectPolicy()),
cacheabilityValidator, cacheabilityValidator,
cacheKeyModifier); cacheKeyModifier);