Date & Age handling
This commit is contained in:
parent
91d57c72bf
commit
7d716d2007
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
|
{
|
||||||
|
interface IResponseCachingOptions
|
||||||
|
{
|
||||||
|
int MaxCachedItemBytes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// 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 System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
|
|
@ -12,5 +13,6 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
internal IHeaderDictionary Headers { get; set; } = new HeaderDictionary();
|
internal IHeaderDictionary Headers { get; set; } = new HeaderDictionary();
|
||||||
|
|
||||||
internal byte[] Body { get; set; }
|
internal byte[] Body { get; set; }
|
||||||
|
public DateTimeOffset Created { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
// 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 System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
@ -14,6 +16,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
public class ResponseCachingContext
|
public class ResponseCachingContext
|
||||||
{
|
{
|
||||||
private string _cacheKey;
|
private string _cacheKey;
|
||||||
|
private RequestType _requestType;
|
||||||
|
|
||||||
public ResponseCachingContext(HttpContext httpContext, IResponseCache cache)
|
public ResponseCachingContext(HttpContext httpContext, IResponseCache cache)
|
||||||
{
|
{
|
||||||
|
|
@ -43,12 +46,24 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
|
|
||||||
private bool CacheResponse { get; set; }
|
private bool CacheResponse { get; set; }
|
||||||
|
|
||||||
|
private bool IsProxied { get; set; }
|
||||||
|
|
||||||
public bool CheckRequestAllowsCaching()
|
public bool CheckRequestAllowsCaching()
|
||||||
{
|
{
|
||||||
// Verify the method
|
// Verify the method
|
||||||
// TODO: What other methods should be supported?
|
// TODO: What other methods should be supported?
|
||||||
if (!string.Equals("GET", HttpContext.Request.Method, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals("GET", HttpContext.Request.Method, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
_requestType = RequestType.FullReponse;
|
||||||
|
}
|
||||||
|
else if (string.Equals("HEAD", HttpContext.Request.Method, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals("OPTIONS", HttpContext.Request.Method, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_requestType = RequestType.HeadersOnly;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_requestType = RequestType.NotCached;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,14 +152,24 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
response.Headers[pair.Key] = pair.Value;
|
response.Headers[pair.Key] = pair.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Update cache headers (Age)
|
// TODO: Allow setting proxied _isProxied
|
||||||
response.Headers["Served_From_Cache"] = DateTime.Now.ToString();
|
var age = Math.Max((DateTimeOffset.UtcNow - cacheEntry.Created).TotalSeconds, 0.0);
|
||||||
|
var ageString = (age > int.MaxValue ? int.MaxValue : (int)age).ToString(CultureInfo.InvariantCulture);
|
||||||
|
response.Headers[IsProxied ? "Age" : "X-Cache-Age"] = ageString;
|
||||||
|
|
||||||
// Copy the cached response body
|
if (_requestType == RequestType.HeadersOnly)
|
||||||
var body = cachedResponse.Body;
|
|
||||||
if (body.Length > 0)
|
|
||||||
{
|
{
|
||||||
await response.Body.WriteAsync(body, 0, body.Length);
|
response.Headers["Content-Length"] = "0";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Copy the cached response body
|
||||||
|
var body = cachedResponse.Body;
|
||||||
|
response.Headers["Content-Length"] = body.Length.ToString(CultureInfo.InvariantCulture);
|
||||||
|
if (body.Length > 0)
|
||||||
|
{
|
||||||
|
await response.Body.WriteAsync(body, 0, body.Length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +198,8 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
|
|
||||||
internal void FinalizeCaching()
|
internal void FinalizeCaching()
|
||||||
{
|
{
|
||||||
if (CacheResponse)
|
// Don't cache errors? 404 etc
|
||||||
|
if (CacheResponse && HttpContext.Response.StatusCode == 200)
|
||||||
{
|
{
|
||||||
var response = HttpContext.Response;
|
var response = HttpContext.Response;
|
||||||
var varyHeaderValue = response.Headers["Vary"];
|
var varyHeaderValue = response.Headers["Vary"];
|
||||||
|
|
@ -194,12 +220,30 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
// Store the response to cache
|
// Store the response to cache
|
||||||
var cachedResponse = new CachedResponse
|
var cachedResponse = new CachedResponse
|
||||||
{
|
{
|
||||||
|
Created = DateTimeOffset.UtcNow,
|
||||||
StatusCode = HttpContext.Response.StatusCode,
|
StatusCode = HttpContext.Response.StatusCode,
|
||||||
Body = Buffer.ToArray()
|
Body = Buffer.ToArray()
|
||||||
};
|
};
|
||||||
foreach (var pair in HttpContext.Response.Headers)
|
|
||||||
|
var headers = HttpContext.Response.Headers;
|
||||||
|
var count = headers.Count
|
||||||
|
- (headers.ContainsKey("Date") ? 1 : 0)
|
||||||
|
- (headers.ContainsKey("Content-Length") ? 1 : 0)
|
||||||
|
- (headers.ContainsKey("Age") ? 1 : 0);
|
||||||
|
var cachedHeaders = new List<KeyValuePair<string, StringValues>>(count);
|
||||||
|
var age = 0;
|
||||||
|
foreach (var entry in headers)
|
||||||
{
|
{
|
||||||
cachedResponse.Headers[pair.Key] = pair.Value;
|
// Reduce create date by Age
|
||||||
|
if (entry.Key == "Age" && int.TryParse(entry.Value, out age) && age > 0)
|
||||||
|
{
|
||||||
|
cacheEntry.Created -= new TimeSpan(0, 0, age);
|
||||||
|
}
|
||||||
|
// Don't copy Date header or Content-Length
|
||||||
|
else if (entry.Key != "Date" && entry.Key != "Content-Length")
|
||||||
|
{
|
||||||
|
cachedHeaders.Add(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache.Set(_cacheKey, cachedResponse); // TODO: Timeouts
|
Cache.Set(_cacheKey, cachedResponse); // TODO: Timeouts
|
||||||
|
|
@ -215,5 +259,12 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
// Unhook the response stream.
|
// Unhook the response stream.
|
||||||
HttpContext.Response.Body = OriginalResponseStream;
|
HttpContext.Response.Body = OriginalResponseStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum RequestType
|
||||||
|
{
|
||||||
|
NotCached = 0,
|
||||||
|
HeadersOnly,
|
||||||
|
FullReponse
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue