API review renames and updates continued

- Consolidate base key to be singular
This commit is contained in:
John Luo 2016-09-14 15:20:48 -07:00
parent ccfa090e6e
commit 6c13371fa0
29 changed files with 555 additions and 586 deletions

View File

@ -20,7 +20,7 @@ namespace ResponseCachingSample
public void Configure(IApplicationBuilder app)
{
app.UseResponseCaching();
app.UseResponseCache();
app.Run(async (context) =>
{
// These settings should be configured by context.Response.Cache.*

View File

@ -42,8 +42,8 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
// Serialization Format
// Format version (int)
// Type (char: 'B' for CachedResponseBody, 'R' for CachedResponse, 'V' for CachedVaryRules)
// Type-dependent data (see CachedResponse and CachedVaryRules)
// Type (char: 'B' for CachedResponseBody, 'R' for CachedResponse, 'V' for CachedVaryByRules)
// Type-dependent data (see CachedResponse and CachedVaryByRules)
public static object Read(BinaryReader reader)
{
if (reader == null)
@ -68,10 +68,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
}
else if (type == 'V')
{
return ReadCachedVaryRules(reader);
return ReadCachedVaryByRules(reader);
}
// Unable to read as CachedResponse or CachedVaryRules
// Unable to read as CachedResponse or CachedVaryByRules
return null;
}
@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
// Header(s) (comma separated string)
// Params count
// Param(s) (comma separated string)
private static CachedVaryRules ReadCachedVaryRules(BinaryReader reader)
private static CachedVaryByRules ReadCachedVaryByRules(BinaryReader reader)
{
var varyKeyPrefix = reader.ReadString();
@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
param[index] = reader.ReadString();
}
return new CachedVaryRules { VaryKeyPrefix = varyKeyPrefix, Headers = headers, Params = param };
return new CachedVaryByRules { VaryByKeyPrefix = varyKeyPrefix, Headers = headers, Params = param };
}
// See serialization format above
@ -174,10 +174,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
writer.Write('R');
WriteCachedResponse(writer, entry as CachedResponse);
}
else if (entry is CachedVaryRules)
else if (entry is CachedVaryByRules)
{
writer.Write('V');
WriteCachedVaryRules(writer, entry as CachedVaryRules);
WriteCachedVaryByRules(writer, entry as CachedVaryByRules);
}
else
{
@ -218,18 +218,18 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
}
// See serialization format above
private static void WriteCachedVaryRules(BinaryWriter writer, CachedVaryRules varyRules)
private static void WriteCachedVaryByRules(BinaryWriter writer, CachedVaryByRules varyByRules)
{
writer.Write(varyRules.VaryKeyPrefix);
writer.Write(varyByRules.VaryByKeyPrefix);
writer.Write(varyRules.Headers.Count);
foreach (var header in varyRules.Headers)
writer.Write(varyByRules.Headers.Count);
foreach (var header in varyByRules.Headers)
{
writer.Write(header);
}
writer.Write(varyRules.Params.Count);
foreach (var param in varyRules.Params)
writer.Write(varyByRules.Params.Count);
foreach (var param in varyByRules.Params)
{
writer.Write(param);
}

View File

@ -8,14 +8,14 @@ namespace Microsoft.AspNetCore.ResponseCaching
{
public class CachedResponse
{
public string BodyKeyPrefix { get; internal set; }
public string BodyKeyPrefix { get; set; }
public DateTimeOffset Created { get; internal set; }
public DateTimeOffset Created { get; set; }
public int StatusCode { get; internal set; }
public int StatusCode { get; set; }
public IHeaderDictionary Headers { get; internal set; } = new HeaderDictionary();
public IHeaderDictionary Headers { get; set; } = new HeaderDictionary();
public byte[] Body { get; internal set; }
public byte[] Body { get; set; }
}
}

View File

@ -5,6 +5,6 @@ namespace Microsoft.AspNetCore.ResponseCaching
{
public class CachedResponseBody
{
public byte[] Body { get; internal set; }
public byte[] Body { get; set; }
}
}

View File

@ -5,12 +5,12 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.ResponseCaching
{
public class CachedVaryRules
public class CachedVaryByRules
{
public string VaryKeyPrefix { get; internal set; }
public string VaryByKeyPrefix { get; set; }
public StringValues Headers { get; internal set; }
public StringValues Headers { get; set; }
public StringValues Params { get; internal set; }
public StringValues Params { get; set; }
}
}

View File

@ -7,19 +7,19 @@ using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder
{
public static class ResponseCachingExtensions
public static class ResponseCacheExtensions
{
public static IApplicationBuilder UseResponseCaching(this IApplicationBuilder app)
public static IApplicationBuilder UseResponseCache(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<ResponseCachingMiddleware>();
return app.UseMiddleware<ResponseCacheMiddleware>();
}
public static IApplicationBuilder UseResponseCaching(this IApplicationBuilder app, ResponseCachingOptions options)
public static IApplicationBuilder UseResponseCache(this IApplicationBuilder app, ResponseCacheOptions options)
{
if (app == null)
{
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Builder
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<ResponseCachingMiddleware>(Options.Create(options));
return app.UseMiddleware<ResponseCacheMiddleware>(Options.Create(options));
}
}
}

View File

@ -6,11 +6,11 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.ResponseCaching
{
// TODO: Temporary interface for endpoints to specify options for response caching
public static class ResponseCachingHttpContextExtensions
public static class ResponseCacheHttpContextExtensions
{
public static ResponseCachingFeature GetResponseCachingFeature(this HttpContext httpContext)
public static ResponseCacheFeature GetResponseCacheFeature(this HttpContext httpContext)
{
return httpContext.Features.Get<ResponseCachingFeature>();
return httpContext.Features.Get<ResponseCacheFeature>();
}
}
}

View File

@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ResponseCachingServiceCollectionExtensions
public static class ResponseCacheServiceCollectionExtensions
{
public static IServiceCollection AddMemoryResponseCache(this IServiceCollection services)
{
@ -18,8 +18,8 @@ namespace Microsoft.Extensions.DependencyInjection
}
services.AddMemoryCache();
services.AddResponseCachingServices();
services.TryAdd(ServiceDescriptor.Singleton<IResponseCache, MemoryResponseCache>());
services.AddResponseCacheServices();
services.TryAdd(ServiceDescriptor.Singleton<IResponseCacheStore, MemoryResponseCacheStore>());
return services;
}
@ -32,16 +32,16 @@ namespace Microsoft.Extensions.DependencyInjection
}
services.AddDistributedMemoryCache();
services.AddResponseCachingServices();
services.TryAdd(ServiceDescriptor.Singleton<IResponseCache, DistributedResponseCache>());
services.AddResponseCacheServices();
services.TryAdd(ServiceDescriptor.Singleton<IResponseCacheStore, DistributedResponseCacheStore>());
return services;
}
private static IServiceCollection AddResponseCachingServices(this IServiceCollection services)
private static IServiceCollection AddResponseCacheServices(this IServiceCollection services)
{
services.TryAdd(ServiceDescriptor.Singleton<ICacheKeyProvider, CacheKeyProvider>());
services.TryAdd(ServiceDescriptor.Singleton<ICacheabilityValidator, CacheabilityValidator>());
services.TryAdd(ServiceDescriptor.Singleton<IResponseCacheKeyProvider, ResponseCacheKeyProvider>());
services.TryAdd(ServiceDescriptor.Singleton<IResponseCachePolicyProvider, ResponseCachePolicyProvider>());
return services;
}

View File

@ -1,38 +0,0 @@
// 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.Collections.Generic;
namespace Microsoft.AspNetCore.ResponseCaching
{
public interface ICacheKeyProvider
{
/// <summary>
/// Create a base key for storing items.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns>The created base key.</returns>
string CreateStorageBaseKey(ResponseCachingContext context);
/// <summary>
/// Create one or more base keys for looking up items.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns>An ordered <see cref="IEnumerable{T}"/> containing the base keys to try when looking up items.</returns>
IEnumerable<string> CreateLookupBaseKeys(ResponseCachingContext context);
/// <summary>
/// Create a vary key for storing items.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns>The created vary key.</returns>
string CreateStorageVaryKey(ResponseCachingContext context);
/// <summary>
/// Create one or more vary keys for looking up items.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns>An ordered <see cref="IEnumerable{T}"/> containing the vary keys to try when looking up items.</returns>
IEnumerable<string> CreateLookupVaryKeys(ResponseCachingContext context);
}
}

View File

@ -1,29 +0,0 @@
// 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.
namespace Microsoft.AspNetCore.ResponseCaching
{
public interface ICacheabilityValidator
{
/// <summary>
/// Determine the cacheability of an HTTP request.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns><c>true</c> if the request is cacheable; otherwise <c>false</c>.</returns>
bool IsRequestCacheable(ResponseCachingContext context);
/// <summary>
/// Determine the cacheability of an HTTP response.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns><c>true</c> if the response is cacheable; otherwise <c>false</c>.</returns>
bool IsResponseCacheable(ResponseCachingContext context);
/// <summary>
/// Determine the freshness of the cached entry.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns><c>true</c> if the cached entry is fresh; otherwise <c>false</c>.</returns>
bool IsCachedEntryFresh(ResponseCachingContext context);
}
}

View File

@ -0,0 +1,31 @@
// 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.Collections.Generic;
namespace Microsoft.AspNetCore.ResponseCaching
{
public interface IResponseCacheKeyProvider
{
/// <summary>
/// Create a base key for a response cache entry.
/// </summary>
/// <param name="context">The <see cref="ResponseCacheContext"/>.</param>
/// <returns>The created base key.</returns>
string CreateBaseKey(ResponseCacheContext context);
/// <summary>
/// Create a vary key for storing cached responses.
/// </summary>
/// <param name="context">The <see cref="ResponseCacheContext"/>.</param>
/// <returns>The created vary key.</returns>
string CreateStorageVaryByKey(ResponseCacheContext context);
/// <summary>
/// Create one or more vary keys for looking up cached responses.
/// </summary>
/// <param name="context">The <see cref="ResponseCacheContext"/>.</param>
/// <returns>An ordered <see cref="IEnumerable{T}"/> containing the vary keys to try when looking up items.</returns>
IEnumerable<string> CreateLookupVaryByKeys(ResponseCacheContext context);
}
}

View File

@ -0,0 +1,29 @@
// 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.
namespace Microsoft.AspNetCore.ResponseCaching
{
public interface IResponseCachePolicyProvider
{
/// <summary>
/// Determine wehther the response cache middleware should be executed for the incoming HTTP request.
/// </summary>
/// <param name="context">The <see cref="ResponseCacheContext"/>.</param>
/// <returns><c>true</c> if the request is cacheable; otherwise <c>false</c>.</returns>
bool IsRequestCacheable(ResponseCacheContext context);
/// <summary>
/// Determine whether the response received by the middleware be cached for future requests.
/// </summary>
/// <param name="context">The <see cref="ResponseCacheContext"/>.</param>
/// <returns><c>true</c> if the response is cacheable; otherwise <c>false</c>.</returns>
bool IsResponseCacheable(ResponseCacheContext context);
/// <summary>
/// Determine whether the response retrieved from the response cache is fresh and be served.
/// </summary>
/// <param name="context">The <see cref="ResponseCacheContext"/>.</param>
/// <returns><c>true</c> if the cached entry is fresh; otherwise <c>false</c>.</returns>
bool IsCachedEntryFresh(ResponseCacheContext context);
}
}

View File

@ -5,7 +5,7 @@ using System;
namespace Microsoft.AspNetCore.ResponseCaching
{
public interface IResponseCache
public interface IResponseCacheStore
{
object Get(string key);
void Set(string key, object entry, TimeSpan validFor);

View File

@ -6,11 +6,11 @@ using Microsoft.Extensions.Caching.Distributed;
namespace Microsoft.AspNetCore.ResponseCaching.Internal
{
internal class DistributedResponseCache : IResponseCache
public class DistributedResponseCacheStore : IResponseCacheStore
{
private readonly IDistributedCache _cache;
public DistributedResponseCache(IDistributedCache cache)
public DistributedResponseCacheStore(IDistributedCache cache)
{
if (cache == null)
{

View File

@ -8,18 +8,18 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
{
internal static class InternalHttpContextExtensions
{
internal static void AddResponseCachingFeature(this HttpContext httpContext)
internal static void AddResponseCacheFeature(this HttpContext httpContext)
{
if (httpContext.GetResponseCachingFeature() != null)
if (httpContext.GetResponseCacheFeature() != null)
{
throw new InvalidOperationException($"Another instance of {nameof(ResponseCachingFeature)} already exists. Only one instance of {nameof(ResponseCachingMiddleware)} can be configured for an application.");
throw new InvalidOperationException($"Another instance of {nameof(ResponseCacheFeature)} already exists. Only one instance of {nameof(ResponseCacheMiddleware)} can be configured for an application.");
}
httpContext.Features.Set(new ResponseCachingFeature());
httpContext.Features.Set(new ResponseCacheFeature());
}
internal static void RemoveResponseCachingFeature(this HttpContext httpContext)
internal static void RemoveResponseCacheFeature(this HttpContext httpContext)
{
httpContext.Features.Set<ResponseCachingFeature>(null);
httpContext.Features.Set<ResponseCacheFeature>(null);
}
}
}

View File

@ -6,11 +6,11 @@ using Microsoft.Extensions.Caching.Memory;
namespace Microsoft.AspNetCore.ResponseCaching.Internal
{
internal class MemoryResponseCache : IResponseCache
public class MemoryResponseCacheStore : IResponseCacheStore
{
private readonly IMemoryCache _cache;
public MemoryResponseCache(IMemoryCache cache)
public MemoryResponseCacheStore(IMemoryCache cache)
{
if (cache == null)
{

View File

@ -11,7 +11,7 @@ using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.ResponseCaching
{
public class ResponseCachingContext
public class ResponseCacheContext
{
private static readonly CacheControlHeaderValue EmptyCacheControl = new CacheControlHeaderValue();
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
private CacheControlHeaderValue _requestCacheControl;
private CacheControlHeaderValue _responseCacheControl;
internal ResponseCachingContext(
internal ResponseCacheContext(
HttpContext httpContext)
{
HttpContext = httpContext;
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
public bool ShouldCacheResponse { get; internal set; }
public string StorageBaseKey { get; internal set; }
public string BaseKey { get; internal set; }
public string StorageVaryKey { get; internal set; }
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
public CachedResponse CachedResponse { get; internal set; }
public CachedVaryRules CachedVaryRules { get; internal set; }
public CachedVaryByRules CachedVaryByRules { get; internal set; }
internal bool ResponseStarted { get; set; }

View File

@ -6,8 +6,8 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.ResponseCaching
{
// TODO: Temporary interface for endpoints to specify options for response caching
public class ResponseCachingFeature
public class ResponseCacheFeature
{
public StringValues VaryParams { get; set; }
public StringValues VaryByParams { get; set; }
}
}

View File

@ -12,15 +12,15 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.ResponseCaching
{
public class CacheKeyProvider : ICacheKeyProvider
public class ResponseCacheKeyProvider : IResponseCacheKeyProvider
{
// Use the record separator for delimiting components of the cache key to avoid possible collisions
private static readonly char KeyDelimiter = '\x1e';
private readonly ObjectPool<StringBuilder> _builderPool;
private readonly ResponseCachingOptions _options;
private readonly ResponseCacheOptions _options;
public CacheKeyProvider(ObjectPoolProvider poolProvider, IOptions<ResponseCachingOptions> options)
public ResponseCacheKeyProvider(ObjectPoolProvider poolProvider, IOptions<ResponseCacheOptions> options)
{
if (poolProvider == null)
{
@ -35,18 +35,13 @@ namespace Microsoft.AspNetCore.ResponseCaching
_options = options.Value;
}
public virtual IEnumerable<string> CreateLookupBaseKeys(ResponseCachingContext context)
public virtual IEnumerable<string> CreateLookupVaryByKeys(ResponseCacheContext context)
{
return new string[] { CreateStorageBaseKey(context) };
}
public virtual IEnumerable<string> CreateLookupVaryKeys(ResponseCachingContext context)
{
return new string[] { CreateStorageVaryKey(context) };
return new string[] { CreateStorageVaryByKey(context) };
}
// GET<delimiter>/PATH
public virtual string CreateStorageBaseKey(ResponseCachingContext context)
public virtual string CreateBaseKey(ResponseCacheContext context)
{
if (context == null)
{
@ -61,7 +56,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
builder
.Append(request.Method.ToUpperInvariant())
.Append(KeyDelimiter)
.Append(_options.CaseSensitivePaths ? request.Path.Value : request.Path.Value.ToUpperInvariant());
.Append(_options.UseCaseSensitivePaths ? request.Path.Value : request.Path.Value.ToUpperInvariant());
return builder.ToString();;
}
@ -72,22 +67,22 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
// BaseKey<delimiter>H<delimiter>HeaderName=HeaderValue<delimiter>Q<delimiter>QueryName=QueryValue
public virtual string CreateStorageVaryKey(ResponseCachingContext context)
public virtual string CreateStorageVaryByKey(ResponseCacheContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var varyRules = context.CachedVaryRules;
if (varyRules == null)
var varyByRules = context.CachedVaryByRules;
if (varyByRules == null)
{
throw new InvalidOperationException($"{nameof(CachedVaryRules)} must not be null on the {nameof(ResponseCachingContext)}");
throw new InvalidOperationException($"{nameof(CachedVaryByRules)} must not be null on the {nameof(ResponseCacheContext)}");
}
if ((StringValues.IsNullOrEmpty(varyRules.Headers) && StringValues.IsNullOrEmpty(varyRules.Params)))
if ((StringValues.IsNullOrEmpty(varyByRules.Headers) && StringValues.IsNullOrEmpty(varyByRules.Params)))
{
return varyRules.VaryKeyPrefix;
return varyByRules.VaryByKeyPrefix;
}
var request = context.HttpContext.Request;
@ -95,17 +90,17 @@ namespace Microsoft.AspNetCore.ResponseCaching
try
{
// Prepend with the Guid of the CachedVaryRules
builder.Append(varyRules.VaryKeyPrefix);
// Prepend with the Guid of the CachedVaryByRules
builder.Append(varyByRules.VaryByKeyPrefix);
// Vary by headers
if (varyRules?.Headers.Count > 0)
if (varyByRules?.Headers.Count > 0)
{
// Append a group separator for the header segment of the cache key
builder.Append(KeyDelimiter)
.Append('H');
foreach (var header in varyRules.Headers)
foreach (var header in varyByRules.Headers)
{
builder.Append(KeyDelimiter)
.Append(header)
@ -116,13 +111,13 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
// Vary by query params
if (varyRules?.Params.Count > 0)
if (varyByRules?.Params.Count > 0)
{
// Append a group separator for the query parameter segment of the cache key
builder.Append(KeyDelimiter)
.Append('Q');
if (varyRules.Params.Count == 1 && string.Equals(varyRules.Params[0], "*", StringComparison.Ordinal))
if (varyByRules.Params.Count == 1 && string.Equals(varyByRules.Params[0], "*", StringComparison.Ordinal))
{
// Vary by all available query params
foreach (var query in context.HttpContext.Request.Query.OrderBy(q => q.Key, StringComparer.OrdinalIgnoreCase))
@ -135,7 +130,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
else
{
foreach (var param in varyRules.Params)
foreach (var param in varyByRules.Params)
{
builder.Append(KeyDelimiter)
.Append(param)

View File

@ -16,63 +16,63 @@ using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.ResponseCaching
{
public class ResponseCachingMiddleware
public class ResponseCacheMiddleware
{
private static readonly TimeSpan DefaultExpirationTimeSpan = TimeSpan.FromSeconds(10);
private readonly RequestDelegate _next;
private readonly IResponseCache _cache;
private readonly ResponseCachingOptions _options;
private readonly ICacheabilityValidator _cacheabilityValidator;
private readonly ICacheKeyProvider _cacheKeyProvider;
private readonly IResponseCacheStore _store;
private readonly ResponseCacheOptions _options;
private readonly IResponseCachePolicyProvider _policyProvider;
private readonly IResponseCacheKeyProvider _keyProvider;
private readonly Func<object, Task> _onStartingCallback;
public ResponseCachingMiddleware(
public ResponseCacheMiddleware(
RequestDelegate next,
IResponseCache cache,
IOptions<ResponseCachingOptions> options,
ICacheabilityValidator cacheabilityValidator,
ICacheKeyProvider cacheKeyProvider)
IResponseCacheStore store,
IOptions<ResponseCacheOptions> options,
IResponseCachePolicyProvider policyProvider,
IResponseCacheKeyProvider keyProvider)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (cache == null)
if (store == null)
{
throw new ArgumentNullException(nameof(cache));
throw new ArgumentNullException(nameof(store));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (cacheabilityValidator == null)
if (policyProvider == null)
{
throw new ArgumentNullException(nameof(cacheabilityValidator));
throw new ArgumentNullException(nameof(policyProvider));
}
if (cacheKeyProvider == null)
if (keyProvider == null)
{
throw new ArgumentNullException(nameof(cacheKeyProvider));
throw new ArgumentNullException(nameof(keyProvider));
}
_next = next;
_cache = cache;
_store = store;
_options = options.Value;
_cacheabilityValidator = cacheabilityValidator;
_cacheKeyProvider = cacheKeyProvider;
_policyProvider = policyProvider;
_keyProvider = keyProvider;
_onStartingCallback = state =>
{
OnResponseStarting((ResponseCachingContext)state);
OnResponseStarting((ResponseCacheContext)state);
return TaskCache.CompletedTask;
};
}
public async Task Invoke(HttpContext httpContext)
{
var context = new ResponseCachingContext(httpContext);
var context = new ResponseCacheContext(httpContext);
// Should we attempt any caching logic?
if (_cacheabilityValidator.IsRequestCacheable(context))
if (_policyProvider.IsRequestCacheable(context))
{
// Can this request be served from cache?
if (await TryServeFromCacheAsync(context))
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
OnResponseStarting(context);
// Finalize the cache entry
FinalizeCachingBody(context);
FinalizeCacheBody(context);
}
finally
{
@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
}
internal async Task<bool> TryServeCachedResponseAsync(ResponseCachingContext context, CachedResponse cachedResponse)
internal async Task<bool> TryServeCachedResponseAsync(ResponseCacheContext context, CachedResponse cachedResponse)
{
context.CachedResponse = cachedResponse;
context.CachedResponseHeaders = new ResponseHeaders(cachedResponse.Headers);
@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
var cachedEntryAge = context.ResponseTime - context.CachedResponse.Created;
context.CachedEntryAge = cachedEntryAge > TimeSpan.Zero ? cachedEntryAge : TimeSpan.Zero;
if (_cacheabilityValidator.IsCachedEntryFresh(context))
if (_policyProvider.IsCachedEntryFresh(context))
{
// Check conditional request rules
if (ConditionalRequestSatisfied(context))
@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
response.Headers[HeaderNames.Age] = context.CachedEntryAge.TotalSeconds.ToString("F0", CultureInfo.InvariantCulture);
var body = context.CachedResponse.Body ??
((CachedResponseBody)_cache.Get(context.CachedResponse.BodyKeyPrefix))?.Body;
((CachedResponseBody)_store.Get(context.CachedResponse.BodyKeyPrefix))?.Body;
// If the body is not found, something went wrong.
if (body == null)
@ -166,32 +166,30 @@ namespace Microsoft.AspNetCore.ResponseCaching
return false;
}
internal async Task<bool> TryServeFromCacheAsync(ResponseCachingContext context)
internal async Task<bool> TryServeFromCacheAsync(ResponseCacheContext context)
{
foreach (var baseKey in _cacheKeyProvider.CreateLookupBaseKeys(context))
context.BaseKey = _keyProvider.CreateBaseKey(context);
var cacheEntry = _store.Get(context.BaseKey);
if (cacheEntry is CachedVaryByRules)
{
var cacheEntry = _cache.Get(baseKey);
// Request contains vary rules, recompute key(s) and try again
context.CachedVaryByRules = (CachedVaryByRules)cacheEntry;
if (cacheEntry is CachedVaryRules)
foreach (var varyKey in _keyProvider.CreateLookupVaryByKeys(context))
{
// Request contains vary rules, recompute key(s) and try again
context.CachedVaryRules = (CachedVaryRules)cacheEntry;
cacheEntry = _store.Get(varyKey);
foreach (var varyKey in _cacheKeyProvider.CreateLookupVaryKeys(context))
if (cacheEntry is CachedResponse && await TryServeCachedResponseAsync(context, (CachedResponse)cacheEntry))
{
cacheEntry = _cache.Get(varyKey);
if (cacheEntry is CachedResponse && await TryServeCachedResponseAsync(context, (CachedResponse)cacheEntry))
{
return true;
}
return true;
}
}
}
if (cacheEntry is CachedResponse && await TryServeCachedResponseAsync(context, (CachedResponse)cacheEntry))
{
return true;
}
if (cacheEntry is CachedResponse && await TryServeCachedResponseAsync(context, (CachedResponse)cacheEntry))
{
return true;
}
@ -204,17 +202,17 @@ namespace Microsoft.AspNetCore.ResponseCaching
return false;
}
internal void FinalizeCachingHeaders(ResponseCachingContext context)
internal void FinalizeCacheHeaders(ResponseCacheContext context)
{
if (_cacheabilityValidator.IsResponseCacheable(context))
if (_policyProvider.IsResponseCacheable(context))
{
context.ShouldCacheResponse = true;
context.StorageBaseKey = _cacheKeyProvider.CreateStorageBaseKey(context);
context.BaseKey = _keyProvider.CreateBaseKey(context);
// Create the cache entry now
var response = context.HttpContext.Response;
var varyHeaderValue = response.Headers[HeaderNames.Vary];
var varyParamsValue = context.HttpContext.GetResponseCachingFeature()?.VaryParams ?? StringValues.Empty;
var varyParamsValue = context.HttpContext.GetResponseCacheFeature()?.VaryByParams ?? StringValues.Empty;
context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ??
context.ResponseCacheControlHeaderValue.MaxAge ??
(context.TypedResponseHeaders.Expires - context.ResponseTime) ??
@ -228,21 +226,21 @@ namespace Microsoft.AspNetCore.ResponseCaching
var normalizedVaryParamsValue = GetNormalizedStringValues(varyParamsValue);
// Update vary rules if they are different
if (context.CachedVaryRules == null ||
!StringValues.Equals(context.CachedVaryRules.Params, normalizedVaryParamsValue) ||
!StringValues.Equals(context.CachedVaryRules.Headers, normalizedVaryHeaderValue))
if (context.CachedVaryByRules == null ||
!StringValues.Equals(context.CachedVaryByRules.Params, normalizedVaryParamsValue) ||
!StringValues.Equals(context.CachedVaryByRules.Headers, normalizedVaryHeaderValue))
{
context.CachedVaryRules = new CachedVaryRules
context.CachedVaryByRules = new CachedVaryByRules
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = normalizedVaryHeaderValue,
Params = normalizedVaryParamsValue
};
_cache.Set(context.StorageBaseKey, context.CachedVaryRules, context.CachedResponseValidFor);
_store.Set(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor);
}
context.StorageVaryKey = _cacheKeyProvider.CreateStorageVaryKey(context);
context.StorageVaryKey = _keyProvider.CreateStorageVaryByKey(context);
}
// Ensure date header is set
@ -273,7 +271,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
}
internal void FinalizeCachingBody(ResponseCachingContext context)
internal void FinalizeCacheBody(ResponseCacheContext context)
{
if (context.ShouldCacheResponse &&
context.ResponseCacheStream.BufferingEnabled &&
@ -283,36 +281,36 @@ namespace Microsoft.AspNetCore.ResponseCaching
if (context.ResponseCacheStream.BufferedStream.Length >= _options.MinimumSplitBodySize)
{
// Store response and response body separately
_cache.Set(context.StorageVaryKey ?? context.StorageBaseKey, context.CachedResponse, context.CachedResponseValidFor);
_store.Set(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor);
var cachedResponseBody = new CachedResponseBody()
{
Body = context.ResponseCacheStream.BufferedStream.ToArray()
};
_cache.Set(context.CachedResponse.BodyKeyPrefix, cachedResponseBody, context.CachedResponseValidFor);
_store.Set(context.CachedResponse.BodyKeyPrefix, cachedResponseBody, context.CachedResponseValidFor);
}
else
{
// Store response and response body together
context.CachedResponse.Body = context.ResponseCacheStream.BufferedStream.ToArray();
_cache.Set(context.StorageVaryKey ?? context.StorageBaseKey, context.CachedResponse, context.CachedResponseValidFor);
_store.Set(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor);
}
}
}
internal void OnResponseStarting(ResponseCachingContext context)
internal void OnResponseStarting(ResponseCacheContext context)
{
if (!context.ResponseStarted)
{
context.ResponseStarted = true;
context.ResponseTime = _options.SystemClock.UtcNow;
FinalizeCachingHeaders(context);
FinalizeCacheHeaders(context);
}
}
internal void ShimResponseStream(ResponseCachingContext context)
internal void ShimResponseStream(ResponseCacheContext context)
{
// TODO: Consider caching large responses on disk and serving them from there.
@ -329,10 +327,10 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
// TODO: Move this temporary interface with endpoint to HttpAbstractions
context.HttpContext.AddResponseCachingFeature();
context.HttpContext.AddResponseCacheFeature();
}
internal static void UnshimResponseStream(ResponseCachingContext context)
internal static void UnshimResponseStream(ResponseCacheContext context)
{
// Unshim response stream
context.HttpContext.Response.Body = context.OriginalResponseStream;
@ -341,10 +339,10 @@ namespace Microsoft.AspNetCore.ResponseCaching
context.HttpContext.Features.Set(context.OriginalSendFileFeature);
// TODO: Move this temporary interface with endpoint to HttpAbstractions
context.HttpContext.RemoveResponseCachingFeature();
context.HttpContext.RemoveResponseCacheFeature();
}
internal static bool ConditionalRequestSatisfied(ResponseCachingContext context)
internal static bool ConditionalRequestSatisfied(ResponseCacheContext context)
{
var cachedResponseHeaders = context.CachedResponseHeaders;
var ifNoneMatchHeader = context.TypedRequestHeaders.IfNoneMatch;

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.ResponseCaching.Internal;
namespace Microsoft.AspNetCore.Builder
{
public class ResponseCachingOptions
public class ResponseCacheOptions
{
/// <summary>
/// The largest cacheable size for the response body in bytes. The default is set to 1 MB.
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Builder
/// <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;
public bool UseCaseSensitivePaths { get; set; } = false;
/// <summary>
/// The smallest size in bytes for which the headers and body of the response will be stored separately. The default is set to 70 KB.

View File

@ -3,17 +3,16 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Headers;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.ResponseCaching
{
public class CacheabilityValidator : ICacheabilityValidator
public class ResponseCachePolicyProvider : IResponseCachePolicyProvider
{
private static readonly CacheControlHeaderValue EmptyCacheControl = new CacheControlHeaderValue();
public virtual bool IsRequestCacheable(ResponseCachingContext context)
public virtual bool IsRequestCacheable(ResponseCacheContext context)
{
// Verify the method
// TODO: RFC lists POST as a cacheable method when explicit freshness information is provided, but this is not widely implemented. Will revisit.
@ -57,7 +56,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
return true;
}
public virtual bool IsResponseCacheable(ResponseCachingContext context)
public virtual bool IsResponseCacheable(ResponseCacheContext context)
{
// Only cache pages explicitly marked with public
// TODO: Consider caching responses that are not marked as public but otherwise cacheable?
@ -150,7 +149,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
return true;
}
public virtual bool IsCachedEntryFresh(ResponseCachingContext context)
public virtual bool IsCachedEntryFresh(ResponseCacheContext context)
{
var age = context.CachedEntryAge;
var cachedControlHeaders = context.CachedResponseHeaders.CacheControl ?? EmptyCacheControl;

View File

@ -77,67 +77,67 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}
[Fact]
public void RoundTrip_CachedVaryRule_EmptyRules_Succeeds()
public void RoundTrip_CachedVaryByRule_EmptyRules_Succeeds()
{
var cachedVaryRule = new CachedVaryRules()
var cachedVaryByRule = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString
VaryByKeyPrefix = FastGuid.NewGuid().IdString
};
AssertCachedVaryRuleEqual(cachedVaryRule, (CachedVaryRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryRule)));
AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule)));
}
[Fact]
public void RoundTrip_CachedVaryRule_HeadersOnly_Succeeds()
public void RoundTrip_CachedVaryByRule_HeadersOnly_Succeeds()
{
var headers = new[] { "headerA", "headerB" };
var cachedVaryRule = new CachedVaryRules()
var cachedVaryByRule = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = headers
};
AssertCachedVaryRuleEqual(cachedVaryRule, (CachedVaryRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryRule)));
AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule)));
}
[Fact]
public void RoundTrip_CachedVaryRule_ParamsOnly_Succeeds()
public void RoundTrip_CachedVaryByRule_ParamsOnly_Succeeds()
{
var param = new[] { "paramA", "paramB" };
var cachedVaryRule = new CachedVaryRules()
var cachedVaryByRule = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = param
};
AssertCachedVaryRuleEqual(cachedVaryRule, (CachedVaryRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryRule)));
AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule)));
}
[Fact]
public void RoundTrip_CachedVaryRule_HeadersAndParams_Succeeds()
public void RoundTrip_CachedVaryByRule_HeadersAndParams_Succeeds()
{
var headers = new[] { "headerA", "headerB" };
var param = new[] { "paramA", "paramB" };
var cachedVaryRule = new CachedVaryRules()
var cachedVaryByRule = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = headers,
Params = param
};
AssertCachedVaryRuleEqual(cachedVaryRule, (CachedVaryRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryRule)));
AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule)));
}
[Fact]
public void Deserialize_InvalidEntries_ReturnsNull()
{
var headers = new[] { "headerA", "headerB" };
var cachedVaryRule = new CachedVaryRules()
var cachedVaryByRule = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = headers
};
var serializedEntry = CacheEntrySerializer.Serialize(cachedVaryRule);
var serializedEntry = CacheEntrySerializer.Serialize(cachedVaryByRule);
Array.Reverse(serializedEntry);
Assert.Null(CacheEntrySerializer.Deserialize(serializedEntry));
@ -170,11 +170,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}
}
private static void AssertCachedVaryRuleEqual(CachedVaryRules expected, CachedVaryRules actual)
private static void AssertCachedVaryByRuleEqual(CachedVaryByRules expected, CachedVaryByRules actual)
{
Assert.NotNull(actual);
Assert.NotNull(expected);
Assert.Equal(expected.VaryKeyPrefix, actual.VaryKeyPrefix);
Assert.Equal(expected.VaryByKeyPrefix, actual.VaryByKeyPrefix);
Assert.Equal(expected.Headers, actual.Headers);
Assert.Equal(expected.Params, actual.Params);
}

View File

@ -11,15 +11,15 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
public class HttpContextInternalExtensionTests
{
[Fact]
public void AddingSecondResponseCachingFeature_Throws()
public void AddingSecondResponseCacheFeature_Throws()
{
var httpContext = new DefaultHttpContext();
// Should not throw
httpContext.AddResponseCachingFeature();
httpContext.AddResponseCacheFeature();
// Should throw
Assert.ThrowsAny<InvalidOperationException>(() => httpContext.AddResponseCachingFeature());
Assert.ThrowsAny<InvalidOperationException>(() => httpContext.AddResponseCacheFeature());
}
}
}

View File

@ -9,12 +9,12 @@ using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
public class DefaultKeyProviderTests
public class ResponseCacheKeyProviderTests
{
private static readonly char KeyDelimiter = '\x1e';
[Fact]
public void DefaultKeyProvider_CreateStorageBaseKey_IncludesOnlyNormalizedMethodAndPath()
public void ResponseCacheKeyProvider_CreateStorageBaseKey_IncludesOnlyNormalizedMethodAndPath()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
@ -25,142 +25,142 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.HttpContext.Request.PathBase = "/pathBase";
context.HttpContext.Request.QueryString = new QueryString("?query.Key=a&query.Value=b");
Assert.Equal($"HEAD{KeyDelimiter}/PATH/SUBPATH", cacheKeyProvider.CreateStorageBaseKey(context));
Assert.Equal($"HEAD{KeyDelimiter}/PATH/SUBPATH", cacheKeyProvider.CreateBaseKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageBaseKey_CaseInsensitivePath_NormalizesPath()
public void ResponseCacheKeyProvider_CreateStorageBaseKey_CaseInsensitivePath_NormalizesPath()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(new ResponseCachingOptions()
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(new ResponseCacheOptions()
{
CaseSensitivePaths = false
UseCaseSensitivePaths = false
});
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = "GET";
context.HttpContext.Request.Path = "/Path";
Assert.Equal($"GET{KeyDelimiter}/PATH", cacheKeyProvider.CreateStorageBaseKey(context));
Assert.Equal($"GET{KeyDelimiter}/PATH", cacheKeyProvider.CreateBaseKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageBaseKey_CaseSensitivePath_PreservesPathCase()
public void ResponseCacheKeyProvider_CreateStorageBaseKey_CaseSensitivePath_PreservesPathCase()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(new ResponseCachingOptions()
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(new ResponseCacheOptions()
{
CaseSensitivePaths = true
UseCaseSensitivePaths = true
});
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = "GET";
context.HttpContext.Request.Path = "/Path";
Assert.Equal($"GET{KeyDelimiter}/Path", cacheKeyProvider.CreateStorageBaseKey(context));
Assert.Equal($"GET{KeyDelimiter}/Path", cacheKeyProvider.CreateBaseKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageVaryKey_Throws_IfVaryRulesIsNull()
public void ResponseCacheKeyProvider_CreateStorageVaryByKey_Throws_IfVaryByRulesIsNull()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
Assert.Throws<InvalidOperationException>(() => cacheKeyProvider.CreateStorageVaryKey(context));
Assert.Throws<InvalidOperationException>(() => cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageVaryKey_ReturnsCachedVaryGuid_IfVaryRulesIsEmpty()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_ReturnsCachedVaryByGuid_IfVaryByRulesIsEmpty()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.CachedVaryRules = new CachedVaryRules()
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString
VaryByKeyPrefix = FastGuid.NewGuid().IdString
};
Assert.Equal($"{context.CachedVaryRules.VaryKeyPrefix}", cacheKeyProvider.CreateStorageVaryKey(context));
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}", cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageVaryKey_IncludesListedHeadersOnly()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedHeadersOnly()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Headers["HeaderA"] = "ValueA";
context.HttpContext.Request.Headers["HeaderB"] = "ValueB";
context.CachedVaryRules = new CachedVaryRules()
context.CachedVaryByRules = new CachedVaryByRules()
{
Headers = new string[] { "HeaderA", "HeaderC" }
};
Assert.Equal($"{context.CachedVaryRules.VaryKeyPrefix}{KeyDelimiter}H{KeyDelimiter}HeaderA=ValueA{KeyDelimiter}HeaderC=",
cacheKeyProvider.CreateStorageVaryKey(context));
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}H{KeyDelimiter}HeaderA=ValueA{KeyDelimiter}HeaderC=",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageVaryKey_IncludesListedParamsOnly()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedParamsOnly()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.QueryString = new QueryString("?ParamA=ValueA&ParamB=ValueB");
context.CachedVaryRules = new CachedVaryRules()
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = new string[] { "ParamA", "ParamC" }
};
Assert.Equal($"{context.CachedVaryRules.VaryKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
cacheKeyProvider.CreateStorageVaryKey(context));
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageVaryKey_IncludesParams_ParamNameCaseInsensitive_UseParamCasing()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesParams_ParamNameCaseInsensitive_UseParamCasing()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.QueryString = new QueryString("?parama=ValueA&paramB=ValueB");
context.CachedVaryRules = new CachedVaryRules()
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = new string[] { "ParamA", "ParamC" }
};
Assert.Equal($"{context.CachedVaryRules.VaryKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
cacheKeyProvider.CreateStorageVaryKey(context));
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageVaryKey_IncludesAllQueryParamsGivenAsterisk()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesAllQueryParamsGivenAsterisk()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.QueryString = new QueryString("?ParamA=ValueA&ParamB=ValueB");
context.CachedVaryRules = new CachedVaryRules()
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = new string[] { "*" }
};
// To support case insensitivity, all param keys are converted to upper case.
// Explicit params uses the casing specified in the setting.
Assert.Equal($"{context.CachedVaryRules.VaryKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}PARAMA=ValueA{KeyDelimiter}PARAMB=ValueB",
cacheKeyProvider.CreateStorageVaryKey(context));
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}PARAMA=ValueA{KeyDelimiter}PARAMB=ValueB",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void DefaultKeyProvider_CreateStorageVaryKey_IncludesListedHeadersAndParams()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedHeadersAndParams()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Headers["HeaderA"] = "ValueA";
context.HttpContext.Request.Headers["HeaderB"] = "ValueB";
context.HttpContext.Request.QueryString = new QueryString("?ParamA=ValueA&ParamB=ValueB");
context.CachedVaryRules = new CachedVaryRules()
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = new string[] { "HeaderA", "HeaderC" },
Params = new string[] { "ParamA", "ParamC" }
};
Assert.Equal($"{context.CachedVaryRules.VaryKeyPrefix}{KeyDelimiter}H{KeyDelimiter}HeaderA=ValueA{KeyDelimiter}HeaderC={KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
cacheKeyProvider.CreateStorageVaryKey(context));
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}H{KeyDelimiter}HeaderA=ValueA{KeyDelimiter}HeaderC={KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
}
}

View File

@ -14,13 +14,13 @@ using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
public class ResponseCachingMiddlewareTests
public class ResponseCacheMiddlewareTests
{
[Fact]
public async Task TryServeFromCacheAsync_OnlyIfCached_Serves504()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(responseCache: cache, cacheKeyProvider: new TestKeyProvider());
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store: store, keyProvider: new TestResponseCacheKeyProvider());
var context = TestUtils.CreateTestContext();
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
{
@ -34,23 +34,23 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async Task TryServeFromCacheAsync_CachedResponseNotFound_Fails()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(responseCache: cache, cacheKeyProvider: new TestKeyProvider(new[] { "BaseKey", "BaseKey2" }));
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey"));
var context = TestUtils.CreateTestContext();
Assert.False(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(2, cache.GetCount);
Assert.Equal(1, store.GetCount);
}
[Fact]
public async Task TryServeFromCacheAsync_CachedResponseFound_Succeeds()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(responseCache: cache, cacheKeyProvider: new TestKeyProvider(new[] { "BaseKey", "BaseKey2" }));
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey"));
var context = TestUtils.CreateTestContext();
cache.Set(
"BaseKey2",
store.Set(
"BaseKey",
new CachedResponse()
{
Body = new byte[0]
@ -58,38 +58,38 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
TimeSpan.Zero);
Assert.True(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(2, cache.GetCount);
Assert.Equal(1, store.GetCount);
}
[Fact]
public async Task TryServeFromCacheAsync_VaryRuleFound_CachedResponseNotFound_Fails()
public async Task TryServeFromCacheAsync_VaryByRuleFound_CachedResponseNotFound_Fails()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(responseCache: cache, cacheKeyProvider: new TestKeyProvider(new[] { "BaseKey", "BaseKey2" }));
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey"));
var context = TestUtils.CreateTestContext();
cache.Set(
"BaseKey2",
new CachedVaryRules(),
store.Set(
"BaseKey",
new CachedVaryByRules(),
TimeSpan.Zero);
Assert.False(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(2, cache.GetCount);
Assert.Equal(1, store.GetCount);
}
[Fact]
public async Task TryServeFromCacheAsync_VaryRuleFound_CachedResponseFound_Succeeds()
public async Task TryServeFromCacheAsync_VaryByRuleFound_CachedResponseFound_Succeeds()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(responseCache: cache, cacheKeyProvider: new TestKeyProvider(new[] { "BaseKey", "BaseKey2" }, new[] { "VaryKey", "VaryKey2" }));
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey", new[] { "VaryKey", "VaryKey2" }));
var context = TestUtils.CreateTestContext();
cache.Set(
"BaseKey2",
new CachedVaryRules(),
store.Set(
"BaseKey",
new CachedVaryByRules(),
TimeSpan.Zero);
cache.Set(
"BaseKey2VaryKey2",
store.Set(
"BaseKeyVaryKey2",
new CachedResponse()
{
Body = new byte[0]
@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
TimeSpan.Zero);
Assert.True(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(6, cache.GetCount);
Assert.Equal(3, store.GetCount);
}
[Fact]
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var context = TestUtils.CreateTestContext();
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary());
Assert.False(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.False(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
}
[Fact]
@ -120,15 +120,15 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
// Verify modifications in the past succeeds
context.CachedResponseHeaders.Date = utcNow - TimeSpan.FromSeconds(10);
Assert.True(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.True(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
// Verify modifications at present succeeds
context.CachedResponseHeaders.Date = utcNow;
Assert.True(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.True(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
// Verify modifications in the future fails
context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10);
Assert.False(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.False(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
}
[Fact]
@ -143,17 +143,17 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
// Verify modifications in the past succeeds
context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10);
context.CachedResponseHeaders.LastModified = utcNow - TimeSpan.FromSeconds(10);
Assert.True(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.True(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
// Verify modifications at present
context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10);
context.CachedResponseHeaders.LastModified = utcNow;
Assert.True(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.True(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
// Verify modifications in the future fails
context.CachedResponseHeaders.Date = utcNow - TimeSpan.FromSeconds(10);
context.CachedResponseHeaders.LastModified = utcNow + TimeSpan.FromSeconds(10);
Assert.False(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.False(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
}
[Fact]
@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.CachedResponseHeaders.LastModified = utcNow + TimeSpan.FromSeconds(10);
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { EntityTagHeaderValue.Any });
Assert.True(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.True(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
}
[Fact]
@ -183,7 +183,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.CachedResponseHeaders.LastModified = utcNow - TimeSpan.FromSeconds(10);
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") });
Assert.False(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.False(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
}
[Fact]
@ -194,7 +194,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") });
Assert.False(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.False(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
}
[Fact]
@ -208,7 +208,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") });
Assert.True(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.True(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
}
[Fact]
@ -222,27 +222,27 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") });
Assert.False(ResponseCachingMiddleware.ConditionalRequestSatisfied(context));
Assert.False(ResponseCacheMiddleware.ConditionalRequestSatisfied(context));
}
[Fact]
public void FinalizeCachingHeaders_DoNotUpdateShouldCacheResponse_IfResponseIsNotCacheable()
public void FinalizeCacheHeaders_DoNotUpdateShouldCacheResponse_IfResponseIsNotCacheable()
{
var middleware = TestUtils.CreateTestMiddleware(cacheabilityValidator: new CacheabilityValidator());
var middleware = TestUtils.CreateTestMiddleware(policyProvider: new ResponseCachePolicyProvider());
var context = TestUtils.CreateTestContext();
Assert.False(context.ShouldCacheResponse);
middleware.ShimResponseStream(context);
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.False(context.ShouldCacheResponse);
}
[Fact]
public void FinalizeCachingHeaders_UpdateShouldCacheResponse_IfResponseIsCacheable()
public void FinalizeCacheHeaders_UpdateShouldCacheResponse_IfResponseIsCacheable()
{
var middleware = TestUtils.CreateTestMiddleware(cacheabilityValidator: new CacheabilityValidator());
var middleware = TestUtils.CreateTestMiddleware(policyProvider: new ResponseCachePolicyProvider());
var context = TestUtils.CreateTestContext();
context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue()
{
@ -251,24 +251,24 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Assert.False(context.ShouldCacheResponse);
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.True(context.ShouldCacheResponse);
}
[Fact]
public void FinalizeCachingHeaders_DefaultResponseValidity_Is10Seconds()
public void FinalizeCacheHeaders_DefaultResponseValidity_Is10Seconds()
{
var middleware = TestUtils.CreateTestMiddleware();
var context = TestUtils.CreateTestContext();
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.Equal(TimeSpan.FromSeconds(10), context.CachedResponseValidFor);
}
[Fact]
public void FinalizeCachingHeaders_ResponseValidity_UseExpiryIfAvailable()
public void FinalizeCacheHeaders_ResponseValidity_UseExpiryIfAvailable()
{
var utcNow = DateTimeOffset.MinValue;
var middleware = TestUtils.CreateTestMiddleware();
@ -277,13 +277,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.ResponseTime = utcNow;
context.TypedResponseHeaders.Expires = utcNow + TimeSpan.FromSeconds(11);
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.Equal(TimeSpan.FromSeconds(11), context.CachedResponseValidFor);
}
[Fact]
public void FinalizeCachingHeaders_ResponseValidity_UseMaxAgeIfAvailable()
public void FinalizeCacheHeaders_ResponseValidity_UseMaxAgeIfAvailable()
{
var middleware = TestUtils.CreateTestMiddleware();
var context = TestUtils.CreateTestContext();
@ -295,13 +295,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.ResponseTime = DateTimeOffset.UtcNow;
context.TypedResponseHeaders.Expires = context.ResponseTime + TimeSpan.FromSeconds(11);
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.Equal(TimeSpan.FromSeconds(12), context.CachedResponseValidFor);
}
[Fact]
public void FinalizeCachingHeaders_ResponseValidity_UseSharedMaxAgeIfAvailable()
public void FinalizeCacheHeaders_ResponseValidity_UseSharedMaxAgeIfAvailable()
{
var middleware = TestUtils.CreateTestMiddleware();
var context = TestUtils.CreateTestContext();
@ -314,60 +314,60 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.ResponseTime = DateTimeOffset.UtcNow;
context.TypedResponseHeaders.Expires = context.ResponseTime + TimeSpan.FromSeconds(11);
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.Equal(TimeSpan.FromSeconds(13), context.CachedResponseValidFor);
}
[Fact]
public void FinalizeCachingHeaders_UpdateCachedVaryRules_IfNotEquivalentToPrevious()
public void FinalizeCacheHeaders_UpdateCachedVaryByRules_IfNotEquivalentToPrevious()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(cache);
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store);
var context = TestUtils.CreateTestContext();
context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB", "HEADERc" });
context.HttpContext.AddResponseCachingFeature();
context.HttpContext.GetResponseCachingFeature().VaryParams = new StringValues(new[] { "paramB", "PARAMAA" });
var cachedVaryRules = new CachedVaryRules()
context.HttpContext.AddResponseCacheFeature();
context.HttpContext.GetResponseCacheFeature().VaryByParams = new StringValues(new[] { "paramB", "PARAMAA" });
var cachedVaryByRules = new CachedVaryByRules()
{
Headers = new StringValues(new[] { "HeaderA", "HeaderB" }),
Params = new StringValues(new[] { "ParamA", "ParamB" })
};
context.CachedVaryRules = cachedVaryRules;
context.CachedVaryByRules = cachedVaryByRules;
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.Equal(1, cache.SetCount);
Assert.NotSame(cachedVaryRules, context.CachedVaryRules);
Assert.Equal(1, store.SetCount);
Assert.NotSame(cachedVaryByRules, context.CachedVaryByRules);
}
[Fact]
public void FinalizeCachingHeaders_DoNotUpdateCachedVaryRules_IfEquivalentToPrevious()
public void FinalizeCacheHeaders_DoNotUpdateCachedVaryByRules_IfEquivalentToPrevious()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(cache);
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store);
var context = TestUtils.CreateTestContext();
context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB" });
context.HttpContext.AddResponseCachingFeature();
context.HttpContext.GetResponseCachingFeature().VaryParams = new StringValues(new[] { "paramB", "PARAMA" });
var cachedVaryRules = new CachedVaryRules()
context.HttpContext.AddResponseCacheFeature();
context.HttpContext.GetResponseCacheFeature().VaryByParams = new StringValues(new[] { "paramB", "PARAMA" });
var cachedVaryByRules = new CachedVaryByRules()
{
VaryKeyPrefix = FastGuid.NewGuid().IdString,
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = new StringValues(new[] { "HEADERA", "HEADERB" }),
Params = new StringValues(new[] { "PARAMA", "PARAMB" })
};
context.CachedVaryRules = cachedVaryRules;
context.CachedVaryByRules = cachedVaryByRules;
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.Equal(0, cache.SetCount);
Assert.Same(cachedVaryRules, context.CachedVaryRules);
Assert.Equal(0, store.SetCount);
Assert.Same(cachedVaryByRules, context.CachedVaryByRules);
}
[Fact]
public void FinalizeCachingHeaders_DoNotAddDate_IfSpecified()
public void FinalizeCacheHeaders_DoNotAddDate_IfSpecified()
{
var utcNow = DateTimeOffset.MinValue;
var middleware = TestUtils.CreateTestMiddleware();
@ -376,13 +376,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Assert.Null(context.TypedResponseHeaders.Date);
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.Equal(utcNow, context.TypedResponseHeaders.Date);
}
[Fact]
public void FinalizeCachingHeaders_AddsDate_IfNoneSpecified()
public void FinalizeCacheHeaders_AddsDate_IfNoneSpecified()
{
var utcNow = DateTimeOffset.MinValue;
var middleware = TestUtils.CreateTestMiddleware();
@ -392,29 +392,29 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Assert.Equal(utcNow, context.TypedResponseHeaders.Date);
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.Equal(utcNow, context.TypedResponseHeaders.Date);
}
[Fact]
public void FinalizeCachingHeaders_StoresCachedResponse_InState()
public void FinalizeCacheHeaders_StoresCachedResponse_InState()
{
var middleware = TestUtils.CreateTestMiddleware();
var context = TestUtils.CreateTestContext();
Assert.Null(context.CachedResponse);
middleware.FinalizeCachingHeaders(context);
middleware.FinalizeCacheHeaders(context);
Assert.NotNull(context.CachedResponse);
}
[Fact]
public async Task FinalizeCachingBody_StoreResponseBodySeparately_IfLargerThanLimit()
public async Task FinalizeCacheBody_StoreResponseBodySeparately_IfLargerThanLimit()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(cache);
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store);
var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context);
@ -425,19 +425,19 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
BodyKeyPrefix = FastGuid.NewGuid().IdString
};
context.StorageBaseKey = "BaseKey";
context.BaseKey = "BaseKey";
context.CachedResponseValidFor = TimeSpan.FromSeconds(10);
middleware.FinalizeCachingBody(context);
middleware.FinalizeCacheBody(context);
Assert.Equal(2, cache.SetCount);
Assert.Equal(2, store.SetCount);
}
[Fact]
public async Task FinalizeCachingBody_StoreResponseBodyInCachedResponse_IfSmallerThanLimit()
public async Task FinalizeCacheBody_StoreResponseBodyInCachedResponse_IfSmallerThanLimit()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(cache);
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store);
var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context);
@ -448,19 +448,19 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
BodyKeyPrefix = FastGuid.NewGuid().IdString
};
context.StorageBaseKey = "BaseKey";
context.BaseKey = "BaseKey";
context.CachedResponseValidFor = TimeSpan.FromSeconds(10);
middleware.FinalizeCachingBody(context);
middleware.FinalizeCacheBody(context);
Assert.Equal(1, cache.SetCount);
Assert.Equal(1, store.SetCount);
}
[Fact]
public async Task FinalizeCachingBody_StoreResponseBodySeparately_LimitIsConfigurable()
public async Task FinalizeCacheBody_StoreResponseBodySeparately_LimitIsConfigurable()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(cache, new ResponseCachingOptions()
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store, new ResponseCacheOptions()
{
MinimumSplitBodySize = 2048
});
@ -474,19 +474,19 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
BodyKeyPrefix = FastGuid.NewGuid().IdString
};
context.StorageBaseKey = "BaseKey";
context.BaseKey = "BaseKey";
context.CachedResponseValidFor = TimeSpan.FromSeconds(10);
middleware.FinalizeCachingBody(context);
middleware.FinalizeCacheBody(context);
Assert.Equal(1, cache.SetCount);
Assert.Equal(1, store.SetCount);
}
[Fact]
public async Task FinalizeCachingBody_Cache_IfContentLengthMatches()
public async Task FinalizeCacheBody_Cache_IfContentLengthMatches()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(cache);
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store);
var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context);
@ -498,19 +498,19 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
BodyKeyPrefix = FastGuid.NewGuid().IdString
};
context.StorageBaseKey = "BaseKey";
context.BaseKey = "BaseKey";
context.CachedResponseValidFor = TimeSpan.FromSeconds(10);
middleware.FinalizeCachingBody(context);
middleware.FinalizeCacheBody(context);
Assert.Equal(1, cache.SetCount);
Assert.Equal(1, store.SetCount);
}
[Fact]
public async Task FinalizeCachingBody_DoNotCache_IfContentLengthMismatches()
public async Task FinalizeCacheBody_DoNotCache_IfContentLengthMismatches()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(cache);
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store);
var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context);
@ -522,19 +522,19 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
BodyKeyPrefix = FastGuid.NewGuid().IdString
};
context.StorageBaseKey = "BaseKey";
context.BaseKey = "BaseKey";
context.CachedResponseValidFor = TimeSpan.FromSeconds(10);
middleware.FinalizeCachingBody(context);
middleware.FinalizeCacheBody(context);
Assert.Equal(0, cache.SetCount);
Assert.Equal(0, store.SetCount);
}
[Fact]
public async Task FinalizeCachingBody_Cache_IfContentLengthAbsent()
public async Task FinalizeCacheBody_Cache_IfContentLengthAbsent()
{
var cache = new TestResponseCache();
var middleware = TestUtils.CreateTestMiddleware(cache);
var store = new TestResponseCacheStore();
var middleware = TestUtils.CreateTestMiddleware(store);
var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context);
@ -545,12 +545,12 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
BodyKeyPrefix = FastGuid.NewGuid().IdString
};
context.StorageBaseKey = "BaseKey";
context.BaseKey = "BaseKey";
context.CachedResponseValidFor = TimeSpan.FromSeconds(10);
middleware.FinalizeCachingBody(context);
middleware.FinalizeCacheBody(context);
Assert.Equal(1, cache.SetCount);
Assert.Equal(1, store.SetCount);
}
[Fact]
@ -559,7 +559,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var uppercaseStrings = new StringValues(new[] { "STRINGA", "STRINGB" });
var lowercaseStrings = new StringValues(new[] { "stringA", "stringB" });
var normalizedStrings = ResponseCachingMiddleware.GetNormalizedStringValues(lowercaseStrings);
var normalizedStrings = ResponseCacheMiddleware.GetNormalizedStringValues(lowercaseStrings);
Assert.Equal(uppercaseStrings, normalizedStrings);
}
@ -570,9 +570,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var orderedStrings = new StringValues(new[] { "STRINGA", "STRINGB" });
var reverseOrderStrings = new StringValues(new[] { "STRINGB", "STRINGA" });
var normalizedStrings = ResponseCachingMiddleware.GetNormalizedStringValues(reverseOrderStrings);
var normalizedStrings = ResponseCacheMiddleware.GetNormalizedStringValues(reverseOrderStrings);
Assert.Equal(orderedStrings, normalizedStrings);
}
}
}

View File

@ -9,17 +9,17 @@ using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
public class CacheabilityValidatorTests
public class ResponseCachePolicyProviderTests
{
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
public void RequestIsCacheable_CacheableMethods_Allowed(string method)
public void IsRequestCacheable_CacheableMethods_Allowed(string method)
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = method;
Assert.True(new CacheabilityValidator().IsRequestCacheable(context));
Assert.True(new ResponseCachePolicyProvider().IsRequestCacheable(context));
}
[Theory]
@ -31,26 +31,26 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[InlineData("CONNECT")]
[InlineData("")]
[InlineData(null)]
public void RequestIsCacheable_UncacheableMethods_NotAllowed(string method)
public void IsRequestCacheable_UncacheableMethods_NotAllowed(string method)
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = method;
Assert.False(new CacheabilityValidator().IsRequestCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsRequestCacheable(context));
}
[Fact]
public void RequestIsCacheable_AuthorizationHeaders_NotAllowed()
public void IsRequestCacheable_AuthorizationHeaders_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = "GET";
context.HttpContext.Request.Headers[HeaderNames.Authorization] = "Basic plaintextUN:plaintextPW";
Assert.False(new CacheabilityValidator().IsRequestCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsRequestCacheable(context));
}
[Fact]
public void RequestIsCacheable_NoCache_NotAllowed()
public void IsRequestCacheable_NoCache_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = "GET";
@ -59,11 +59,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
NoCache = true
};
Assert.False(new CacheabilityValidator().IsRequestCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsRequestCacheable(context));
}
[Fact]
public void RequestIsCacheable_NoStore_Allowed()
public void IsRequestCacheable_NoStore_Allowed()
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = "GET";
@ -72,40 +72,40 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
NoStore = true
};
Assert.True(new CacheabilityValidator().IsRequestCacheable(context));
Assert.True(new ResponseCachePolicyProvider().IsRequestCacheable(context));
}
[Fact]
public void RequestIsCacheable_LegacyDirectives_NotAllowed()
public void IsRequestCacheable_LegacyDirectives_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = "GET";
context.HttpContext.Request.Headers[HeaderNames.Pragma] = "no-cache";
Assert.False(new CacheabilityValidator().IsRequestCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsRequestCacheable(context));
}
[Fact]
public void RequestIsCacheable_LegacyDirectives_OverridenByCacheControl()
public void IsRequestCacheable_LegacyDirectives_OverridenByCacheControl()
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Method = "GET";
context.HttpContext.Request.Headers[HeaderNames.Pragma] = "no-cache";
context.HttpContext.Request.Headers[HeaderNames.CacheControl] = "max-age=10";
Assert.True(new CacheabilityValidator().IsRequestCacheable(context));
Assert.True(new ResponseCachePolicyProvider().IsRequestCacheable(context));
}
[Fact]
public void ResponseIsCacheable_NoPublic_NotAllowed()
public void IsResponseCacheable_NoPublic_NotAllowed()
{
var context = TestUtils.CreateTestContext();
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_Public_Allowed()
public void IsResponseCacheable_Public_Allowed()
{
var context = TestUtils.CreateTestContext();
context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue()
@ -113,11 +113,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Public = true
};
Assert.True(new CacheabilityValidator().IsResponseCacheable(context));
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_NoCache_NotAllowed()
public void IsResponseCacheable_NoCache_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue()
@ -126,11 +126,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
NoCache = true
};
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_RequestNoStore_NotAllowed()
public void IsResponseCacheable_RequestNoStore_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
@ -142,11 +142,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Public = true
};
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_ResponseNoStore_NotAllowed()
public void IsResponseCacheable_ResponseNoStore_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue()
@ -155,11 +155,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
NoStore = true
};
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_SetCookieHeader_NotAllowed()
public void IsResponseCacheable_SetCookieHeader_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue()
@ -168,11 +168,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
};
context.HttpContext.Response.Headers[HeaderNames.SetCookie] = "cookieName=cookieValue";
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_VaryHeaderByStar_NotAllowed()
public void IsResponseCacheable_VaryHeaderByStar_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue()
@ -181,11 +181,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
};
context.HttpContext.Response.Headers[HeaderNames.Vary] = "*";
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_Private_NotAllowed()
public void IsResponseCacheable_Private_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue()
@ -194,12 +194,12 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Private = true
};
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Theory]
[InlineData(StatusCodes.Status200OK)]
public void ResponseIsCacheable_SuccessStatusCodes_Allowed(int statusCode)
public void IsResponseCacheable_SuccessStatusCodes_Allowed(int statusCode)
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Response.StatusCode = statusCode;
@ -208,7 +208,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Public = true
};
Assert.True(new CacheabilityValidator().IsResponseCacheable(context));
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Theory]
@ -260,7 +260,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[InlineData(StatusCodes.Status505HttpVersionNotsupported)]
[InlineData(StatusCodes.Status506VariantAlsoNegotiates)]
[InlineData(StatusCodes.Status507InsufficientStorage)]
public void ResponseIsCacheable_NonSuccessStatusCodes_NotAllowed(int statusCode)
public void IsResponseCacheable_NonSuccessStatusCodes_NotAllowed(int statusCode)
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Response.StatusCode = statusCode;
@ -269,11 +269,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Public = true
};
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_NoExpiryRequirements_IsAllowed()
public void IsResponseCacheable_NoExpiryRequirements_IsAllowed()
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
@ -286,11 +286,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = DateTimeOffset.MaxValue;
Assert.True(new CacheabilityValidator().IsResponseCacheable(context));
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_PastExpiry_NotAllowed()
public void IsResponseCacheable_PastExpiry_NotAllowed()
{
var context = TestUtils.CreateTestContext();
context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
@ -304,11 +304,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = DateTimeOffset.MaxValue;
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_MaxAgeOverridesExpiry_ToAllowed()
public void IsResponseCacheable_MaxAgeOverridesExpiry_ToAllowed()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -322,11 +322,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow + TimeSpan.FromSeconds(9);
Assert.True(new CacheabilityValidator().IsResponseCacheable(context));
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_MaxAgeOverridesExpiry_ToNotAllowed()
public void IsResponseCacheable_MaxAgeOverridesExpiry_ToNotAllowed()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -340,11 +340,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow + TimeSpan.FromSeconds(11);
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_SharedMaxAgeOverridesMaxAge_ToAllowed()
public void IsResponseCacheable_SharedMaxAgeOverridesMaxAge_ToAllowed()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -358,11 +358,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow + TimeSpan.FromSeconds(11);
Assert.True(new CacheabilityValidator().IsResponseCacheable(context));
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void ResponseIsCacheable_SharedMaxAgeOverridesMaxAge_ToNotFresh()
public void IsResponseCacheable_SharedMaxAgeOverridesMaxAge_ToNotFresh()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -376,22 +376,22 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow + TimeSpan.FromSeconds(6);
Assert.False(new CacheabilityValidator().IsResponseCacheable(context));
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
}
[Fact]
public void EntryIsFresh_NoCachedCacheControl_FallsbackToEmptyCacheControl()
public void IsCachedEntryFresh_NoCachedCacheControl_FallsbackToEmptyCacheControl()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
context.ResponseTime = DateTimeOffset.MaxValue;
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary());
Assert.True(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_NoExpiryRequirements_IsFresh()
public void IsCachedEntryFresh_NoExpiryRequirements_IsFresh()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -404,11 +404,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}
};
Assert.True(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_PastExpiry_IsNotFresh()
public void IsCachedEntryFresh_PastExpiry_IsNotFresh()
{
var context = TestUtils.CreateTestContext();
context.ResponseTime = DateTimeOffset.MaxValue;
@ -421,11 +421,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = DateTimeOffset.UtcNow
};
Assert.False(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_MaxAgeOverridesExpiry_ToFresh()
public void IsCachedEntryFresh_MaxAgeOverridesExpiry_ToFresh()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -441,11 +441,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow
};
Assert.True(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_MaxAgeOverridesExpiry_ToNotFresh()
public void IsCachedEntryFresh_MaxAgeOverridesExpiry_ToNotFresh()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -461,11 +461,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow
};
Assert.False(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_SharedMaxAgeOverridesMaxAge_ToFresh()
public void IsCachedEntryFresh_SharedMaxAgeOverridesMaxAge_ToFresh()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -482,11 +482,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow
};
Assert.True(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_SharedMaxAgeOverridesMaxAge_ToNotFresh()
public void IsCachedEntryFresh_SharedMaxAgeOverridesMaxAge_ToNotFresh()
{
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
@ -503,11 +503,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow
};
Assert.False(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_MinFreshReducesFreshness_ToNotFresh()
public void IsCachedEntryFresh_MinFreshReducesFreshness_ToNotFresh()
{
var context = TestUtils.CreateTestContext();
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
@ -524,11 +524,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
};
context.CachedEntryAge = TimeSpan.FromSeconds(3);
Assert.False(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_RequestMaxAgeRestrictAge_ToNotFresh()
public void IsCachedEntryFresh_RequestMaxAgeRestrictAge_ToNotFresh()
{
var context = TestUtils.CreateTestContext();
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
@ -544,11 +544,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
};
context.CachedEntryAge = TimeSpan.FromSeconds(6);
Assert.False(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_MaxStaleOverridesFreshness_ToFresh()
public void IsCachedEntryFresh_MaxStaleOverridesFreshness_ToFresh()
{
var context = TestUtils.CreateTestContext();
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
@ -566,11 +566,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
};
context.CachedEntryAge = TimeSpan.FromSeconds(6);
Assert.True(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_MustRevalidateOverridesRequestMaxStale_ToNotFresh()
public void IsCachedEntryFresh_MustRevalidateOverridesRequestMaxStale_ToNotFresh()
{
var context = TestUtils.CreateTestContext();
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
@ -589,11 +589,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
};
context.CachedEntryAge = TimeSpan.FromSeconds(6);
Assert.False(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
[Fact]
public void EntryIsFresh_IgnoresRequestVerificationWhenSpecified()
public void IsCachedEntryFresh_IgnoresRequestVerificationWhenSpecified()
{
var context = TestUtils.CreateTestContext();
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
@ -611,7 +611,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
};
context.CachedEntryAge = TimeSpan.FromSeconds(3);
Assert.True(new CacheabilityValidator().IsCachedEntryFresh(context));
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
}
}
}

View File

@ -14,12 +14,12 @@ using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
public class ResponseCachingTests
public class ResponseCacheTests
{
[Fact]
public async void ServesCachedContent_IfAvailable()
{
var builder = TestUtils.CreateBuilderWithResponseCaching();
var builder = TestUtils.CreateBuilderWithResponseCache();
using (var server = new TestServer(builder))
{
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfNotAvailable()
{
var builder = TestUtils.CreateBuilderWithResponseCaching();
var builder = TestUtils.CreateBuilderWithResponseCache();
using (var server = new TestServer(builder))
{
@ -49,10 +49,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfVaryHeader_Matches()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
await TestUtils.DefaultRequestDelegate(context);
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -69,10 +69,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfVaryHeader_Mismatches()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
await TestUtils.DefaultRequestDelegate(context);
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -90,10 +90,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfVaryParams_Matches()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCachingFeature().VaryParams = "param";
await TestUtils.DefaultRequestDelegate(context);
context.GetResponseCacheFeature().VaryByParams = "param";
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -109,10 +109,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfVaryParamsExplicit_Matches_ParamNameCaseInsensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCachingFeature().VaryParams = new[] { "ParamA", "paramb" };
await TestUtils.DefaultRequestDelegate(context);
context.GetResponseCacheFeature().VaryByParams = new[] { "ParamA", "paramb" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -128,10 +128,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfVaryParamsStar_Matches_ParamNameCaseInsensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCachingFeature().VaryParams = new[] { "*" };
await TestUtils.DefaultRequestDelegate(context);
context.GetResponseCacheFeature().VaryByParams = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -147,10 +147,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfVaryParamsExplicit_Matches_OrderInsensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCachingFeature().VaryParams = new[] { "ParamB", "ParamA" };
await TestUtils.DefaultRequestDelegate(context);
context.GetResponseCacheFeature().VaryByParams = new[] { "ParamB", "ParamA" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -166,10 +166,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfVaryParamsStar_Matches_OrderInsensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCachingFeature().VaryParams = new[] { "*" };
await TestUtils.DefaultRequestDelegate(context);
context.GetResponseCacheFeature().VaryByParams = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -185,10 +185,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfVaryParams_Mismatches()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCachingFeature().VaryParams = "param";
await TestUtils.DefaultRequestDelegate(context);
context.GetResponseCacheFeature().VaryByParams = "param";
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -204,10 +204,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfVaryParamsExplicit_Mismatch_ParamValueCaseSensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCachingFeature().VaryParams = new[] { "ParamA", "ParamB" };
await TestUtils.DefaultRequestDelegate(context);
context.GetResponseCacheFeature().VaryByParams = new[] { "ParamA", "ParamB" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -223,10 +223,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfVaryParamsStar_Mismatch_ParamValueCaseSensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCachingFeature().VaryParams = new[] { "*" };
await TestUtils.DefaultRequestDelegate(context);
context.GetResponseCacheFeature().VaryByParams = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -242,7 +242,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfRequestRequirements_NotMet()
{
var builder = TestUtils.CreateBuilderWithResponseCaching();
var builder = TestUtils.CreateBuilderWithResponseCache();
using (var server = new TestServer(builder))
{
@ -261,7 +261,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void Serves504_IfOnlyIfCachedHeader_IsSpecified()
{
var builder = TestUtils.CreateBuilderWithResponseCaching();
var builder = TestUtils.CreateBuilderWithResponseCache();
using (var server = new TestServer(builder))
{
@ -281,10 +281,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfSetCookie_IsSpecified()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
var headers = context.Response.Headers[HeaderNames.SetCookie] = "cookieName=cookieValue";
await TestUtils.DefaultRequestDelegate(context);
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -300,7 +300,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfIHttpSendFileFeature_NotUsed()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(app =>
var builder = TestUtils.CreateBuilderWithResponseCache(app =>
{
app.Use(async (context, next) =>
{
@ -322,7 +322,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfIHttpSendFileFeature_Used()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(
var builder = TestUtils.CreateBuilderWithResponseCache(
app =>
{
app.Use(async (context, next) =>
@ -334,7 +334,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
requestDelegate: async (context) =>
{
await context.Features.Get<IHttpSendFileFeature>().SendFileAsync("dummy", 0, 0, CancellationToken.None);
await TestUtils.DefaultRequestDelegate(context);
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -350,7 +350,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfSubsequentRequest_ContainsNoStore()
{
var builder = TestUtils.CreateBuilderWithResponseCaching();
var builder = TestUtils.CreateBuilderWithResponseCache();
using (var server = new TestServer(builder))
{
@ -369,7 +369,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfInitialRequestContains_NoStore()
{
var builder = TestUtils.CreateBuilderWithResponseCaching();
var builder = TestUtils.CreateBuilderWithResponseCache();
using (var server = new TestServer(builder))
{
@ -388,7 +388,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void Serves304_IfIfModifiedSince_Satisfied()
{
var builder = TestUtils.CreateBuilderWithResponseCaching();
var builder = TestUtils.CreateBuilderWithResponseCache();
using (var server = new TestServer(builder))
{
@ -405,7 +405,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfIfModifiedSince_NotSatisfied()
{
var builder = TestUtils.CreateBuilderWithResponseCaching();
var builder = TestUtils.CreateBuilderWithResponseCache();
using (var server = new TestServer(builder))
{
@ -421,10 +421,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void Serves304_IfIfNoneMatch_Satisfied()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
var headers = context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\"");
await TestUtils.DefaultRequestDelegate(context);
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -442,10 +442,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfIfNoneMatch_NotSatisfied()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
var headers = context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\"");
await TestUtils.DefaultRequestDelegate(context);
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
@ -462,7 +462,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_IfBodySize_IsCacheable()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(options: new ResponseCachingOptions()
var builder = TestUtils.CreateBuilderWithResponseCache(options: new ResponseCacheOptions()
{
MaximumCachedBodySize = 100
});
@ -480,7 +480,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesFreshContent_IfBodySize_IsNotCacheable()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(options: new ResponseCachingOptions()
var builder = TestUtils.CreateBuilderWithResponseCache(options: new ResponseCacheOptions()
{
MaximumCachedBodySize = 1
});
@ -498,10 +498,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact]
public async void ServesCachedContent_WithoutReplacingCachedVaryBy_OnCacheMiss()
{
var builder = TestUtils.CreateBuilderWithResponseCaching(requestDelegate: async (context) =>
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
await TestUtils.DefaultRequestDelegate(context);
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))

View File

@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
internal class TestUtils
{
internal static RequestDelegate DefaultRequestDelegate = async (context) =>
internal static RequestDelegate TestRequestDelegate = async (context) =>
{
var uniqueId = Guid.NewGuid().ToString();
var headers = context.Response.GetTypedHeaders();
@ -34,19 +34,19 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await context.Response.WriteAsync(uniqueId);
};
internal static ICacheKeyProvider CreateTestKeyProvider()
internal static IResponseCacheKeyProvider CreateTestKeyProvider()
{
return CreateTestKeyProvider(new ResponseCachingOptions());
return CreateTestKeyProvider(new ResponseCacheOptions());
}
internal static ICacheKeyProvider CreateTestKeyProvider(ResponseCachingOptions options)
internal static IResponseCacheKeyProvider CreateTestKeyProvider(ResponseCacheOptions options)
{
return new CacheKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options));
return new ResponseCacheKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options));
}
internal static IWebHostBuilder CreateBuilderWithResponseCaching(
internal static IWebHostBuilder CreateBuilderWithResponseCache(
Action<IApplicationBuilder> configureDelegate = null,
ResponseCachingOptions options = null,
ResponseCacheOptions options = null,
RequestDelegate requestDelegate = null)
{
if (configureDelegate == null)
@ -55,11 +55,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}
if (options == null)
{
options = new ResponseCachingOptions();
options = new ResponseCacheOptions();
}
if (requestDelegate == null)
{
requestDelegate = DefaultRequestDelegate;
requestDelegate = TestRequestDelegate;
}
return new WebHostBuilder()
@ -70,45 +70,45 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
.Configure(app =>
{
configureDelegate(app);
app.UseResponseCaching(options);
app.UseResponseCache(options);
app.Run(requestDelegate);
});
}
internal static ResponseCachingMiddleware CreateTestMiddleware(
IResponseCache responseCache = null,
ResponseCachingOptions options = null,
ICacheKeyProvider cacheKeyProvider = null,
ICacheabilityValidator cacheabilityValidator = null)
internal static ResponseCacheMiddleware CreateTestMiddleware(
IResponseCacheStore store = null,
ResponseCacheOptions options = null,
IResponseCacheKeyProvider keyProvider = null,
IResponseCachePolicyProvider policyProvider = null)
{
if (responseCache == null)
if (store == null)
{
responseCache = new TestResponseCache();
store = new TestResponseCacheStore();
}
if (options == null)
{
options = new ResponseCachingOptions();
options = new ResponseCacheOptions();
}
if (cacheKeyProvider == null)
if (keyProvider == null)
{
cacheKeyProvider = new CacheKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options));
keyProvider = new ResponseCacheKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options));
}
if (cacheabilityValidator == null)
if (policyProvider == null)
{
cacheabilityValidator = new TestCacheabilityValidator();
policyProvider = new TestResponseCachePolicyProvider();
}
return new ResponseCachingMiddleware(
return new ResponseCacheMiddleware(
httpContext => TaskCache.CompletedTask,
responseCache,
store,
Options.Create(options),
cacheabilityValidator,
cacheKeyProvider);
policyProvider,
keyProvider);
}
internal static ResponseCachingContext CreateTestContext()
internal static ResponseCacheContext CreateTestContext()
{
return new ResponseCachingContext(new DefaultHttpContext());
return new ResponseCacheContext(new DefaultHttpContext());
}
}
@ -120,58 +120,49 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}
}
internal class TestCacheabilityValidator : ICacheabilityValidator
internal class TestResponseCachePolicyProvider : IResponseCachePolicyProvider
{
public bool IsCachedEntryFresh(ResponseCachingContext context) => true;
public bool IsCachedEntryFresh(ResponseCacheContext context) => true;
public bool IsRequestCacheable(ResponseCachingContext context) => true;
public bool IsRequestCacheable(ResponseCacheContext context) => true;
public bool IsResponseCacheable(ResponseCachingContext context) => true;
public bool IsResponseCacheable(ResponseCacheContext context) => true;
}
internal class TestKeyProvider : ICacheKeyProvider
internal class TestResponseCacheKeyProvider : IResponseCacheKeyProvider
{
private readonly StringValues _baseKey;
private readonly string _baseKey;
private readonly StringValues _varyKey;
public TestKeyProvider(StringValues? lookupBaseKey = null, StringValues? lookupVaryKey = null)
public TestResponseCacheKeyProvider(string lookupBaseKey = null, StringValues? lookupVaryKey = null)
{
if (lookupBaseKey.HasValue)
{
_baseKey = lookupBaseKey.Value;
}
_baseKey = lookupBaseKey;
if (lookupVaryKey.HasValue)
{
_varyKey = lookupVaryKey.Value;
}
}
public IEnumerable<string> CreateLookupBaseKeys(ResponseCachingContext context) => _baseKey;
public IEnumerable<string> CreateLookupVaryKeys(ResponseCachingContext context)
public IEnumerable<string> CreateLookupVaryByKeys(ResponseCacheContext context)
{
foreach (var baseKey in _baseKey)
foreach (var varyKey in _varyKey)
{
foreach (var varyKey in _varyKey)
{
yield return baseKey + varyKey;
}
yield return _baseKey + varyKey;
}
}
public string CreateStorageBaseKey(ResponseCachingContext context)
public string CreateBaseKey(ResponseCacheContext context)
{
throw new NotImplementedException();
return _baseKey;
}
public string CreateStorageVaryKey(ResponseCachingContext context)
public string CreateStorageVaryByKey(ResponseCacheContext context)
{
throw new NotImplementedException();
}
}
internal class TestResponseCache : IResponseCache
internal class TestResponseCacheStore : IResponseCacheStore
{
private readonly IDictionary<string, object> _storage = new Dictionary<string, object>();
public int GetCount { get; private set; }
@ -200,12 +191,4 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
_storage[key] = entry;
}
}
internal class TestHttpSendFileFeature : IHttpSendFileFeature
{
public Task SendFileAsync(string path, long offset, long? count, CancellationToken cancellation)
{
return TaskCache.CompletedTask;
}
}
}