Stricter expiration checks to avoid serving responses when max-age is 0
Cache parsed response headers for performance
This commit is contained in:
parent
c30d471c27
commit
6891d00032
|
|
@ -19,6 +19,10 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
private ResponseHeaders _responseHeaders;
|
private ResponseHeaders _responseHeaders;
|
||||||
private CacheControlHeaderValue _requestCacheControl;
|
private CacheControlHeaderValue _requestCacheControl;
|
||||||
private CacheControlHeaderValue _responseCacheControl;
|
private CacheControlHeaderValue _responseCacheControl;
|
||||||
|
private DateTimeOffset? _responseDate;
|
||||||
|
private bool _parsedResponseDate;
|
||||||
|
private DateTimeOffset? _responseExpires;
|
||||||
|
private bool _parsedResponseExpires;
|
||||||
|
|
||||||
internal ResponseCacheContext(
|
internal ResponseCacheContext(
|
||||||
HttpContext httpContext)
|
HttpContext httpContext)
|
||||||
|
|
@ -101,5 +105,37 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
return _responseCacheControl;
|
return _responseCacheControl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal DateTimeOffset? ResponseDate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_parsedResponseDate)
|
||||||
|
{
|
||||||
|
_parsedResponseDate = true;
|
||||||
|
_responseDate = TypedResponseHeaders.Date;
|
||||||
|
}
|
||||||
|
return _responseDate;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
// Don't reparse the response date again if it's explicitly set
|
||||||
|
_parsedResponseDate = true;
|
||||||
|
_responseDate = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DateTimeOffset? ResponseExpires
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_parsedResponseExpires)
|
||||||
|
{
|
||||||
|
_parsedResponseExpires = true;
|
||||||
|
_responseExpires = TypedResponseHeaders.Expires;
|
||||||
|
}
|
||||||
|
return _responseExpires;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
if (body.Length > 0)
|
if (body.Length > 0)
|
||||||
{
|
{
|
||||||
// Add a content-length if required
|
// Add a content-length if required
|
||||||
if (response.ContentLength == null && StringValues.IsNullOrEmpty(response.Headers[HeaderNames.TransferEncoding]))
|
if (!response.ContentLength.HasValue && StringValues.IsNullOrEmpty(response.Headers[HeaderNames.TransferEncoding]))
|
||||||
{
|
{
|
||||||
response.ContentLength = body.Length;
|
response.ContentLength = body.Length;
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +204,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
var varyParamsValue = context.HttpContext.GetResponseCacheFeature()?.VaryByParams ?? StringValues.Empty;
|
var varyParamsValue = context.HttpContext.GetResponseCacheFeature()?.VaryByParams ?? StringValues.Empty;
|
||||||
context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ??
|
context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ??
|
||||||
context.ResponseCacheControlHeaderValue.MaxAge ??
|
context.ResponseCacheControlHeaderValue.MaxAge ??
|
||||||
(context.TypedResponseHeaders.Expires - context.ResponseTime) ??
|
(context.ResponseExpires - context.ResponseTime) ??
|
||||||
DefaultExpirationTimeSpan;
|
DefaultExpirationTimeSpan;
|
||||||
|
|
||||||
// Check if any vary rules exist
|
// Check if any vary rules exist
|
||||||
|
|
@ -234,16 +234,18 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure date header is set
|
// Ensure date header is set
|
||||||
if (context.TypedResponseHeaders.Date == null)
|
if (!context.ResponseDate.HasValue)
|
||||||
{
|
{
|
||||||
context.TypedResponseHeaders.Date = context.ResponseTime;
|
context.ResponseDate = context.ResponseTime;
|
||||||
|
// Setting the date on the raw response headers.
|
||||||
|
context.TypedResponseHeaders.Date = context.ResponseDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the response on the state
|
// Store the response on the state
|
||||||
context.CachedResponse = new CachedResponse
|
context.CachedResponse = new CachedResponse
|
||||||
{
|
{
|
||||||
BodyKeyPrefix = FastGuid.NewGuid().IdString,
|
BodyKeyPrefix = FastGuid.NewGuid().IdString,
|
||||||
Created = context.TypedResponseHeaders.Date.Value,
|
Created = context.ResponseDate.Value,
|
||||||
StatusCode = context.HttpContext.Response.StatusCode
|
StatusCode = context.HttpContext.Response.StatusCode
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -263,10 +265,10 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
|
|
||||||
internal async Task FinalizeCacheBodyAsync(ResponseCacheContext context)
|
internal async Task FinalizeCacheBodyAsync(ResponseCacheContext context)
|
||||||
{
|
{
|
||||||
|
var contentLength = context.TypedResponseHeaders.ContentLength;
|
||||||
if (context.ShouldCacheResponse &&
|
if (context.ShouldCacheResponse &&
|
||||||
context.ResponseCacheStream.BufferingEnabled &&
|
context.ResponseCacheStream.BufferingEnabled &&
|
||||||
(context.TypedResponseHeaders.ContentLength == null ||
|
(!contentLength.HasValue || contentLength == context.ResponseCacheStream.BufferedStream.Length))
|
||||||
context.TypedResponseHeaders.ContentLength == context.ResponseCacheStream.BufferedStream.Length))
|
|
||||||
{
|
{
|
||||||
if (context.ResponseCacheStream.BufferedStream.Length >= _options.MinimumSplitBodySize)
|
if (context.ResponseCacheStream.BufferedStream.Length >= _options.MinimumSplitBodySize)
|
||||||
{
|
{
|
||||||
|
|
@ -355,9 +357,13 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (context.TypedRequestHeaders.IfUnmodifiedSince != null && (cachedResponseHeaders.LastModified ?? cachedResponseHeaders.Date) <= context.TypedRequestHeaders.IfUnmodifiedSince)
|
else
|
||||||
{
|
{
|
||||||
return true;
|
var ifUnmodifiedSince = context.TypedRequestHeaders.IfUnmodifiedSince;
|
||||||
|
if (ifUnmodifiedSince != null && (cachedResponseHeaders.LastModified ?? cachedResponseHeaders.Date) <= ifUnmodifiedSince)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -100,35 +100,35 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check response freshness
|
// Check response freshness
|
||||||
if (context.TypedResponseHeaders.Date == null)
|
if (!context.ResponseDate.HasValue)
|
||||||
{
|
{
|
||||||
if (context.ResponseCacheControlHeaderValue.SharedMaxAge == null &&
|
if (!context.ResponseCacheControlHeaderValue.SharedMaxAge.HasValue &&
|
||||||
context.ResponseCacheControlHeaderValue.MaxAge == null &&
|
!context.ResponseCacheControlHeaderValue.MaxAge.HasValue &&
|
||||||
context.ResponseTime > context.TypedResponseHeaders.Expires)
|
context.ResponseTime >= context.ResponseExpires)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var age = context.ResponseTime - context.TypedResponseHeaders.Date.Value;
|
var age = context.ResponseTime - context.ResponseDate.Value;
|
||||||
|
|
||||||
// Validate shared max age
|
// Validate shared max age
|
||||||
if (age > context.ResponseCacheControlHeaderValue.SharedMaxAge)
|
if (age >= context.ResponseCacheControlHeaderValue.SharedMaxAge)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (context.ResponseCacheControlHeaderValue.SharedMaxAge == null)
|
else if (!context.ResponseCacheControlHeaderValue.SharedMaxAge.HasValue)
|
||||||
{
|
{
|
||||||
// Validate max age
|
// Validate max age
|
||||||
if (age > context.ResponseCacheControlHeaderValue.MaxAge)
|
if (age >= context.ResponseCacheControlHeaderValue.MaxAge)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (context.ResponseCacheControlHeaderValue.MaxAge == null)
|
else if (!context.ResponseCacheControlHeaderValue.MaxAge.HasValue)
|
||||||
{
|
{
|
||||||
// Validate expiration
|
// Validate expiration
|
||||||
if (context.ResponseTime > context.TypedResponseHeaders.Expires)
|
if (context.ResponseTime >= context.ResponseExpires)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -145,21 +145,21 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
var cachedControlHeaders = context.CachedResponseHeaders.CacheControl ?? EmptyCacheControl;
|
var cachedControlHeaders = context.CachedResponseHeaders.CacheControl ?? EmptyCacheControl;
|
||||||
|
|
||||||
// Add min-fresh requirements
|
// Add min-fresh requirements
|
||||||
if (context.RequestCacheControlHeaderValue.MinFresh != null)
|
if (context.RequestCacheControlHeaderValue.MinFresh.HasValue)
|
||||||
{
|
{
|
||||||
age += context.RequestCacheControlHeaderValue.MinFresh.Value;
|
age += context.RequestCacheControlHeaderValue.MinFresh.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate shared max age, this overrides any max age settings for shared caches
|
// Validate shared max age, this overrides any max age settings for shared caches
|
||||||
if (age > cachedControlHeaders.SharedMaxAge)
|
if (age >= cachedControlHeaders.SharedMaxAge)
|
||||||
{
|
{
|
||||||
// shared max age implies must revalidate
|
// shared max age implies must revalidate
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (cachedControlHeaders.SharedMaxAge == null)
|
else if (!cachedControlHeaders.SharedMaxAge.HasValue)
|
||||||
{
|
{
|
||||||
// Validate max age
|
// Validate max age
|
||||||
if (age > cachedControlHeaders.MaxAge || age > context.RequestCacheControlHeaderValue.MaxAge)
|
if (age >= cachedControlHeaders.MaxAge || age >= context.RequestCacheControlHeaderValue.MaxAge)
|
||||||
{
|
{
|
||||||
// Must revalidate
|
// Must revalidate
|
||||||
if (cachedControlHeaders.MustRevalidate)
|
if (cachedControlHeaders.MustRevalidate)
|
||||||
|
|
@ -175,10 +175,10 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (cachedControlHeaders.MaxAge == null && context.RequestCacheControlHeaderValue.MaxAge == null)
|
else if (!cachedControlHeaders.MaxAge.HasValue && !context.RequestCacheControlHeaderValue.MaxAge.HasValue)
|
||||||
{
|
{
|
||||||
// Validate expiration
|
// Validate expiration
|
||||||
if (context.ResponseTime > context.CachedResponseHeaders.Expires)
|
if (context.ResponseTime >= context.CachedResponseHeaders.Expires)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void IsResponseCacheable_PastExpiry_NotAllowed()
|
public void IsResponseCacheable_AtExpiry_NotAllowed()
|
||||||
{
|
{
|
||||||
var context = TestUtils.CreateTestContext();
|
var context = TestUtils.CreateTestContext();
|
||||||
context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
|
context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
|
||||||
|
|
@ -302,7 +302,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
context.TypedResponseHeaders.Expires = utcNow;
|
context.TypedResponseHeaders.Expires = utcNow;
|
||||||
|
|
||||||
context.TypedResponseHeaders.Date = utcNow;
|
context.TypedResponseHeaders.Date = utcNow;
|
||||||
context.ResponseTime = DateTimeOffset.MaxValue;
|
context.ResponseTime = utcNow;
|
||||||
|
|
||||||
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
|
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
|
||||||
}
|
}
|
||||||
|
|
@ -338,7 +338,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
};
|
};
|
||||||
context.TypedResponseHeaders.Expires = utcNow;
|
context.TypedResponseHeaders.Expires = utcNow;
|
||||||
context.TypedResponseHeaders.Date = utcNow;
|
context.TypedResponseHeaders.Date = utcNow;
|
||||||
context.ResponseTime = utcNow + TimeSpan.FromSeconds(11);
|
context.ResponseTime = utcNow + TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
|
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
|
||||||
}
|
}
|
||||||
|
|
@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void IsResponseCacheable_SharedMaxAgeOverridesMaxAge_ToNotFresh()
|
public void IsResponseCacheable_SharedMaxAgeOverridesMaxAge_ToNotAllowed()
|
||||||
{
|
{
|
||||||
var utcNow = DateTimeOffset.UtcNow;
|
var utcNow = DateTimeOffset.UtcNow;
|
||||||
var context = TestUtils.CreateTestContext();
|
var context = TestUtils.CreateTestContext();
|
||||||
|
|
@ -374,7 +374,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
SharedMaxAge = TimeSpan.FromSeconds(5)
|
SharedMaxAge = TimeSpan.FromSeconds(5)
|
||||||
};
|
};
|
||||||
context.TypedResponseHeaders.Date = utcNow;
|
context.TypedResponseHeaders.Date = utcNow;
|
||||||
context.ResponseTime = utcNow + TimeSpan.FromSeconds(6);
|
context.ResponseTime = utcNow + TimeSpan.FromSeconds(5);
|
||||||
|
|
||||||
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
|
Assert.False(new ResponseCachePolicyProvider().IsResponseCacheable(context));
|
||||||
}
|
}
|
||||||
|
|
@ -408,17 +408,18 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void IsCachedEntryFresh_PastExpiry_IsNotFresh()
|
public void IsCachedEntryFresh_AtExpiry_IsNotFresh()
|
||||||
{
|
{
|
||||||
|
var utcNow = DateTimeOffset.UtcNow;
|
||||||
var context = TestUtils.CreateTestContext();
|
var context = TestUtils.CreateTestContext();
|
||||||
context.ResponseTime = DateTimeOffset.MaxValue;
|
context.ResponseTime = utcNow;
|
||||||
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
||||||
{
|
{
|
||||||
CacheControl = new CacheControlHeaderValue()
|
CacheControl = new CacheControlHeaderValue()
|
||||||
{
|
{
|
||||||
Public = true
|
Public = true
|
||||||
},
|
},
|
||||||
Expires = DateTimeOffset.UtcNow
|
Expires = utcNow
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
||||||
|
|
@ -449,7 +450,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
{
|
{
|
||||||
var utcNow = DateTimeOffset.UtcNow;
|
var utcNow = DateTimeOffset.UtcNow;
|
||||||
var context = TestUtils.CreateTestContext();
|
var context = TestUtils.CreateTestContext();
|
||||||
context.CachedEntryAge = TimeSpan.FromSeconds(11);
|
context.CachedEntryAge = TimeSpan.FromSeconds(10);
|
||||||
context.ResponseTime = utcNow + context.CachedEntryAge;
|
context.ResponseTime = utcNow + context.CachedEntryAge;
|
||||||
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
||||||
{
|
{
|
||||||
|
|
@ -490,7 +491,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
{
|
{
|
||||||
var utcNow = DateTimeOffset.UtcNow;
|
var utcNow = DateTimeOffset.UtcNow;
|
||||||
var context = TestUtils.CreateTestContext();
|
var context = TestUtils.CreateTestContext();
|
||||||
context.CachedEntryAge = TimeSpan.FromSeconds(6);
|
context.CachedEntryAge = TimeSpan.FromSeconds(5);
|
||||||
context.ResponseTime = utcNow + context.CachedEntryAge;
|
context.ResponseTime = utcNow + context.CachedEntryAge;
|
||||||
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
||||||
{
|
{
|
||||||
|
|
@ -512,7 +513,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
var context = TestUtils.CreateTestContext();
|
var context = TestUtils.CreateTestContext();
|
||||||
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
|
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
|
||||||
{
|
{
|
||||||
MinFresh = TimeSpan.FromSeconds(3)
|
MinFresh = TimeSpan.FromSeconds(2)
|
||||||
};
|
};
|
||||||
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
||||||
{
|
{
|
||||||
|
|
@ -542,7 +543,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
MaxAge = TimeSpan.FromSeconds(10),
|
MaxAge = TimeSpan.FromSeconds(10),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
context.CachedEntryAge = TimeSpan.FromSeconds(6);
|
context.CachedEntryAge = TimeSpan.FromSeconds(5);
|
||||||
|
|
||||||
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
||||||
}
|
}
|
||||||
|
|
@ -569,6 +570,28 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsCachedEntryFresh_MaxStaleOverridesFreshness_ButStillNotFresh()
|
||||||
|
{
|
||||||
|
var context = TestUtils.CreateTestContext();
|
||||||
|
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
|
||||||
|
{
|
||||||
|
MaxAge = TimeSpan.FromSeconds(5),
|
||||||
|
MaxStale = true, // This value must be set to true in order to specify MaxStaleLimit
|
||||||
|
MaxStaleLimit = TimeSpan.FromSeconds(6)
|
||||||
|
};
|
||||||
|
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
||||||
|
{
|
||||||
|
CacheControl = new CacheControlHeaderValue()
|
||||||
|
{
|
||||||
|
MaxAge = TimeSpan.FromSeconds(5),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
context.CachedEntryAge = TimeSpan.FromSeconds(6);
|
||||||
|
|
||||||
|
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void IsCachedEntryFresh_MustRevalidateOverridesRequestMaxStale_ToNotFresh()
|
public void IsCachedEntryFresh_MustRevalidateOverridesRequestMaxStale_ToNotFresh()
|
||||||
{
|
{
|
||||||
|
|
@ -591,27 +614,5 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
|
|
||||||
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
Assert.False(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void IsCachedEntryFresh_IgnoresRequestVerificationWhenSpecified()
|
|
||||||
{
|
|
||||||
var context = TestUtils.CreateTestContext();
|
|
||||||
context.TypedRequestHeaders.CacheControl = new CacheControlHeaderValue()
|
|
||||||
{
|
|
||||||
MinFresh = TimeSpan.FromSeconds(1),
|
|
||||||
MaxAge = TimeSpan.FromSeconds(3)
|
|
||||||
};
|
|
||||||
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
|
|
||||||
{
|
|
||||||
CacheControl = new CacheControlHeaderValue()
|
|
||||||
{
|
|
||||||
MaxAge = TimeSpan.FromSeconds(10),
|
|
||||||
SharedMaxAge = TimeSpan.FromSeconds(5)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
context.CachedEntryAge = TimeSpan.FromSeconds(3);
|
|
||||||
|
|
||||||
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue