diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs index 42656f8f0..6f2149a57 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs @@ -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; diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index d80bbd51a..e10ca2d32 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -73,6 +73,7 @@ namespace Orchard.OutputCache.Filters { private string _actionName; private DateTime _now; private string[] _varyQueryStringParameters; + private ISet _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().VaryRequestHeaders; + + return string.IsNullOrWhiteSpace(varyRequestHeaders) ? null + : varyRequestHeaders.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray(); + } + ); + + _varyRequestHeaders = (varyRequestHeadersFromSettings == null) ? new HashSet() : new HashSet(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(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 diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Migrations.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Migrations.cs index abe6fb459..cc9d30a8e 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Migrations.cs @@ -10,6 +10,8 @@ namespace Orchard.OutputCache { .Column("DefaultCacheDuration") .Column("DefaultMaxAge") .Column("IgnoredUrls", c => c.Unlimited()) + .Column("VaryQueryStringParameters", c => c.Unlimited()) + .Column("VaryRequestHeaders", c => c.Unlimited()) .Column("DebugMode", c => c.WithDefault(false)) .Column("ApplyCulture", c => c.WithDefault(false)) ); @@ -22,7 +24,7 @@ namespace Orchard.OutputCache { .Column("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("VaryRequestHeaders", c => c.Unlimited()) + ); + + return 6; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs index 47b25ebe9..d10f3639d 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs @@ -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; } diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPartRecord.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPartRecord.cs index cb93dccbf..efac6d778 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPartRecord.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPartRecord.cs @@ -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; } } diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs index dc8e9f123..39ffac4f6 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs @@ -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; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml index cf37d9fe0..58170ae62 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml @@ -31,6 +31,12 @@ @T("When defined, using comma separated values, sets caching to vary via specified query string parameters") +
+ + @Html.TextBoxFor(m => m.VaryRequestHeaders, new { @class = "textMedium" }) + @T("When defined, using comma separated values, sets caching to vary via specified request headers.") +
+
@Html.TextAreaFor(m => m.IgnoredUrls, new { @class = "textMedium" })