Merge branch 'rel/1.0.0' into rel/1.0.0-preview1

This commit is contained in:
John Luo 2016-10-17 11:55:38 -07:00
commit 2eb66dc684
25 changed files with 474 additions and 444 deletions

View File

@ -15,12 +15,12 @@ namespace ResponseCachingSample
{ {
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddMemoryResponseCacheStore(); services.AddResponseCaching();
} }
public void Configure(IApplicationBuilder app) public void Configure(IApplicationBuilder app)
{ {
app.UseResponseCache(); app.UseResponseCaching();
app.Run(async (context) => app.Run(async (context) =>
{ {
context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue()

View File

@ -1,18 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.ResponseCaching namespace Microsoft.AspNetCore.ResponseCaching
{ {
/// <summary> /// <summary>
/// A feature for configuring additional response cache options on the HTTP response. /// A feature for configuring additional response cache options on the HTTP response.
/// </summary> /// </summary>
public interface IResponseCacheFeature public interface IResponseCachingFeature
{ {
/// <summary> /// <summary>
/// Gets or sets the query keys used by the response cache middleware for calculating secondary vary keys. /// Gets or sets the query keys used by the response cache middleware for calculating secondary vary keys.
/// </summary> /// </summary>
StringValues VaryByQueryKeys { get; set; } string[] VaryByQueryKeys { get; set; }
} }
} }

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Microsoft.AspNetCore.ResponseCaching.Internal namespace Microsoft.AspNetCore.ResponseCaching.Internal
{ {
public interface IResponseCacheStore public interface IResponseCache
{ {
Task<IResponseCacheEntry> GetAsync(string key); Task<IResponseCacheEntry> GetAsync(string key);
Task SetAsync(string key, IResponseCacheEntry entry, TimeSpan validFor); Task SetAsync(string key, IResponseCacheEntry entry, TimeSpan validFor);

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@ using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.ResponseCaching.Internal namespace Microsoft.AspNetCore.ResponseCaching.Internal
{ {
public class ResponseCacheContext public class ResponseCachingContext
{ {
private static readonly CacheControlHeaderValue EmptyCacheControl = new CacheControlHeaderValue(); private static readonly CacheControlHeaderValue EmptyCacheControl = new CacheControlHeaderValue();
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
private DateTimeOffset? _responseExpires; private DateTimeOffset? _responseExpires;
private bool _parsedResponseExpires; private bool _parsedResponseExpires;
internal ResponseCacheContext(HttpContext httpContext, ILogger logger) internal ResponseCachingContext(HttpContext httpContext, ILogger logger)
{ {
HttpContext = httpContext; HttpContext = httpContext;
Logger = logger; Logger = logger;
@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
internal Stream OriginalResponseStream { get; set; } internal Stream OriginalResponseStream { get; set; }
internal ResponseCacheStream ResponseCacheStream { get; set; } internal ResponseCachingStream ResponseCachingStream { get; set; }
internal IHttpSendFileFeature OriginalSendFileFeature { get; set; } internal IHttpSendFileFeature OriginalSendFileFeature { get; set; }

View File

@ -5,23 +5,21 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.ResponseCaching.Internal;
using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.ResponseCaching.Internal namespace Microsoft.AspNetCore.ResponseCaching.Internal
{ {
public class ResponseCacheKeyProvider : IResponseCacheKeyProvider public class ResponseCachingKeyProvider : IResponseCachingKeyProvider
{ {
// Use the record separator for delimiting components of the cache key to avoid possible collisions // Use the record separator for delimiting components of the cache key to avoid possible collisions
private static readonly char KeyDelimiter = '\x1e'; private static readonly char KeyDelimiter = '\x1e';
private readonly ObjectPool<StringBuilder> _builderPool; private readonly ObjectPool<StringBuilder> _builderPool;
private readonly ResponseCacheOptions _options; private readonly ResponseCachingOptions _options;
public ResponseCacheKeyProvider(ObjectPoolProvider poolProvider, IOptions<ResponseCacheOptions> options) public ResponseCachingKeyProvider(ObjectPoolProvider poolProvider, IOptions<ResponseCachingOptions> options)
{ {
if (poolProvider == null) if (poolProvider == null)
{ {
@ -36,13 +34,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
_options = options.Value; _options = options.Value;
} }
public IEnumerable<string> CreateLookupVaryByKeys(ResponseCacheContext context) public IEnumerable<string> CreateLookupVaryByKeys(ResponseCachingContext context)
{ {
return new string[] { CreateStorageVaryByKey(context) }; return new string[] { CreateStorageVaryByKey(context) };
} }
// GET<delimiter>/PATH // GET<delimiter>/PATH
public string CreateBaseKey(ResponseCacheContext context) public string CreateBaseKey(ResponseCachingContext context)
{ {
if (context == null) if (context == null)
{ {
@ -76,7 +74,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
} }
// BaseKey<delimiter>H<delimiter>HeaderName=HeaderValue<delimiter>Q<delimiter>QueryName=QueryValue // BaseKey<delimiter>H<delimiter>HeaderName=HeaderValue<delimiter>Q<delimiter>QueryName=QueryValue
public string CreateStorageVaryByKey(ResponseCacheContext context) public string CreateStorageVaryByKey(ResponseCachingContext context)
{ {
if (context == null) if (context == null)
{ {
@ -86,7 +84,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
var varyByRules = context.CachedVaryByRules; var varyByRules = context.CachedVaryByRules;
if (varyByRules == null) if (varyByRules == null)
{ {
throw new InvalidOperationException($"{nameof(CachedVaryByRules)} must not be null on the {nameof(ResponseCacheContext)}"); throw new InvalidOperationException($"{nameof(CachedVaryByRules)} must not be null on the {nameof(ResponseCachingContext)}");
} }
if ((StringValues.IsNullOrEmpty(varyByRules.Headers) && StringValues.IsNullOrEmpty(varyByRules.QueryKeys))) if ((StringValues.IsNullOrEmpty(varyByRules.Headers) && StringValues.IsNullOrEmpty(varyByRules.QueryKeys)))

View File

@ -8,11 +8,11 @@ using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.ResponseCaching.Internal namespace Microsoft.AspNetCore.ResponseCaching.Internal
{ {
public class ResponseCachePolicyProvider : IResponseCachePolicyProvider public class ResponseCachingPolicyProvider : IResponseCachingPolicyProvider
{ {
private static readonly CacheControlHeaderValue EmptyCacheControl = new CacheControlHeaderValue(); private static readonly CacheControlHeaderValue EmptyCacheControl = new CacheControlHeaderValue();
public virtual bool IsRequestCacheable(ResponseCacheContext context) public virtual bool IsRequestCacheable(ResponseCachingContext context)
{ {
// Verify the method // Verify the method
var request = context.HttpContext.Request; var request = context.HttpContext.Request;
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
return true; return true;
} }
public virtual bool IsResponseCacheable(ResponseCacheContext context) public virtual bool IsResponseCacheable(ResponseCachingContext context)
{ {
// Only cache pages explicitly marked with public // Only cache pages explicitly marked with public
if (!context.ResponseCacheControlHeaderValue.Public) if (!context.ResponseCacheControlHeaderValue.Public)
@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
return true; return true;
} }
public virtual bool IsCachedEntryFresh(ResponseCacheContext context) public virtual bool IsCachedEntryFresh(ResponseCachingContext context)
{ {
var age = context.CachedEntryAge.Value; var age = context.CachedEntryAge.Value;
var cachedControlHeaders = context.CachedResponseHeaders.CacheControl ?? EmptyCacheControl; var cachedControlHeaders = context.CachedResponseHeaders.CacheControl ?? EmptyCacheControl;

View File

@ -10,18 +10,18 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
internal class SendFileFeatureWrapper : IHttpSendFileFeature internal class SendFileFeatureWrapper : IHttpSendFileFeature
{ {
private readonly IHttpSendFileFeature _originalSendFileFeature; private readonly IHttpSendFileFeature _originalSendFileFeature;
private readonly ResponseCacheStream _responseCacheStream; private readonly ResponseCachingStream _responseCachingStream;
public SendFileFeatureWrapper(IHttpSendFileFeature originalSendFileFeature, ResponseCacheStream responseCacheStream) public SendFileFeatureWrapper(IHttpSendFileFeature originalSendFileFeature, ResponseCachingStream responseCachingStream)
{ {
_originalSendFileFeature = originalSendFileFeature; _originalSendFileFeature = originalSendFileFeature;
_responseCacheStream = responseCacheStream; _responseCachingStream = responseCachingStream;
} }
// Flush and disable the buffer if anyone tries to call the SendFile feature. // Flush and disable the buffer if anyone tries to call the SendFile feature.
public Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) public Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation)
{ {
_responseCacheStream.DisableBuffering(); _responseCachingStream.DisableBuffering();
return _originalSendFileFeature.SendFileAsync(path, offset, length, cancellation); return _originalSendFileFeature.SendFileAsync(path, offset, length, cancellation);
} }
} }

View File

@ -1,36 +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;
using Microsoft.AspNetCore.ResponseCaching;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder
{
public static class ResponseCacheExtensions
{
public static IApplicationBuilder UseResponseCache(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<ResponseCacheMiddleware>();
}
public static IApplicationBuilder UseResponseCache(this IApplicationBuilder app, ResponseCacheOptions options)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<ResponseCacheMiddleware>(Options.Create(options));
}
}
}

View File

@ -1,28 +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;
using Microsoft.AspNetCore.ResponseCaching;
using Microsoft.AspNetCore.ResponseCaching.Internal;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ResponseCacheServiceCollectionExtensions
{
public static IServiceCollection AddMemoryResponseCacheStore(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.AddMemoryCache();
services.TryAdd(ServiceDescriptor.Singleton<IResponseCachePolicyProvider, ResponseCachePolicyProvider>());
services.TryAdd(ServiceDescriptor.Singleton<IResponseCacheKeyProvider, ResponseCacheKeyProvider>());
services.TryAdd(ServiceDescriptor.Singleton<IResponseCacheStore, MemoryResponseCacheStore>());
return services;
}
}
}

View File

@ -0,0 +1,22 @@
// 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;
using Microsoft.AspNetCore.ResponseCaching;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder
{
public static class ResponseCachingExtensions
{
public static IApplicationBuilder UseResponseCaching(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<ResponseCachingMiddleware>();
}
}
}

View File

@ -2,15 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.ResponseCaching namespace Microsoft.AspNetCore.ResponseCaching
{ {
public class ResponseCacheFeature : IResponseCacheFeature public class ResponseCachingFeature : IResponseCachingFeature
{ {
private StringValues _varyByQueryKeys; private string[] _varyByQueryKeys;
public StringValues VaryByQueryKeys public string[] VaryByQueryKeys
{ {
get get
{ {
@ -18,9 +17,9 @@ namespace Microsoft.AspNetCore.ResponseCaching
} }
set set
{ {
if (value.Count > 1) if (value?.Length > 1)
{ {
for (var i = 0; i < value.Count; i++) for (var i = 0; i < value.Length; i++)
{ {
if (string.IsNullOrEmpty(value[i])) if (string.IsNullOrEmpty(value[i]))
{ {

View File

@ -4,7 +4,6 @@
using System; using System;
using System.Globalization; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Headers; using Microsoft.AspNetCore.Http.Headers;
@ -17,25 +16,25 @@ using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.ResponseCaching namespace Microsoft.AspNetCore.ResponseCaching
{ {
public class ResponseCacheMiddleware public class ResponseCachingMiddleware
{ {
private static readonly TimeSpan DefaultExpirationTimeSpan = TimeSpan.FromSeconds(10); private static readonly TimeSpan DefaultExpirationTimeSpan = TimeSpan.FromSeconds(10);
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly ResponseCacheOptions _options; private readonly ResponseCachingOptions _options;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IResponseCachePolicyProvider _policyProvider; private readonly IResponseCachingPolicyProvider _policyProvider;
private readonly IResponseCacheStore _store; private readonly IResponseCache _cache;
private readonly IResponseCacheKeyProvider _keyProvider; private readonly IResponseCachingKeyProvider _keyProvider;
private readonly Func<object, Task> _onStartingCallback; private readonly Func<object, Task> _onStartingCallback;
public ResponseCacheMiddleware( public ResponseCachingMiddleware(
RequestDelegate next, RequestDelegate next,
IOptions<ResponseCacheOptions> options, IOptions<ResponseCachingOptions> options,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
IResponseCachePolicyProvider policyProvider, IResponseCachingPolicyProvider policyProvider,
IResponseCacheStore store, IResponseCache cache,
IResponseCacheKeyProvider keyProvider) IResponseCachingKeyProvider keyProvider)
{ {
if (next == null) if (next == null)
{ {
@ -53,9 +52,9 @@ namespace Microsoft.AspNetCore.ResponseCaching
{ {
throw new ArgumentNullException(nameof(policyProvider)); throw new ArgumentNullException(nameof(policyProvider));
} }
if (store == null) if (cache == null)
{ {
throw new ArgumentNullException(nameof(store)); throw new ArgumentNullException(nameof(cache));
} }
if (keyProvider == null) if (keyProvider == null)
{ {
@ -64,16 +63,16 @@ namespace Microsoft.AspNetCore.ResponseCaching
_next = next; _next = next;
_options = options.Value; _options = options.Value;
_logger = loggerFactory.CreateLogger<ResponseCacheMiddleware>(); _logger = loggerFactory.CreateLogger<ResponseCachingMiddleware>();
_policyProvider = policyProvider; _policyProvider = policyProvider;
_store = store; _cache = cache;
_keyProvider = keyProvider; _keyProvider = keyProvider;
_onStartingCallback = state => OnResponseStartingAsync((ResponseCacheContext)state); _onStartingCallback = state => OnResponseStartingAsync((ResponseCachingContext)state);
} }
public async Task Invoke(HttpContext httpContext) public async Task Invoke(HttpContext httpContext)
{ {
var context = new ResponseCacheContext(httpContext, _logger); var context = new ResponseCachingContext(httpContext, _logger);
// Should we attempt any caching logic? // Should we attempt any caching logic?
if (_policyProvider.IsRequestCacheable(context)) if (_policyProvider.IsRequestCacheable(context))
@ -111,7 +110,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
} }
} }
internal async Task<bool> TryServeCachedResponseAsync(ResponseCacheContext context, IResponseCacheEntry cacheEntry) internal async Task<bool> TryServeCachedResponseAsync(ResponseCachingContext context, IResponseCacheEntry cacheEntry)
{ {
var cachedResponse = cacheEntry as CachedResponse; var cachedResponse = cacheEntry as CachedResponse;
if (cachedResponse == null) if (cachedResponse == null)
@ -172,10 +171,10 @@ namespace Microsoft.AspNetCore.ResponseCaching
return false; return false;
} }
internal async Task<bool> TryServeFromCacheAsync(ResponseCacheContext context) internal async Task<bool> TryServeFromCacheAsync(ResponseCachingContext context)
{ {
context.BaseKey = _keyProvider.CreateBaseKey(context); context.BaseKey = _keyProvider.CreateBaseKey(context);
var cacheEntry = await _store.GetAsync(context.BaseKey); var cacheEntry = await _cache.GetAsync(context.BaseKey);
var cachedVaryByRules = cacheEntry as CachedVaryByRules; var cachedVaryByRules = cacheEntry as CachedVaryByRules;
if (cachedVaryByRules != null) if (cachedVaryByRules != null)
@ -185,7 +184,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
foreach (var varyKey in _keyProvider.CreateLookupVaryByKeys(context)) foreach (var varyKey in _keyProvider.CreateLookupVaryByKeys(context))
{ {
if (await TryServeCachedResponseAsync(context, await _store.GetAsync(varyKey))) if (await TryServeCachedResponseAsync(context, await _cache.GetAsync(varyKey)))
{ {
return true; return true;
} }
@ -210,7 +209,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
return false; return false;
} }
internal async Task FinalizeCacheHeadersAsync(ResponseCacheContext context) internal async Task FinalizeCacheHeadersAsync(ResponseCachingContext context)
{ {
if (_policyProvider.IsResponseCacheable(context)) if (_policyProvider.IsResponseCacheable(context))
{ {
@ -219,7 +218,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Create the cache entry now // Create the cache entry now
var response = context.HttpContext.Response; var response = context.HttpContext.Response;
var varyHeaders = new StringValues(response.Headers.GetCommaSeparatedValues(HeaderNames.Vary)); var varyHeaders = new StringValues(response.Headers.GetCommaSeparatedValues(HeaderNames.Vary));
var varyQueryKeys = context.HttpContext.Features.Get<IResponseCacheFeature>()?.VaryByQueryKeys ?? StringValues.Empty; var varyQueryKeys = new StringValues(context.HttpContext.Features.Get<IResponseCachingFeature>()?.VaryByQueryKeys);
context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ?? context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ??
context.ResponseCacheControlHeaderValue.MaxAge ?? context.ResponseCacheControlHeaderValue.MaxAge ??
(context.ResponseExpires - context.ResponseTime.Value) ?? (context.ResponseExpires - context.ResponseTime.Value) ??
@ -247,7 +246,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Always overwrite the CachedVaryByRules to update the expiry information // Always overwrite the CachedVaryByRules to update the expiry information
_logger.LogVaryByRulesUpdated(normalizedVaryHeaders, normalizedVaryQueryKeys); _logger.LogVaryByRulesUpdated(normalizedVaryHeaders, normalizedVaryQueryKeys);
await _store.SetAsync(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor); await _cache.SetAsync(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor);
context.StorageVaryKey = _keyProvider.CreateStorageVaryByKey(context); context.StorageVaryKey = _keyProvider.CreateStorageVaryByKey(context);
} }
@ -277,21 +276,21 @@ namespace Microsoft.AspNetCore.ResponseCaching
} }
else else
{ {
context.ResponseCacheStream.DisableBuffering(); context.ResponseCachingStream.DisableBuffering();
} }
} }
internal async Task FinalizeCacheBodyAsync(ResponseCacheContext context) internal async Task FinalizeCacheBodyAsync(ResponseCachingContext context)
{ {
var contentLength = context.TypedResponseHeaders.ContentLength; var contentLength = context.TypedResponseHeaders.ContentLength;
if (context.ShouldCacheResponse && context.ResponseCacheStream.BufferingEnabled) if (context.ShouldCacheResponse && context.ResponseCachingStream.BufferingEnabled)
{ {
var bufferStream = context.ResponseCacheStream.GetBufferStream(); var bufferStream = context.ResponseCachingStream.GetBufferStream();
if (!contentLength.HasValue || contentLength == bufferStream.Length) if (!contentLength.HasValue || contentLength == bufferStream.Length)
{ {
context.CachedResponse.Body = bufferStream; context.CachedResponse.Body = bufferStream;
_logger.LogResponseCached(); _logger.LogResponseCached();
await _store.SetAsync(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor); await _cache.SetAsync(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor);
} }
else else
{ {
@ -304,7 +303,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
} }
} }
internal Task OnResponseStartingAsync(ResponseCacheContext context) internal Task OnResponseStartingAsync(ResponseCachingContext context)
{ {
if (!context.ResponseStarted) if (!context.ResponseStarted)
{ {
@ -319,29 +318,29 @@ namespace Microsoft.AspNetCore.ResponseCaching
} }
} }
internal void ShimResponseStream(ResponseCacheContext context) internal void ShimResponseStream(ResponseCachingContext context)
{ {
// Shim response stream // Shim response stream
context.OriginalResponseStream = context.HttpContext.Response.Body; context.OriginalResponseStream = context.HttpContext.Response.Body;
context.ResponseCacheStream = new ResponseCacheStream(context.OriginalResponseStream, _options.MaximumBodySize, StreamUtilities.BodySegmentSize); context.ResponseCachingStream = new ResponseCachingStream(context.OriginalResponseStream, _options.MaximumBodySize, StreamUtilities.BodySegmentSize);
context.HttpContext.Response.Body = context.ResponseCacheStream; context.HttpContext.Response.Body = context.ResponseCachingStream;
// Shim IHttpSendFileFeature // Shim IHttpSendFileFeature
context.OriginalSendFileFeature = context.HttpContext.Features.Get<IHttpSendFileFeature>(); context.OriginalSendFileFeature = context.HttpContext.Features.Get<IHttpSendFileFeature>();
if (context.OriginalSendFileFeature != null) if (context.OriginalSendFileFeature != null)
{ {
context.HttpContext.Features.Set<IHttpSendFileFeature>(new SendFileFeatureWrapper(context.OriginalSendFileFeature, context.ResponseCacheStream)); context.HttpContext.Features.Set<IHttpSendFileFeature>(new SendFileFeatureWrapper(context.OriginalSendFileFeature, context.ResponseCachingStream));
} }
// Add IResponseCacheFeature // Add IResponseCachingFeature
if (context.HttpContext.Features.Get<IResponseCacheFeature>() != null) if (context.HttpContext.Features.Get<IResponseCachingFeature>() != null)
{ {
throw new InvalidOperationException($"Another instance of {nameof(ResponseCacheFeature)} already exists. Only one instance of {nameof(ResponseCacheMiddleware)} can be configured for an application."); throw new InvalidOperationException($"Another instance of {nameof(ResponseCachingFeature)} already exists. Only one instance of {nameof(ResponseCachingMiddleware)} can be configured for an application.");
} }
context.HttpContext.Features.Set<IResponseCacheFeature>(new ResponseCacheFeature()); context.HttpContext.Features.Set<IResponseCachingFeature>(new ResponseCachingFeature());
} }
internal static void UnshimResponseStream(ResponseCacheContext context) internal static void UnshimResponseStream(ResponseCachingContext context)
{ {
// Unshim response stream // Unshim response stream
context.HttpContext.Response.Body = context.OriginalResponseStream; context.HttpContext.Response.Body = context.OriginalResponseStream;
@ -349,11 +348,11 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Unshim IHttpSendFileFeature // Unshim IHttpSendFileFeature
context.HttpContext.Features.Set(context.OriginalSendFileFeature); context.HttpContext.Features.Set(context.OriginalSendFileFeature);
// Remove IResponseCacheFeature // Remove IResponseCachingFeature
context.HttpContext.Features.Set<IResponseCacheFeature>(null); context.HttpContext.Features.Set<IResponseCachingFeature>(null);
} }
internal static bool ContentIsNotModified(ResponseCacheContext context) internal static bool ContentIsNotModified(ResponseCachingContext context)
{ {
var cachedResponseHeaders = context.CachedResponseHeaders; var cachedResponseHeaders = context.CachedResponseHeaders;
var ifNoneMatchHeader = context.TypedRequestHeaders.IfNoneMatch; var ifNoneMatchHeader = context.TypedRequestHeaders.IfNoneMatch;

View File

@ -4,9 +4,9 @@
using System.ComponentModel; using System.ComponentModel;
using Microsoft.AspNetCore.ResponseCaching.Internal; using Microsoft.AspNetCore.ResponseCaching.Internal;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.ResponseCaching
{ {
public class ResponseCacheOptions public class ResponseCachingOptions
{ {
/// <summary> /// <summary>
/// The largest cacheable size for the response body in bytes. The default is set to 64 MB. /// The largest cacheable size for the response body in bytes. The default is set to 64 MB.

View File

@ -0,0 +1,59 @@
// 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;
using Microsoft.AspNetCore.ResponseCaching;
using Microsoft.AspNetCore.ResponseCaching.Internal;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extension methods for the ResponseCaching middleware.
/// </summary>
public static class ResponseCachingServicesExtensions
{
/// <summary>
/// Add response caching services.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> for adding services.</param>
/// <returns></returns>
public static IServiceCollection AddResponseCaching(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.AddMemoryCache();
services.TryAdd(ServiceDescriptor.Singleton<IResponseCachingPolicyProvider, ResponseCachingPolicyProvider>());
services.TryAdd(ServiceDescriptor.Singleton<IResponseCachingKeyProvider, ResponseCachingKeyProvider>());
services.TryAdd(ServiceDescriptor.Singleton<IResponseCache, MemoryResponseCache>());
return services;
}
/// <summary>
/// Add response caching services and configure the related options.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> for adding services.</param>
/// <param name="configureOptions">A delegate to configure the <see cref="ResponseCachingOptions"/>.</param>
/// <returns></returns>
public static IServiceCollection AddResponseCaching(this IServiceCollection services, Action<ResponseCachingOptions> configureOptions)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (configureOptions == null)
{
throw new ArgumentNullException(nameof(configureOptions));
}
services.Configure(configureOptions);
services.AddResponseCaching();
return services;
}
}
}

View File

@ -8,14 +8,14 @@ using System.Threading.Tasks;
namespace Microsoft.AspNetCore.ResponseCaching.Internal namespace Microsoft.AspNetCore.ResponseCaching.Internal
{ {
internal class ResponseCacheStream : Stream internal class ResponseCachingStream : Stream
{ {
private readonly Stream _innerStream; private readonly Stream _innerStream;
private readonly long _maxBufferSize; private readonly long _maxBufferSize;
private readonly int _segmentSize; private readonly int _segmentSize;
private SegmentWriteStream _segmentWriteStream; private SegmentWriteStream _segmentWriteStream;
internal ResponseCacheStream(Stream innerStream, long maxBufferSize, int segmentSize) internal ResponseCachingStream(Stream innerStream, long maxBufferSize, int segmentSize)
{ {
_innerStream = innerStream; _innerStream = innerStream;
_maxBufferSize = maxBufferSize; _maxBufferSize = maxBufferSize;

View File

@ -1,64 +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;
using Microsoft.Extensions.Primitives;
using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
public class ResponseCacheFeatureTests
{
public static TheoryData<StringValues> ValidNullOrEmptyVaryRules
{
get
{
return new TheoryData<StringValues>
{
default(StringValues),
StringValues.Empty,
new StringValues((string)null),
new StringValues(string.Empty),
new StringValues((string[])null),
new StringValues(new string[0]),
new StringValues(new string[] { null }),
new StringValues(new string[] { string.Empty })
};
}
}
[Theory]
[MemberData(nameof(ValidNullOrEmptyVaryRules))]
public void VaryByQueryKeys_Set_ValidEmptyValues_Succeeds(StringValues value)
{
// Does not throw
new ResponseCacheFeature().VaryByQueryKeys = value;
}
public static TheoryData<StringValues> InvalidVaryRules
{
get
{
return new TheoryData<StringValues>
{
new StringValues(new string[] { null, null }),
new StringValues(new string[] { null, string.Empty }),
new StringValues(new string[] { string.Empty, null }),
new StringValues(new string[] { string.Empty, "Valid" }),
new StringValues(new string[] { "Valid", string.Empty }),
new StringValues(new string[] { null, "Valid" }),
new StringValues(new string[] { "Valid", null })
};
}
}
[Theory]
[MemberData(nameof(InvalidVaryRules))]
public void VaryByQueryKeys_Set_InValidEmptyValues_Throws(StringValues value)
{
// Throws
Assert.Throws<ArgumentException>(() => new ResponseCacheFeature().VaryByQueryKeys = value);
}
}
}

View File

@ -0,0 +1,59 @@
// 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;
using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
public class ResponseCachingFeatureTests
{
public static TheoryData<string[]> ValidNullOrEmptyVaryRules
{
get
{
return new TheoryData<string[]>
{
null,
new string[0],
new string[] { null },
new string[] { string.Empty }
};
}
}
[Theory]
[MemberData(nameof(ValidNullOrEmptyVaryRules))]
public void VaryByQueryKeys_Set_ValidEmptyValues_Succeeds(string[] value)
{
// Does not throw
new ResponseCachingFeature().VaryByQueryKeys = value;
}
public static TheoryData<string[]> InvalidVaryRules
{
get
{
return new TheoryData<string[]>
{
new string[] { null, null },
new string[] { null, string.Empty },
new string[] { string.Empty, null },
new string[] { string.Empty, "Valid" },
new string[] { "Valid", string.Empty },
new string[] { null, "Valid" },
new string[] { "Valid", null }
};
}
}
[Theory]
[MemberData(nameof(InvalidVaryRules))]
public void VaryByQueryKeys_Set_InValidEmptyValues_Throws(string[] value)
{
// Throws
Assert.Throws<ArgumentException>(() => new ResponseCachingFeature().VaryByQueryKeys = value);
}
}
}

View File

@ -2,19 +2,18 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.ResponseCaching.Internal; using Microsoft.AspNetCore.ResponseCaching.Internal;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests namespace Microsoft.AspNetCore.ResponseCaching.Tests
{ {
public class ResponseCacheKeyProviderTests public class ResponseCachingKeyProviderTests
{ {
private static readonly char KeyDelimiter = '\x1e'; private static readonly char KeyDelimiter = '\x1e';
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageBaseKey_IncludesOnlyNormalizedMethodAndPath() public void ResponseCachingKeyProvider_CreateStorageBaseKey_IncludesOnlyNormalizedMethodAndPath()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
@ -29,9 +28,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageBaseKey_CaseInsensitivePath_NormalizesPath() public void ResponseCachingKeyProvider_CreateStorageBaseKey_CaseInsensitivePath_NormalizesPath()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(new ResponseCacheOptions() var cacheKeyProvider = TestUtils.CreateTestKeyProvider(new ResponseCachingOptions()
{ {
UseCaseSensitivePaths = false UseCaseSensitivePaths = false
}); });
@ -43,9 +42,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageBaseKey_CaseSensitivePath_PreservesPathCase() public void ResponseCachingKeyProvider_CreateStorageBaseKey_CaseSensitivePath_PreservesPathCase()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(new ResponseCacheOptions() var cacheKeyProvider = TestUtils.CreateTestKeyProvider(new ResponseCachingOptions()
{ {
UseCaseSensitivePaths = true UseCaseSensitivePaths = true
}); });
@ -57,7 +56,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryByKey_Throws_IfVaryByRulesIsNull() public void ResponseCachingKeyProvider_CreateStorageVaryByKey_Throws_IfVaryByRulesIsNull()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
@ -66,7 +65,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_ReturnsCachedVaryByGuid_IfVaryByRulesIsEmpty() public void ResponseCachingKeyProvider_CreateStorageVaryKey_ReturnsCachedVaryByGuid_IfVaryByRulesIsEmpty()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
@ -79,7 +78,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedHeadersOnly() public void ResponseCachingKeyProvider_CreateStorageVaryKey_IncludesListedHeadersOnly()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
@ -95,7 +94,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedQueryKeysOnly() public void ResponseCachingKeyProvider_CreateStorageVaryKey_IncludesListedQueryKeysOnly()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
@ -111,7 +110,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesQueryKeys_QueryKeyCaseInsensitive_UseQueryKeyCasing() public void ResponseCachingKeyProvider_CreateStorageVaryKey_IncludesQueryKeys_QueryKeyCaseInsensitive_UseQueryKeyCasing()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
@ -127,7 +126,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesAllQueryKeysGivenAsterisk() public void ResponseCachingKeyProvider_CreateStorageVaryKey_IncludesAllQueryKeysGivenAsterisk()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
@ -145,7 +144,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedHeadersAndQueryKeys() public void ResponseCachingKeyProvider_CreateStorageVaryKey_IncludesListedHeadersAndQueryKeys()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();

View File

@ -14,14 +14,14 @@ using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests namespace Microsoft.AspNetCore.ResponseCaching.Tests
{ {
public class ResponseCacheMiddlewareTests public class ResponseCachingMiddlewareTests
{ {
[Fact] [Fact]
public async Task TryServeFromCacheAsync_OnlyIfCached_Serves504() public async Task TryServeFromCacheAsync_OnlyIfCached_Serves504()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store, keyProvider: new TestResponseCacheKeyProvider()); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider());
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue() context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
{ {
@ -38,13 +38,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task TryServeFromCacheAsync_CachedResponseNotFound_Fails() public async Task TryServeFromCacheAsync_CachedResponseNotFound_Fails()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey")); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey"));
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
Assert.False(await middleware.TryServeFromCacheAsync(context)); Assert.False(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(1, store.GetCount); Assert.Equal(1, cache.GetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.NoResponseServed); LoggedMessage.NoResponseServed);
@ -53,12 +53,12 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task TryServeFromCacheAsync_CachedResponseFound_Succeeds() public async Task TryServeFromCacheAsync_CachedResponseFound_Succeeds()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey")); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey"));
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
await store.SetAsync( await cache.SetAsync(
"BaseKey", "BaseKey",
new CachedResponse() new CachedResponse()
{ {
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
TimeSpan.Zero); TimeSpan.Zero);
Assert.True(await middleware.TryServeFromCacheAsync(context)); Assert.True(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(1, store.GetCount); Assert.Equal(1, cache.GetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.CachedResponseServed); LoggedMessage.CachedResponseServed);
@ -76,18 +76,18 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task TryServeFromCacheAsync_VaryByRuleFound_CachedResponseNotFound_Fails() public async Task TryServeFromCacheAsync_VaryByRuleFound_CachedResponseNotFound_Fails()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey", "VaryKey")); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey", "VaryKey"));
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
await store.SetAsync( await cache.SetAsync(
"BaseKey", "BaseKey",
new CachedVaryByRules(), new CachedVaryByRules(),
TimeSpan.Zero); TimeSpan.Zero);
Assert.False(await middleware.TryServeFromCacheAsync(context)); Assert.False(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(2, store.GetCount); Assert.Equal(2, cache.GetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.NoResponseServed); LoggedMessage.NoResponseServed);
@ -96,16 +96,16 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task TryServeFromCacheAsync_VaryByRuleFound_CachedResponseFound_Succeeds() public async Task TryServeFromCacheAsync_VaryByRuleFound_CachedResponseFound_Succeeds()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey", new[] { "VaryKey", "VaryKey2" })); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey", new[] { "VaryKey", "VaryKey2" }));
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
await store.SetAsync( await cache.SetAsync(
"BaseKey", "BaseKey",
new CachedVaryByRules(), new CachedVaryByRules(),
TimeSpan.Zero); TimeSpan.Zero);
await store.SetAsync( await cache.SetAsync(
"BaseKeyVaryKey2", "BaseKeyVaryKey2",
new CachedResponse() new CachedResponse()
{ {
@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
TimeSpan.Zero); TimeSpan.Zero);
Assert.True(await middleware.TryServeFromCacheAsync(context)); Assert.True(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(3, store.GetCount); Assert.Equal(3, cache.GetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.CachedResponseServed); LoggedMessage.CachedResponseServed);
@ -123,13 +123,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task TryServeFromCacheAsync_CachedResponseFound_Serves304IfPossible() public async Task TryServeFromCacheAsync_CachedResponseFound_Serves304IfPossible()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey")); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey"));
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Headers[HeaderNames.IfNoneMatch] = "*"; context.HttpContext.Request.Headers[HeaderNames.IfNoneMatch] = "*";
await store.SetAsync( await cache.SetAsync(
"BaseKey", "BaseKey",
new CachedResponse() new CachedResponse()
{ {
@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
TimeSpan.Zero); TimeSpan.Zero);
Assert.True(await middleware.TryServeFromCacheAsync(context)); Assert.True(await middleware.TryServeFromCacheAsync(context));
Assert.Equal(1, store.GetCount); Assert.Equal(1, cache.GetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.NotModifiedServed); LoggedMessage.NotModifiedServed);
@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var context = TestUtils.CreateTestContext(sink); var context = TestUtils.CreateTestContext(sink);
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary()); context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary());
Assert.False(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.False(ResponseCachingMiddleware.ContentIsNotModified(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -167,17 +167,17 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
// Verify modifications in the past succeeds // Verify modifications in the past succeeds
context.CachedResponseHeaders.Date = utcNow - TimeSpan.FromSeconds(10); context.CachedResponseHeaders.Date = utcNow - TimeSpan.FromSeconds(10);
Assert.True(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context));
Assert.Equal(1, sink.Writes.Count); Assert.Equal(1, sink.Writes.Count);
// Verify modifications at present succeeds // Verify modifications at present succeeds
context.CachedResponseHeaders.Date = utcNow; context.CachedResponseHeaders.Date = utcNow;
Assert.True(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context));
Assert.Equal(2, sink.Writes.Count); Assert.Equal(2, sink.Writes.Count);
// Verify modifications in the future fails // Verify modifications in the future fails
context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10); context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10);
Assert.False(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.False(ResponseCachingMiddleware.ContentIsNotModified(context));
// Verify logging // Verify logging
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
@ -199,19 +199,19 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
// Verify modifications in the past succeeds // Verify modifications in the past succeeds
context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10); context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10);
context.CachedResponseHeaders.LastModified = utcNow - TimeSpan.FromSeconds(10); context.CachedResponseHeaders.LastModified = utcNow - TimeSpan.FromSeconds(10);
Assert.True(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context));
Assert.Equal(1, sink.Writes.Count); Assert.Equal(1, sink.Writes.Count);
// Verify modifications at present // Verify modifications at present
context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10); context.CachedResponseHeaders.Date = utcNow + TimeSpan.FromSeconds(10);
context.CachedResponseHeaders.LastModified = utcNow; context.CachedResponseHeaders.LastModified = utcNow;
Assert.True(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context));
Assert.Equal(2, sink.Writes.Count); Assert.Equal(2, sink.Writes.Count);
// Verify modifications in the future fails // Verify modifications in the future fails
context.CachedResponseHeaders.Date = utcNow - TimeSpan.FromSeconds(10); context.CachedResponseHeaders.Date = utcNow - TimeSpan.FromSeconds(10);
context.CachedResponseHeaders.LastModified = utcNow + TimeSpan.FromSeconds(10); context.CachedResponseHeaders.LastModified = utcNow + TimeSpan.FromSeconds(10);
Assert.False(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.False(ResponseCachingMiddleware.ContentIsNotModified(context));
// Verify logging // Verify logging
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
@ -233,7 +233,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.CachedResponseHeaders.LastModified = utcNow + TimeSpan.FromSeconds(10); context.CachedResponseHeaders.LastModified = utcNow + TimeSpan.FromSeconds(10);
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { EntityTagHeaderValue.Any }); context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { EntityTagHeaderValue.Any });
Assert.True(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.NotModifiedIfNoneMatchStar); LoggedMessage.NotModifiedIfNoneMatchStar);
@ -252,7 +252,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.CachedResponseHeaders.LastModified = utcNow - TimeSpan.FromSeconds(10); context.CachedResponseHeaders.LastModified = utcNow - TimeSpan.FromSeconds(10);
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") }); context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") });
Assert.False(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.False(ResponseCachingMiddleware.ContentIsNotModified(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -265,7 +265,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") }); context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") });
Assert.False(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.False(ResponseCachingMiddleware.ContentIsNotModified(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -296,7 +296,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { requestETag }); context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { requestETag });
Assert.True(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.NotModifiedIfNoneMatchMatched); LoggedMessage.NotModifiedIfNoneMatchMatched);
@ -314,7 +314,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") }); context.TypedRequestHeaders.IfNoneMatch = new List<EntityTagHeaderValue>(new[] { new EntityTagHeaderValue("\"E1\"") });
Assert.False(ResponseCacheMiddleware.ContentIsNotModified(context)); Assert.False(ResponseCachingMiddleware.ContentIsNotModified(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -322,7 +322,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
public async Task FinalizeCacheHeaders_DoNotUpdateShouldCacheResponse_IfResponseIsNotCacheable() public async Task FinalizeCacheHeaders_DoNotUpdateShouldCacheResponse_IfResponseIsNotCacheable()
{ {
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, policyProvider: new ResponseCachePolicyProvider()); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, policyProvider: new ResponseCachingPolicyProvider());
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
Assert.False(context.ShouldCacheResponse); Assert.False(context.ShouldCacheResponse);
@ -338,7 +338,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
public async Task FinalizeCacheHeaders_UpdateShouldCacheResponse_IfResponseIsCacheable() public async Task FinalizeCacheHeaders_UpdateShouldCacheResponse_IfResponseIsCacheable()
{ {
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, policyProvider: new ResponseCachePolicyProvider()); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, policyProvider: new ResponseCachingPolicyProvider());
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue() context.TypedResponseHeaders.CacheControl = new CacheControlHeaderValue()
{ {
@ -425,13 +425,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task FinalizeCacheHeaders_UpdateCachedVaryByRules_IfNotEquivalentToPrevious() public async Task FinalizeCacheHeaders_UpdateCachedVaryByRules_IfNotEquivalentToPrevious()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB", "HEADERc" }); context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB", "HEADERc" });
context.HttpContext.Features.Set<IResponseCacheFeature>(new ResponseCacheFeature() context.HttpContext.Features.Set<IResponseCachingFeature>(new ResponseCachingFeature()
{ {
VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" }) VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" })
}); });
@ -445,7 +445,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await middleware.TryServeFromCacheAsync(context); await middleware.TryServeFromCacheAsync(context);
await middleware.FinalizeCacheHeadersAsync(context); await middleware.FinalizeCacheHeadersAsync(context);
Assert.Equal(1, store.SetCount); Assert.Equal(1, cache.SetCount);
Assert.NotSame(cachedVaryByRules, context.CachedVaryByRules); Assert.NotSame(cachedVaryByRules, context.CachedVaryByRules);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
@ -456,13 +456,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task FinalizeCacheHeaders_UpdateCachedVaryByRules_IfEquivalentToPrevious() public async Task FinalizeCacheHeaders_UpdateCachedVaryByRules_IfEquivalentToPrevious()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB" }); context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB" });
context.HttpContext.Features.Set<IResponseCacheFeature>(new ResponseCacheFeature() context.HttpContext.Features.Set<IResponseCachingFeature>(new ResponseCachingFeature()
{ {
VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" }) VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" })
}); });
@ -478,7 +478,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await middleware.FinalizeCacheHeadersAsync(context); await middleware.FinalizeCacheHeadersAsync(context);
// An update to the cache is always made but the entry should be the same // An update to the cache is always made but the entry should be the same
Assert.Equal(1, store.SetCount); Assert.Equal(1, cache.SetCount);
Assert.Same(cachedVaryByRules, context.CachedVaryByRules); Assert.Same(cachedVaryByRules, context.CachedVaryByRules);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
@ -508,13 +508,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[MemberData(nameof(NullOrEmptyVaryRules))] [MemberData(nameof(NullOrEmptyVaryRules))]
public async Task FinalizeCacheHeaders_UpdateCachedVaryByRules_NullOrEmptyRules(StringValues vary) public async Task FinalizeCacheHeaders_UpdateCachedVaryByRules_NullOrEmptyRules(StringValues vary)
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
context.HttpContext.Response.Headers[HeaderNames.Vary] = vary; context.HttpContext.Response.Headers[HeaderNames.Vary] = vary;
context.HttpContext.Features.Set<IResponseCacheFeature>(new ResponseCacheFeature() context.HttpContext.Features.Set<IResponseCachingFeature>(new ResponseCachingFeature()
{ {
VaryByQueryKeys = vary VaryByQueryKeys = vary
}); });
@ -523,7 +523,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await middleware.FinalizeCacheHeadersAsync(context); await middleware.FinalizeCacheHeadersAsync(context);
// Vary rules should not be updated // Vary rules should not be updated
Assert.Equal(0, store.SetCount); Assert.Equal(0, cache.SetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.NoResponseServed); LoggedMessage.NoResponseServed);
@ -600,9 +600,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task FinalizeCacheBody_Cache_IfContentLengthMatches() public async Task FinalizeCacheBody_Cache_IfContentLengthMatches()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context); middleware.ShimResponseStream(context);
@ -616,7 +616,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await middleware.FinalizeCacheBodyAsync(context); await middleware.FinalizeCacheBodyAsync(context);
Assert.Equal(1, store.SetCount); Assert.Equal(1, cache.SetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseCached); LoggedMessage.ResponseCached);
@ -625,9 +625,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task FinalizeCacheBody_DoNotCache_IfContentLengthMismatches() public async Task FinalizeCacheBody_DoNotCache_IfContentLengthMismatches()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context); middleware.ShimResponseStream(context);
@ -641,7 +641,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await middleware.FinalizeCacheBodyAsync(context); await middleware.FinalizeCacheBodyAsync(context);
Assert.Equal(0, store.SetCount); Assert.Equal(0, cache.SetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseContentLengthMismatchNotCached); LoggedMessage.ResponseContentLengthMismatchNotCached);
@ -650,9 +650,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task FinalizeCacheBody_Cache_IfContentLengthAbsent() public async Task FinalizeCacheBody_Cache_IfContentLengthAbsent()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context); middleware.ShimResponseStream(context);
@ -665,7 +665,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await middleware.FinalizeCacheBodyAsync(context); await middleware.FinalizeCacheBodyAsync(context);
Assert.Equal(1, store.SetCount); Assert.Equal(1, cache.SetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseCached); LoggedMessage.ResponseCached);
@ -674,9 +674,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task FinalizeCacheBody_DoNotCache_IfShouldCacheResponseFalse() public async Task FinalizeCacheBody_DoNotCache_IfShouldCacheResponseFalse()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context); middleware.ShimResponseStream(context);
@ -686,7 +686,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await middleware.FinalizeCacheBodyAsync(context); await middleware.FinalizeCacheBodyAsync(context);
Assert.Equal(0, store.SetCount); Assert.Equal(0, cache.SetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseNotCached); LoggedMessage.ResponseNotCached);
@ -695,20 +695,20 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async Task FinalizeCacheBody_DoNotCache_IfBufferingDisabled() public async Task FinalizeCacheBody_DoNotCache_IfBufferingDisabled()
{ {
var store = new TestResponseCacheStore(); var cache = new TestResponseCache();
var sink = new TestSink(); var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, store: store); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
middleware.ShimResponseStream(context); middleware.ShimResponseStream(context);
await context.HttpContext.Response.WriteAsync(new string('0', 10)); await context.HttpContext.Response.WriteAsync(new string('0', 10));
context.ShouldCacheResponse = true; context.ShouldCacheResponse = true;
context.ResponseCacheStream.DisableBuffering(); context.ResponseCachingStream.DisableBuffering();
await middleware.FinalizeCacheBodyAsync(context); await middleware.FinalizeCacheBodyAsync(context);
Assert.Equal(0, store.SetCount); Assert.Equal(0, cache.SetCount);
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseNotCached); LoggedMessage.ResponseNotCached);
@ -733,7 +733,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var uppercaseStrings = new StringValues(new[] { "STRINGA", "STRINGB" }); var uppercaseStrings = new StringValues(new[] { "STRINGA", "STRINGB" });
var lowercaseStrings = new StringValues(new[] { "stringA", "stringB" }); var lowercaseStrings = new StringValues(new[] { "stringA", "stringB" });
var normalizedStrings = ResponseCacheMiddleware.GetOrderCasingNormalizedStringValues(lowercaseStrings); var normalizedStrings = ResponseCachingMiddleware.GetOrderCasingNormalizedStringValues(lowercaseStrings);
Assert.Equal(uppercaseStrings, normalizedStrings); Assert.Equal(uppercaseStrings, normalizedStrings);
} }
@ -744,7 +744,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var orderedStrings = new StringValues(new[] { "STRINGA", "STRINGB" }); var orderedStrings = new StringValues(new[] { "STRINGA", "STRINGB" });
var reverseOrderStrings = new StringValues(new[] { "STRINGB", "STRINGA" }); var reverseOrderStrings = new StringValues(new[] { "STRINGB", "STRINGA" });
var normalizedStrings = ResponseCacheMiddleware.GetOrderCasingNormalizedStringValues(reverseOrderStrings); var normalizedStrings = ResponseCachingMiddleware.GetOrderCasingNormalizedStringValues(reverseOrderStrings);
Assert.Equal(orderedStrings, normalizedStrings); Assert.Equal(orderedStrings, normalizedStrings);
} }
@ -754,7 +754,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{ {
var originalStrings = new StringValues(new[] { "STRINGA, STRINGB" }); var originalStrings = new StringValues(new[] { "STRINGA, STRINGB" });
var normalizedStrings = ResponseCacheMiddleware.GetOrderCasingNormalizedStringValues(originalStrings); var normalizedStrings = ResponseCachingMiddleware.GetOrderCasingNormalizedStringValues(originalStrings);
Assert.Equal(originalStrings, normalizedStrings); Assert.Equal(originalStrings, normalizedStrings);
} }

View File

@ -11,7 +11,7 @@ using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests namespace Microsoft.AspNetCore.ResponseCaching.Tests
{ {
public class ResponseCachePolicyProviderTests public class ResponseCachingPolicyProviderTests
{ {
public static TheoryData<string> CacheableMethods public static TheoryData<string> CacheableMethods
{ {
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var context = TestUtils.CreateTestContext(sink); var context = TestUtils.CreateTestContext(sink);
context.HttpContext.Request.Method = method; context.HttpContext.Request.Method = method;
Assert.True(new ResponseCachePolicyProvider().IsRequestCacheable(context)); Assert.True(new ResponseCachingPolicyProvider().IsRequestCacheable(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
public static TheoryData<string> NonCacheableMethods public static TheoryData<string> NonCacheableMethods
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var context = TestUtils.CreateTestContext(sink); var context = TestUtils.CreateTestContext(sink);
context.HttpContext.Request.Method = method; context.HttpContext.Request.Method = method;
Assert.False(new ResponseCachePolicyProvider().IsRequestCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsRequestCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.RequestMethodNotCacheable); LoggedMessage.RequestMethodNotCacheable);
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.HttpContext.Request.Method = HttpMethods.Get; context.HttpContext.Request.Method = HttpMethods.Get;
context.HttpContext.Request.Headers[HeaderNames.Authorization] = "Basic plaintextUN:plaintextPW"; context.HttpContext.Request.Headers[HeaderNames.Authorization] = "Basic plaintextUN:plaintextPW";
Assert.False(new ResponseCachePolicyProvider().IsRequestCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsRequestCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.RequestWithAuthorizationNotCacheable); LoggedMessage.RequestWithAuthorizationNotCacheable);
@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
NoCache = true NoCache = true
}; };
Assert.False(new ResponseCachePolicyProvider().IsRequestCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsRequestCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.RequestWithNoCacheNotCacheable); LoggedMessage.RequestWithNoCacheNotCacheable);
@ -110,7 +110,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
NoStore = true NoStore = true
}; };
Assert.True(new ResponseCachePolicyProvider().IsRequestCacheable(context)); Assert.True(new ResponseCachingPolicyProvider().IsRequestCacheable(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.HttpContext.Request.Method = HttpMethods.Get; context.HttpContext.Request.Method = HttpMethods.Get;
context.HttpContext.Request.Headers[HeaderNames.Pragma] = "no-cache"; context.HttpContext.Request.Headers[HeaderNames.Pragma] = "no-cache";
Assert.False(new ResponseCachePolicyProvider().IsRequestCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsRequestCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.RequestWithPragmaNoCacheNotCacheable); LoggedMessage.RequestWithPragmaNoCacheNotCacheable);
@ -137,7 +137,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.HttpContext.Request.Headers[HeaderNames.Pragma] = "no-cache"; context.HttpContext.Request.Headers[HeaderNames.Pragma] = "no-cache";
context.HttpContext.Request.Headers[HeaderNames.CacheControl] = "max-age=10"; context.HttpContext.Request.Headers[HeaderNames.CacheControl] = "max-age=10";
Assert.True(new ResponseCachePolicyProvider().IsRequestCacheable(context)); Assert.True(new ResponseCachingPolicyProvider().IsRequestCacheable(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var sink = new TestSink(); var sink = new TestSink();
var context = TestUtils.CreateTestContext(sink); var context = TestUtils.CreateTestContext(sink);
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseWithoutPublicNotCacheable); LoggedMessage.ResponseWithoutPublicNotCacheable);
@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Public = true Public = true
}; };
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.True(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -178,7 +178,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
NoCache = true NoCache = true
}; };
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseWithNoCacheNotCacheable); LoggedMessage.ResponseWithNoCacheNotCacheable);
@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Public = true Public = true
}; };
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseWithNoStoreNotCacheable); LoggedMessage.ResponseWithNoStoreNotCacheable);
@ -215,7 +215,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
NoStore = true NoStore = true
}; };
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseWithNoStoreNotCacheable); LoggedMessage.ResponseWithNoStoreNotCacheable);
@ -232,7 +232,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
context.HttpContext.Response.Headers[HeaderNames.SetCookie] = "cookieName=cookieValue"; context.HttpContext.Response.Headers[HeaderNames.SetCookie] = "cookieName=cookieValue";
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseWithSetCookieNotCacheable); LoggedMessage.ResponseWithSetCookieNotCacheable);
@ -249,7 +249,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
context.HttpContext.Response.Headers[HeaderNames.Vary] = "*"; context.HttpContext.Response.Headers[HeaderNames.Vary] = "*";
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseWithVaryStarNotCacheable); LoggedMessage.ResponseWithVaryStarNotCacheable);
@ -266,7 +266,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Private = true Private = true
}; };
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseWithPrivateNotCacheable); LoggedMessage.ResponseWithPrivateNotCacheable);
@ -284,7 +284,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Public = true Public = true
}; };
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.True(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -347,7 +347,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Public = true Public = true
}; };
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ResponseWithUnsuccessfulStatusCodeNotCacheable); LoggedMessage.ResponseWithUnsuccessfulStatusCodeNotCacheable);
@ -368,7 +368,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow; context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = DateTimeOffset.MaxValue; context.ResponseTime = DateTimeOffset.MaxValue;
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.True(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -388,7 +388,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow; context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow; context.ResponseTime = utcNow;
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationExpiresExceeded); LoggedMessage.ExpirationExpiresExceeded);
@ -410,7 +410,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow; context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow + TimeSpan.FromSeconds(9); context.ResponseTime = utcNow + TimeSpan.FromSeconds(9);
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.True(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -430,7 +430,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow; context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow + TimeSpan.FromSeconds(10); context.ResponseTime = utcNow + TimeSpan.FromSeconds(10);
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationMaxAgeExceeded); LoggedMessage.ExpirationMaxAgeExceeded);
@ -452,7 +452,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow; context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow + TimeSpan.FromSeconds(11); context.ResponseTime = utcNow + TimeSpan.FromSeconds(11);
Assert.True(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.True(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -472,7 +472,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.TypedResponseHeaders.Date = utcNow; context.TypedResponseHeaders.Date = utcNow;
context.ResponseTime = utcNow + TimeSpan.FromSeconds(5); context.ResponseTime = utcNow + TimeSpan.FromSeconds(5);
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context)); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationSharedMaxAgeExceeded); LoggedMessage.ExpirationSharedMaxAgeExceeded);
@ -488,7 +488,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.CachedEntryAge = TimeSpan.MaxValue; context.CachedEntryAge = TimeSpan.MaxValue;
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary()); context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary());
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.True(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -508,7 +508,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
}; };
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.True(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -529,7 +529,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow Expires = utcNow
}; };
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.False(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationExpiresExceeded); LoggedMessage.ExpirationExpiresExceeded);
@ -553,7 +553,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow Expires = utcNow
}; };
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.True(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -575,7 +575,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow Expires = utcNow
}; };
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.False(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationMaxAgeExceeded); LoggedMessage.ExpirationMaxAgeExceeded);
@ -600,7 +600,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow Expires = utcNow
}; };
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.True(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
Assert.Empty(sink.Writes); Assert.Empty(sink.Writes);
} }
@ -623,7 +623,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Expires = utcNow Expires = utcNow
}; };
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.False(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationSharedMaxAgeExceeded); LoggedMessage.ExpirationSharedMaxAgeExceeded);
@ -648,7 +648,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
context.CachedEntryAge = TimeSpan.FromSeconds(3); context.CachedEntryAge = TimeSpan.FromSeconds(3);
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.False(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationMinFreshAdded, LoggedMessage.ExpirationMinFreshAdded,
@ -673,7 +673,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
context.CachedEntryAge = TimeSpan.FromSeconds(5); context.CachedEntryAge = TimeSpan.FromSeconds(5);
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.False(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationMaxAgeExceeded); LoggedMessage.ExpirationMaxAgeExceeded);
@ -699,7 +699,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
context.CachedEntryAge = TimeSpan.FromSeconds(6); context.CachedEntryAge = TimeSpan.FromSeconds(6);
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.True(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationMaxStaleSatisfied); LoggedMessage.ExpirationMaxStaleSatisfied);
@ -725,7 +725,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
context.CachedEntryAge = TimeSpan.FromSeconds(6); context.CachedEntryAge = TimeSpan.FromSeconds(6);
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.False(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationMaxAgeExceeded); LoggedMessage.ExpirationMaxAgeExceeded);
@ -752,7 +752,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
context.CachedEntryAge = TimeSpan.FromSeconds(6); context.CachedEntryAge = TimeSpan.FromSeconds(6);
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context)); Assert.False(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context));
TestUtils.AssertLoggedMessages( TestUtils.AssertLoggedMessages(
sink.Writes, sink.Writes,
LoggedMessage.ExpirationMustRevalidate); LoggedMessage.ExpirationMustRevalidate);

View File

@ -14,12 +14,12 @@ using Xunit;
namespace Microsoft.AspNetCore.ResponseCaching.Tests namespace Microsoft.AspNetCore.ResponseCaching.Tests
{ {
public class ResponseCacheTests public class ResponseCachingTests
{ {
[Fact] [Fact]
public async void ServesCachedContent_IfAvailable() public async void ServesCachedContent_IfAvailable()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(); var builders = TestUtils.CreateBuildersWithResponseCaching();
foreach (var builder in builders) foreach (var builder in builders)
{ {
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfNotAvailable() public async void ServesFreshContent_IfNotAvailable()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(); var builders = TestUtils.CreateBuildersWithResponseCaching();
foreach (var builder in builders) foreach (var builder in builders)
{ {
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync("/different"); var subsequentResponse = await client.GetAsync("/different");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfVaryHeader_Matches() public async void ServesCachedContent_IfVaryHeader_Matches()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From; context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfVaryHeader_Mismatches() public async void ServesFreshContent_IfVaryHeader_Mismatches()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From; context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
client.DefaultRequestHeaders.From = "user2@example.com"; client.DefaultRequestHeaders.From = "user2@example.com";
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -102,9 +102,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfVaryQueryKeys_Matches() public async void ServesCachedContent_IfVaryQueryKeys_Matches()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Features.Get<IResponseCacheFeature>().VaryByQueryKeys = "query"; context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "query" };
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
}); });
@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync("?query=value"); var initialResponse = await client.GetAsync("?query=value");
var subsequentResponse = await client.GetAsync("?query=value"); var subsequentResponse = await client.GetAsync("?query=value");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -124,9 +124,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfVaryQueryKeysExplicit_Matches_QueryKeyCaseInsensitive() public async void ServesCachedContent_IfVaryQueryKeysExplicit_Matches_QueryKeyCaseInsensitive()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Features.Get<IResponseCacheFeature>().VaryByQueryKeys = new[] { "QueryA", "queryb" }; context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryA", "queryb" };
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
}); });
@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb"); var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb");
var subsequentResponse = await client.GetAsync("?QueryA=valuea&QueryB=valueb"); var subsequentResponse = await client.GetAsync("?QueryA=valuea&QueryB=valueb");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -146,9 +146,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_QueryKeyCaseInsensitive() public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_QueryKeyCaseInsensitive()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Features.Get<IResponseCacheFeature>().VaryByQueryKeys = new[] { "*" }; context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
}); });
@ -160,7 +160,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb"); var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb");
var subsequentResponse = await client.GetAsync("?QueryA=valuea&QueryB=valueb"); var subsequentResponse = await client.GetAsync("?QueryA=valuea&QueryB=valueb");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -168,9 +168,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfVaryQueryKeyExplicit_Matches_OrderInsensitive() public async void ServesCachedContent_IfVaryQueryKeyExplicit_Matches_OrderInsensitive()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Features.Get<IResponseCacheFeature>().VaryByQueryKeys = new[] { "QueryB", "QueryA" }; context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryB", "QueryA" };
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
}); });
@ -182,7 +182,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync("?QueryA=ValueA&QueryB=ValueB"); var initialResponse = await client.GetAsync("?QueryA=ValueA&QueryB=ValueB");
var subsequentResponse = await client.GetAsync("?QueryB=ValueB&QueryA=ValueA"); var subsequentResponse = await client.GetAsync("?QueryB=ValueB&QueryA=ValueA");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -190,9 +190,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_OrderInsensitive() public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_OrderInsensitive()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Features.Get<IResponseCacheFeature>().VaryByQueryKeys = new[] { "*" }; context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
}); });
@ -204,7 +204,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync("?QueryA=ValueA&QueryB=ValueB"); var initialResponse = await client.GetAsync("?QueryA=ValueA&QueryB=ValueB");
var subsequentResponse = await client.GetAsync("?QueryB=ValueB&QueryA=ValueA"); var subsequentResponse = await client.GetAsync("?QueryB=ValueB&QueryA=ValueA");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -212,9 +212,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfVaryQueryKey_Mismatches() public async void ServesFreshContent_IfVaryQueryKey_Mismatches()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Features.Get<IResponseCacheFeature>().VaryByQueryKeys = "query"; context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "query" };
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
}); });
@ -226,7 +226,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync("?query=value"); var initialResponse = await client.GetAsync("?query=value");
var subsequentResponse = await client.GetAsync("?query=value2"); var subsequentResponse = await client.GetAsync("?query=value2");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -234,9 +234,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfVaryQueryKeyExplicit_Mismatch_QueryKeyCaseSensitive() public async void ServesFreshContent_IfVaryQueryKeyExplicit_Mismatch_QueryKeyCaseSensitive()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Features.Get<IResponseCacheFeature>().VaryByQueryKeys = new[] { "QueryA", "QueryB" }; context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryA", "QueryB" };
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
}); });
@ -248,7 +248,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb"); var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb");
var subsequentResponse = await client.GetAsync("?querya=ValueA&queryb=ValueB"); var subsequentResponse = await client.GetAsync("?querya=ValueA&queryb=ValueB");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -256,9 +256,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfVaryQueryKeyStar_Mismatch_QueryKeyValueCaseSensitive() public async void ServesFreshContent_IfVaryQueryKeyStar_Mismatch_QueryKeyValueCaseSensitive()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Features.Get<IResponseCacheFeature>().VaryByQueryKeys = new[] { "*" }; context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
}); });
@ -270,7 +270,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb"); var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb");
var subsequentResponse = await client.GetAsync("?querya=ValueA&queryb=ValueB"); var subsequentResponse = await client.GetAsync("?querya=ValueA&queryb=ValueB");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -278,7 +278,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfRequestRequirements_NotMet() public async void ServesFreshContent_IfRequestRequirements_NotMet()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(); var builders = TestUtils.CreateBuildersWithResponseCaching();
foreach (var builder in builders) foreach (var builder in builders)
{ {
@ -292,7 +292,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -300,7 +300,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void Serves504_IfOnlyIfCachedHeader_IsSpecified() public async void Serves504_IfOnlyIfCachedHeader_IsSpecified()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(); var builders = TestUtils.CreateBuildersWithResponseCaching();
foreach (var builder in builders) foreach (var builder in builders)
{ {
@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfSetCookie_IsSpecified() public async void ServesFreshContent_IfSetCookie_IsSpecified()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
var headers = context.Response.Headers[HeaderNames.SetCookie] = "cookieName=cookieValue"; var headers = context.Response.Headers[HeaderNames.SetCookie] = "cookieName=cookieValue";
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -345,7 +345,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfIHttpSendFileFeature_NotUsed() public async void ServesCachedContent_IfIHttpSendFileFeature_NotUsed()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(app => var builders = TestUtils.CreateBuildersWithResponseCaching(app =>
{ {
app.Use(async (context, next) => app.Use(async (context, next) =>
{ {
@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -370,7 +370,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfIHttpSendFileFeature_Used() public async void ServesFreshContent_IfIHttpSendFileFeature_Used()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache( var builders = TestUtils.CreateBuildersWithResponseCaching(
app => app =>
{ {
app.Use(async (context, next) => app.Use(async (context, next) =>
@ -393,7 +393,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -401,7 +401,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfSubsequentRequest_ContainsNoStore() public async void ServesCachedContent_IfSubsequentRequest_ContainsNoStore()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(); var builders = TestUtils.CreateBuildersWithResponseCaching();
foreach (var builder in builders) foreach (var builder in builders)
{ {
@ -415,7 +415,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}; };
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -423,7 +423,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfInitialRequestContains_NoStore() public async void ServesFreshContent_IfInitialRequestContains_NoStore()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(); var builders = TestUtils.CreateBuildersWithResponseCaching();
foreach (var builder in builders) foreach (var builder in builders)
{ {
@ -437,7 +437,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -445,7 +445,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void Serves304_IfIfModifiedSince_Satisfied() public async void Serves304_IfIfModifiedSince_Satisfied()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(); var builders = TestUtils.CreateBuildersWithResponseCaching();
foreach (var builder in builders) foreach (var builder in builders)
{ {
@ -465,7 +465,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfIfModifiedSince_NotSatisfied() public async void ServesCachedContent_IfIfModifiedSince_NotSatisfied()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(); var builders = TestUtils.CreateBuildersWithResponseCaching();
foreach (var builder in builders) foreach (var builder in builders)
{ {
@ -476,7 +476,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
client.DefaultRequestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue; client.DefaultRequestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue;
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -484,7 +484,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void Serves304_IfIfNoneMatch_Satisfied() public async void Serves304_IfIfNoneMatch_Satisfied()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
var headers = context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\""); var headers = context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\"");
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
@ -508,7 +508,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfIfNoneMatch_NotSatisfied() public async void ServesCachedContent_IfIfNoneMatch_NotSatisfied()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
var headers = context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\""); var headers = context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\"");
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
@ -523,7 +523,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
client.DefaultRequestHeaders.IfNoneMatch.Add(new System.Net.Http.Headers.EntityTagHeaderValue("\"E2\"")); client.DefaultRequestHeaders.IfNoneMatch.Add(new System.Net.Http.Headers.EntityTagHeaderValue("\"E2\""));
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -531,7 +531,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfBodySize_IsCacheable() public async void ServesCachedContent_IfBodySize_IsCacheable()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(options: new ResponseCacheOptions() var builders = TestUtils.CreateBuildersWithResponseCaching(options: new ResponseCachingOptions()
{ {
MaximumBodySize = 100 MaximumBodySize = 100
}); });
@ -544,7 +544,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -552,7 +552,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfBodySize_IsNotCacheable() public async void ServesFreshContent_IfBodySize_IsNotCacheable()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(options: new ResponseCacheOptions() var builders = TestUtils.CreateBuildersWithResponseCaching(options: new ResponseCachingOptions()
{ {
MaximumBodySize = 1 MaximumBodySize = 1
}); });
@ -565,7 +565,28 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var initialResponse = await client.GetAsync(""); var initialResponse = await client.GetAsync("");
var subsequentResponse = await client.GetAsync("/different"); var subsequentResponse = await client.GetAsync("/different");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
}
}
}
[Fact]
public async void ServesFreshContent_CaseSensitivePaths_IsNotCacheable()
{
var builders = TestUtils.CreateBuildersWithResponseCaching(options: new ResponseCachingOptions()
{
UseCaseSensitivePaths = true
});
foreach (var builder in builders)
{
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("/path");
var subsequentResponse = await client.GetAsync("/Path");
await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -573,7 +594,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_WithoutReplacingCachedVaryBy_OnCacheMiss() public async void ServesCachedContent_WithoutReplacingCachedVaryBy_OnCacheMiss()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From; context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
@ -591,7 +612,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
client.DefaultRequestHeaders.From = "user@example.com"; client.DefaultRequestHeaders.From = "user@example.com";
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -599,7 +620,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesFreshContent_IfCachedVaryByUpdated_OnCacheMiss() public async void ServesFreshContent_IfCachedVaryByUpdated_OnCacheMiss()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Response.Headers[HeaderNames.Vary] = context.Request.Headers[HeaderNames.Pragma]; context.Response.Headers[HeaderNames.Vary] = context.Request.Headers[HeaderNames.Pragma];
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
@ -626,7 +647,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
client.DefaultRequestHeaders.MaxForwards = 1; client.DefaultRequestHeaders.MaxForwards = 1;
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse); await AssertFreshResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
@ -634,7 +655,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
[Fact] [Fact]
public async void ServesCachedContent_IfCachedVaryByNotUpdated_OnCacheMiss() public async void ServesCachedContent_IfCachedVaryByNotUpdated_OnCacheMiss()
{ {
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) => var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
{ {
context.Response.Headers[HeaderNames.Vary] = context.Request.Headers[HeaderNames.Pragma]; context.Response.Headers[HeaderNames.Vary] = context.Request.Headers[HeaderNames.Pragma];
await TestUtils.TestRequestDelegate(context); await TestUtils.TestRequestDelegate(context);
@ -661,12 +682,12 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
client.DefaultRequestHeaders.MaxForwards = 1; client.DefaultRequestHeaders.MaxForwards = 1;
var subsequentResponse = await client.GetAsync(""); var subsequentResponse = await client.GetAsync("");
await AssertResponseCachedAsync(initialResponse, subsequentResponse); await AssertCachedResponseAsync(initialResponse, subsequentResponse);
} }
} }
} }
private static async Task AssertResponseCachedAsync(HttpResponseMessage initialResponse, HttpResponseMessage subsequentResponse) private static async Task AssertCachedResponseAsync(HttpResponseMessage initialResponse, HttpResponseMessage subsequentResponse)
{ {
initialResponse.EnsureSuccessStatusCode(); initialResponse.EnsureSuccessStatusCode();
subsequentResponse.EnsureSuccessStatusCode(); subsequentResponse.EnsureSuccessStatusCode();
@ -679,7 +700,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Assert.Equal(await initialResponse.Content.ReadAsStringAsync(), await subsequentResponse.Content.ReadAsStringAsync()); Assert.Equal(await initialResponse.Content.ReadAsStringAsync(), await subsequentResponse.Content.ReadAsStringAsync());
} }
private static async Task AssertResponseNotCachedAsync(HttpResponseMessage initialResponse, HttpResponseMessage subsequentResponse) private static async Task AssertFreshResponseAsync(HttpResponseMessage initialResponse, HttpResponseMessage subsequentResponse)
{ {
initialResponse.EnsureSuccessStatusCode(); initialResponse.EnsureSuccessStatusCode();
subsequentResponse.EnsureSuccessStatusCode(); subsequentResponse.EnsureSuccessStatusCode();

View File

@ -44,92 +44,96 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
await context.Response.WriteAsync(uniqueId); await context.Response.WriteAsync(uniqueId);
}; };
internal static IResponseCacheKeyProvider CreateTestKeyProvider() internal static IResponseCachingKeyProvider CreateTestKeyProvider()
{ {
return CreateTestKeyProvider(new ResponseCacheOptions()); return CreateTestKeyProvider(new ResponseCachingOptions());
} }
internal static IResponseCacheKeyProvider CreateTestKeyProvider(ResponseCacheOptions options) internal static IResponseCachingKeyProvider CreateTestKeyProvider(ResponseCachingOptions options)
{ {
return new ResponseCacheKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options)); return new ResponseCachingKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options));
} }
internal static IEnumerable<IWebHostBuilder> CreateBuildersWithResponseCache( internal static IEnumerable<IWebHostBuilder> CreateBuildersWithResponseCaching(
Action<IApplicationBuilder> configureDelegate = null, Action<IApplicationBuilder> configureDelegate = null,
ResponseCacheOptions options = null, ResponseCachingOptions options = null,
RequestDelegate requestDelegate = null) RequestDelegate requestDelegate = null)
{ {
if (configureDelegate == null) if (configureDelegate == null)
{ {
configureDelegate = app => { }; configureDelegate = app => { };
} }
if (options == null)
{
options = new ResponseCacheOptions();
}
if (requestDelegate == null) if (requestDelegate == null)
{ {
requestDelegate = TestRequestDelegate; requestDelegate = TestRequestDelegate;
} }
// Test with MemoryResponseCacheStore // Test with in memory ResponseCache
yield return new WebHostBuilder() yield return new WebHostBuilder()
.ConfigureServices(services => .ConfigureServices(services =>
{ {
services.AddMemoryResponseCacheStore(); services.AddResponseCaching(responseCachingOptions =>
{
if (options != null)
{
responseCachingOptions.MaximumBodySize = options.MaximumBodySize;
responseCachingOptions.UseCaseSensitivePaths = options.UseCaseSensitivePaths;
responseCachingOptions.SystemClock = options.SystemClock;
}
});
}) })
.Configure(app => .Configure(app =>
{ {
configureDelegate(app); configureDelegate(app);
app.UseResponseCache(options); app.UseResponseCaching();
app.Run(requestDelegate); app.Run(requestDelegate);
}); });
} }
internal static ResponseCacheMiddleware CreateTestMiddleware( internal static ResponseCachingMiddleware CreateTestMiddleware(
IResponseCacheStore store = null, IResponseCache cache = null,
ResponseCacheOptions options = null, ResponseCachingOptions options = null,
TestSink testSink = null, TestSink testSink = null,
IResponseCacheKeyProvider keyProvider = null, IResponseCachingKeyProvider keyProvider = null,
IResponseCachePolicyProvider policyProvider = null) IResponseCachingPolicyProvider policyProvider = null)
{ {
if (store == null) if (cache == null)
{ {
store = new TestResponseCacheStore(); cache = new TestResponseCache();
} }
if (options == null) if (options == null)
{ {
options = new ResponseCacheOptions(); options = new ResponseCachingOptions();
} }
if (keyProvider == null) if (keyProvider == null)
{ {
keyProvider = new ResponseCacheKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options)); keyProvider = new ResponseCachingKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options));
} }
if (policyProvider == null) if (policyProvider == null)
{ {
policyProvider = new TestResponseCachePolicyProvider(); policyProvider = new TestResponseCachingPolicyProvider();
} }
return new ResponseCacheMiddleware( return new ResponseCachingMiddleware(
httpContext => TaskCache.CompletedTask, httpContext => TaskCache.CompletedTask,
Options.Create(options), Options.Create(options),
testSink == null ? (ILoggerFactory)NullLoggerFactory.Instance : new TestLoggerFactory(testSink, true), testSink == null ? (ILoggerFactory)NullLoggerFactory.Instance : new TestLoggerFactory(testSink, true),
policyProvider, policyProvider,
store, cache,
keyProvider); keyProvider);
} }
internal static ResponseCacheContext CreateTestContext() internal static ResponseCachingContext CreateTestContext()
{ {
return new ResponseCacheContext(new DefaultHttpContext(), NullLogger.Instance) return new ResponseCachingContext(new DefaultHttpContext(), NullLogger.Instance)
{ {
ResponseTime = DateTimeOffset.UtcNow ResponseTime = DateTimeOffset.UtcNow
}; };
} }
internal static ResponseCacheContext CreateTestContext(ITestSink testSink) internal static ResponseCachingContext CreateTestContext(ITestSink testSink)
{ {
return new ResponseCacheContext(new DefaultHttpContext(), new TestLogger("ResponseCachingTests", testSink, true)) return new ResponseCachingContext(new DefaultHttpContext(), new TestLogger("ResponseCachingTests", testSink, true))
{ {
ResponseTime = DateTimeOffset.UtcNow ResponseTime = DateTimeOffset.UtcNow
}; };
@ -195,21 +199,21 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
} }
internal class TestResponseCachePolicyProvider : IResponseCachePolicyProvider internal class TestResponseCachingPolicyProvider : IResponseCachingPolicyProvider
{ {
public bool IsCachedEntryFresh(ResponseCacheContext context) => true; public bool IsCachedEntryFresh(ResponseCachingContext context) => true;
public bool IsRequestCacheable(ResponseCacheContext context) => true; public bool IsRequestCacheable(ResponseCachingContext context) => true;
public bool IsResponseCacheable(ResponseCacheContext context) => true; public bool IsResponseCacheable(ResponseCachingContext context) => true;
} }
internal class TestResponseCacheKeyProvider : IResponseCacheKeyProvider internal class TestResponseCachingKeyProvider : IResponseCachingKeyProvider
{ {
private readonly string _baseKey; private readonly string _baseKey;
private readonly StringValues _varyKey; private readonly StringValues _varyKey;
public TestResponseCacheKeyProvider(string lookupBaseKey = null, StringValues? lookupVaryKey = null) public TestResponseCachingKeyProvider(string lookupBaseKey = null, StringValues? lookupVaryKey = null)
{ {
_baseKey = lookupBaseKey; _baseKey = lookupBaseKey;
if (lookupVaryKey.HasValue) if (lookupVaryKey.HasValue)
@ -218,7 +222,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
} }
public IEnumerable<string> CreateLookupVaryByKeys(ResponseCacheContext context) public IEnumerable<string> CreateLookupVaryByKeys(ResponseCachingContext context)
{ {
foreach (var varyKey in _varyKey) foreach (var varyKey in _varyKey)
{ {
@ -226,18 +230,18 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
} }
public string CreateBaseKey(ResponseCacheContext context) public string CreateBaseKey(ResponseCachingContext context)
{ {
return _baseKey; return _baseKey;
} }
public string CreateStorageVaryByKey(ResponseCacheContext context) public string CreateStorageVaryByKey(ResponseCachingContext context)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }
internal class TestResponseCacheStore : IResponseCacheStore internal class TestResponseCache : IResponseCache
{ {
private readonly IDictionary<string, IResponseCacheEntry> _storage = new Dictionary<string, IResponseCacheEntry>(); private readonly IDictionary<string, IResponseCacheEntry> _storage = new Dictionary<string, IResponseCacheEntry>();
public int GetCount { get; private set; } public int GetCount { get; private set; }