Skip to content
This repository was archived by the owner on Nov 22, 2018. It is now read-only.

Restructure middleware flow #88

Merged
merged 1 commit into from
Jan 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,35 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
public interface IResponseCachingPolicyProvider
{
/// <summary>
/// Determine wehther the response cache middleware should be executed for the incoming HTTP request.
/// Determine whether the response caching logic should be attempted for the incoming HTTP request.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns><c>true</c> if the request is cacheable; otherwise <c>false</c>.</returns>
bool IsRequestCacheable(ResponseCachingContext context);
/// <returns><c>true</c> if response caching logic should be attempted; otherwise <c>false</c>.</returns>
bool AttemptResponseCaching(ResponseCachingContext context);

/// <summary>
/// Determine whether the response received by the middleware be cached for future requests.
/// Determine whether a cache lookup is allowed for the incoming HTTP request.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns><c>true</c> if cache lookup for this request is allowed; otherwise <c>false</c>.</returns>
bool AllowCacheLookup(ResponseCachingContext context);

/// <summary>
/// Determine whether storage of the response is allowed for the incoming HTTP request.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns><c>true</c> if storage of the response for this request is allowed; otherwise <c>false</c>.</returns>
bool AllowCacheStorage(ResponseCachingContext context);

/// <summary>
/// Determine whether the response received by the middleware can be cached for future requests.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns><c>true</c> if the response is cacheable; otherwise <c>false</c>.</returns>
bool IsResponseCacheable(ResponseCachingContext context);

/// <summary>
/// Determine 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 can be served.
/// </summary>
/// <param name="context">The <see cref="ResponseCachingContext"/>.</param>
/// <returns><c>true</c> if the cached entry is fresh; otherwise <c>false</c>.</returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal static class LoggerExtensions
private static Action<ILogger, int, Exception> _logResponseWithUnsuccessfulStatusCodeNotCacheable;
private static Action<ILogger, Exception> _logNotModifiedIfNoneMatchStar;
private static Action<ILogger, EntityTagHeaderValue, Exception> _logNotModifiedIfNoneMatchMatched;
private static Action<ILogger, DateTimeOffset, DateTimeOffset, Exception> _logNotModifiedIfUnmodifiedSinceSatisfied;
private static Action<ILogger, DateTimeOffset, DateTimeOffset, Exception> _logNotModifiedIfModifiedSinceSatisfied;
private static Action<ILogger, Exception> _logNotModifiedServed;
private static Action<ILogger, Exception> _logCachedResponseServed;
private static Action<ILogger, Exception> _logGatewayTimeoutServed;
Expand All @@ -40,6 +40,7 @@ internal static class LoggerExtensions
private static Action<ILogger, Exception> _logResponseCached;
private static Action<ILogger, Exception> _logResponseNotCached;
private static Action<ILogger, Exception> _logResponseContentLengthMismatchNotCached;
private static Action<ILogger, TimeSpan, TimeSpan, Exception> _logExpirationInfiniteMaxStaleSatisfied;

static LoggerExtensions()
{
Expand Down Expand Up @@ -70,7 +71,7 @@ static LoggerExtensions()
_logExpirationMustRevalidate = LoggerMessage.Define<TimeSpan, TimeSpan>(
logLevel: LogLevel.Debug,
eventId: 7,
formatString: "The age of the entry is {Age} and has exceeded the maximum age of {MaxAge} specified by the 'max-age' cache directive. It must be revalidated because the 'must-revalidate' cache directive is specified.");
formatString: "The age of the entry is {Age} and has exceeded the maximum age of {MaxAge} specified by the 'max-age' cache directive. It must be revalidated because the 'must-revalidate' or 'proxy-revalidate' cache directive is specified.");
_logExpirationMaxStaleSatisfied = LoggerMessage.Define<TimeSpan, TimeSpan, TimeSpan>(
logLevel: LogLevel.Debug,
eventId: 8,
Expand Down Expand Up @@ -119,10 +120,10 @@ static LoggerExtensions()
logLevel: LogLevel.Debug,
eventId: 19,
formatString: $"The ETag {{ETag}} in the '{HeaderNames.IfNoneMatch}' header matched the ETag of a cached entry.");
_logNotModifiedIfUnmodifiedSinceSatisfied = LoggerMessage.Define<DateTimeOffset, DateTimeOffset>(
_logNotModifiedIfModifiedSinceSatisfied = LoggerMessage.Define<DateTimeOffset, DateTimeOffset>(
logLevel: LogLevel.Debug,
eventId: 20,
formatString: $"The last modified date of {{LastModified}} is before the date {{IfUnmodifiedSince}} specified in the '{HeaderNames.IfUnmodifiedSince}' header.");
formatString: $"The last modified date of {{LastModified}} is before the date {{IfModifiedSince}} specified in the '{HeaderNames.IfModifiedSince}' header.");
_logNotModifiedServed = LoggerMessage.Define(
logLevel: LogLevel.Information,
eventId: 21,
Expand Down Expand Up @@ -155,6 +156,10 @@ static LoggerExtensions()
logLevel: LogLevel.Warning,
eventId: 28,
formatString: $"The response could not be cached for this request because the '{HeaderNames.ContentLength}' did not match the body length.");
_logExpirationInfiniteMaxStaleSatisfied = LoggerMessage.Define<TimeSpan, TimeSpan>(
logLevel: LogLevel.Debug,
eventId: 29,
formatString: "The age of the entry is {Age} and has exceeded the maximum age of {MaxAge} specified by the 'max-age' cache directive. However, the 'max-stale' cache directive was specified without an assigned value and a stale response of any age is accepted.");
}

