#20042: Cache invalidation by user defined request headers

Work Item: 20042
This commit is contained in:
bgrabkowitz
2013-08-23 15:49:58 -04:00
committed by Sebastien Ros
parent 4a6daa9ffa
commit a8ff9e218a
7 changed files with 62 additions and 9 deletions

View File

@@ -85,6 +85,7 @@ namespace Orchard.OutputCache.Controllers {
DefaultCacheDuration = settings.DefaultCacheDuration,
DefaultMaxAge = settings.DefaultMaxAge,
VaryQueryStringParameters = settings.VaryQueryStringParameters,
VaryRequestHeaders = settings.VaryRequestHeaders,
IgnoredUrls = settings.IgnoredUrls,
DebugMode = settings.DebugMode,
ApplyCulture = settings.ApplyCulture,
@@ -108,6 +109,7 @@ namespace Orchard.OutputCache.Controllers {
settings.DefaultCacheDuration = model.DefaultCacheDuration;
settings.DefaultMaxAge = model.DefaultMaxAge;
settings.VaryQueryStringParameters = model.VaryQueryStringParameters;
settings.VaryRequestHeaders = model.VaryRequestHeaders;
settings.IgnoredUrls = model.IgnoredUrls;
settings.DebugMode = model.DebugMode;
settings.ApplyCulture = model.ApplyCulture;

View File

@@ -73,6 +73,7 @@ namespace Orchard.OutputCache.Filters {
private string _actionName;
private DateTime _now;
private string[] _varyQueryStringParameters;
private ISet<string> _varyRequestHeaders;
private WorkContext _workContext;
@@ -157,6 +158,27 @@ namespace Orchard.OutputCache.Filters {
}
);
var varyRequestHeadersFromSettings = _cacheManager.Get("CacheSettingsPart.VaryRequestHeaders",
context => {
context.Monitor(_signals.When(CacheSettingsPart.CacheKey));
var varyRequestHeaders = _workContext.CurrentSite.As<CacheSettingsPart>().VaryRequestHeaders;
return string.IsNullOrWhiteSpace(varyRequestHeaders) ? null
: varyRequestHeaders.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray();
}
);
_varyRequestHeaders = (varyRequestHeadersFromSettings == null) ? new HashSet<string>() : new HashSet<string>(varyRequestHeadersFromSettings);
// different tenants with the same urls have different entries
_varyRequestHeaders.Add("HOST");
// Set the Vary: Accept-Encoding response header.
// This instructs the proxies to cache two versions of the resource: one compressed, and one uncompressed.
// The correct version of the resource is delivered based on the client request header.
// This is a good choice for applications that are singly homed and depend on public proxies for user locality.
_varyRequestHeaders.Add("Accept-Encoding");
// caches the ignored urls to prevent a query to the settings
_ignoredUrls = _cacheManager.Get("CacheSettingsPart.IgnoredUrls",
context => {
@@ -187,6 +209,7 @@ namespace Orchard.OutputCache.Filters {
}
var queryString = filterContext.RequestContext.HttpContext.Request.QueryString;
var requestHeaders = filterContext.RequestContext.HttpContext.Request.Headers;
var parameters = new Dictionary<string, object>(filterContext.ActionParameters);
foreach (var key in queryString.AllKeys) {
@@ -195,6 +218,12 @@ namespace Orchard.OutputCache.Filters {
parameters[key] = queryString[key];
}
foreach (var varyByRequestHeader in _varyRequestHeaders) {
if (requestHeaders.AllKeys.Contains(varyByRequestHeader)) {
parameters["HEADER:" + varyByRequestHeader] = requestHeaders[varyByRequestHeader];
}
}
// compute the cache key
_cacheKey = ComputeCacheKey(filterContext, parameters);
@@ -434,14 +463,9 @@ namespace Orchard.OutputCache.Filters {
}
}
// different tenants with the same urls have different entries
response.Cache.VaryByHeaders["HOST"] = true;
// Set the Vary: Accept-Encoding response header.
// This instructs the proxies to cache two versions of the resource: one compressed, and one uncompressed.
// The correct version of the resource is delivered based on the client request header.
// This is a good choice for applications that are singly homed and depend on public proxies for user locality.
response.Cache.VaryByHeaders["Accept-Encoding"] = true;
foreach (var varyRequestHeader in _varyRequestHeaders) {
response.Cache.VaryByHeaders[varyRequestHeader] = true;
}
// create a unique cache per browser, in case a Theme is rendered differently (e.g., mobile)
// c.f. http://msdn.microsoft.com/en-us/library/aa478965.aspx

View File

@@ -10,6 +10,8 @@ namespace Orchard.OutputCache {
.Column<int>("DefaultCacheDuration")
.Column<int>("DefaultMaxAge")
.Column<string>("IgnoredUrls", c => c.Unlimited())
.Column<string>("VaryQueryStringParameters", c => c.Unlimited())
.Column<string>("VaryRequestHeaders", c => c.Unlimited())
.Column<bool>("DebugMode", c => c.WithDefault(false))
.Column<bool>("ApplyCulture", c => c.WithDefault(false))
);
@@ -22,7 +24,7 @@ namespace Orchard.OutputCache {
.Column<string>("RouteKey", c => c.WithLength(255))
);
return 4;
return 6;
}
public int UpdateFrom1() {
@@ -80,5 +82,15 @@ namespace Orchard.OutputCache {
return 5;
}
public int UpdateFrom5() {
SchemaBuilder.AlterTable("CacheSettingsPartRecord",
table => table
.AddColumn<string>("VaryRequestHeaders", c => c.Unlimited())
);
return 6;
}
}
}

View File

@@ -19,6 +19,11 @@ namespace Orchard.OutputCache.Models {
set { Record.VaryQueryStringParameters = value; }
}
public string VaryRequestHeaders {
get { return Record.VaryRequestHeaders; }
set { Record.VaryRequestHeaders = value; }
}
public string IgnoredUrls {
get { return Record.IgnoredUrls; }
set { Record.IgnoredUrls = value; }

View File

@@ -11,6 +11,9 @@ namespace Orchard.OutputCache.Models {
[StringLengthMax]
public virtual string VaryQueryStringParameters { get; set; }
[StringLengthMax]
public virtual string VaryRequestHeaders { get; set; }
[StringLengthMax]
public virtual string IgnoredUrls { get; set; }
}

View File

@@ -12,5 +12,6 @@ namespace Orchard.OutputCache.ViewModels {
public bool ApplyCulture { get; set; }
public bool DebugMode { get; set; }
public string VaryQueryStringParameters { get; set; }
public string VaryRequestHeaders { get; set; }
}
}

View File

@@ -31,6 +31,12 @@
<span class="hint">@T("When defined, using comma separated values, sets caching to vary via specified query string parameters")</span>
</fieldset>
<fieldset>
<label>@T("Vary Request Headers")</label>
@Html.TextBoxFor(m => m.VaryRequestHeaders, new { @class = "textMedium" })
<span class="hint">@T("When defined, using comma separated values, sets caching to vary via specified request headers.")</span>
</fieldset>
<fieldset>
<label>@T("Ignored urls")</label>
@Html.TextAreaFor(m => m.IgnoredUrls, new { @class = "textMedium" })