internal static void LogRequestMethodNotCacheable(this ILogger logger, string method)
Expand Down Expand Up @@ -252,9 +257,9 @@ internal static void LogNotModifiedIfNoneMatchMatched(this ILogger logger, Entit
_logNotModifiedIfNoneMatchMatched(logger, etag, null);
}

internal static void LogNotModifiedIfUnmodifiedSinceSatisfied(this ILogger logger, DateTimeOffset lastModified, DateTimeOffset ifUnmodifiedSince)
internal static void LogNotModifiedIfModifiedSinceSatisfied(this ILogger logger, DateTimeOffset lastModified, DateTimeOffset ifModifiedSince)
{
_logNotModifiedIfUnmodifiedSinceSatisfied(logger, lastModified, ifUnmodifiedSince, null);
_logNotModifiedIfModifiedSinceSatisfied(logger, lastModified, ifModifiedSince, null);
}

internal static void LogNotModifiedServed(this ILogger logger)
Expand Down Expand Up @@ -296,5 +301,10 @@ internal static void LogResponseContentLengthMismatchNotCached(this ILogger logg
{
_logResponseContentLengthMismatchNotCached(logger, null);
}

internal static void LogExpirationInfiniteMaxStaleSatisfied(this ILogger logger, TimeSpan age, TimeSpan maxAge)
{
_logExpirationInfiniteMaxStaleSatisfied(logger, age, maxAge, null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal ResponseCachingContext(HttpContext httpContext, ILogger logger)

internal ILogger Logger { get; }

internal bool ShouldCacheResponse { get; set; }
internal bool ShouldCacheResponse { get; set; }

internal string BaseKey { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
{
public class ResponseCachingPolicyProvider : IResponseCachingPolicyProvider
{
public virtual bool IsRequestCacheable(ResponseCachingContext context)
public virtual bool AttemptResponseCaching(ResponseCachingContext context)
{
// Verify the method
var request = context.HttpContext.Request;

// Verify the method
if (!HttpMethods.IsGet(request.Method) && !HttpMethods.IsHead(request.Method))
{
context.Logger.LogRequestMethodNotCacheable(request.Method);
Expand All @@ -27,6 +28,13 @@ public virtual bool IsRequestCacheable(ResponseCachingContext context)
return false;
}

return true;
}

public virtual bool AllowCacheLookup(ResponseCachingContext context)
{
var request = context.HttpContext.Request;

// Verify request cache-control parameters
if (!StringValues.IsNullOrEmpty(request.Headers[HeaderNames.CacheControl]))
{
Expand All @@ -50,6 +58,12 @@ public virtual bool IsRequestCacheable(ResponseCachingContext context)
return true;
}

public virtual bool AllowCacheStorage(ResponseCachingContext context)
{
// Check request no-store
return !HeaderUtilities.ContainsCacheDirective(context.HttpContext.Request.Headers[HeaderNames.CacheControl], CacheControlHeaderValue.NoStoreString);
}

public virtual bool IsResponseCacheable(ResponseCachingContext context)
{
var responseCacheControlHeader = context.HttpContext.Response.Headers[HeaderNames.CacheControl];
Expand All @@ -61,9 +75,8 @@ public virtual bool IsResponseCacheable(ResponseCachingContext context)
return false;
}

// Check no-store
if (HeaderUtilities.ContainsCacheDirective(context.HttpContext.Request.Headers[HeaderNames.CacheControl], CacheControlHeaderValue.NoStoreString)
|| HeaderUtilities.ContainsCacheDirective(responseCacheControlHeader, CacheControlHeaderValue.NoStoreString))
// Check response no-store
if (HeaderUtilities.ContainsCacheDirective(responseCacheControlHeader, CacheControlHeaderValue.NoStoreString))
{
context.Logger.LogResponseWithNoStoreNotCacheable();
return false;
Expand Down Expand Up @@ -187,17 +200,26 @@ public virtual bool IsCachedEntryFresh(ResponseCachingContext context)
// Validate max age
if (age >= lowestMaxAge)
{
// Must revalidate
if (HeaderUtilities.ContainsCacheDirective(cachedCacheControlHeaders, CacheControlHeaderValue.MustRevalidateString))
// Must revalidate or proxy revalidate
if (HeaderUtilities.ContainsCacheDirective(cachedCacheControlHeaders, CacheControlHeaderValue.MustRevalidateString)
|| HeaderUtilities.ContainsCacheDirective(cachedCacheControlHeaders, CacheControlHeaderValue.ProxyRevalidateString))
{
context.Logger.LogExpirationMustRevalidate(age, lowestMaxAge.Value);
return false;
}

TimeSpan? requestMaxStale;
var maxStaleExist = HeaderUtilities.ContainsCacheDirective(requestCacheControlHeaders, CacheControlHeaderValue.MaxStaleString);
HeaderUtilities.TryParseSeconds(requestCacheControlHeaders, CacheControlHeaderValue.MaxStaleString, out requestMaxStale);

// Request allows stale values
// Request allows stale values with no age limit
if (maxStaleExist && !requestMaxStale.HasValue)
{
context.Logger.LogExpirationInfiniteMaxStaleSatisfied(age, lowestMaxAge.Value);
return true;
}

// Request allows stale values with age limit
if (requestMaxStale.HasValue && age - lowestMaxAge < requestMaxStale)
{
context.Logger.LogExpirationMaxStaleSatisfied(age, lowestMaxAge.Value, requestMaxStale.Value);
Expand Down
Loading