From 302b1f35407f2360b7be7190f7fc19d097429dc4 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Thu, 10 Apr 2014 14:35:08 -0700 Subject: [PATCH] Adding IgnoreNoCache setting to OutputCache This setting lets a website ignore "no-cache" requests from clients. This is usually done to force a refresh of a cached value, but this could also lead to unnecessary load as Orchard already invalidates its cache automatically (based on tags) or it could also be used by DDOS attacks. Also remove the "browser" ASP.NET setting as it could create too many entries in kernel cache. Work Item: 20614 --- .../Controllers/AdminController.cs | 4 +++- .../Filters/OutputCacheFilter.cs | 22 +++++++++---------- .../Models/CacheSettingsPart.cs | 5 +++++ .../ViewModels/IndexViewModel.cs | 1 + .../Views/Admin/Index.cshtml | 10 +++++++-- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs index 6f2149a57..5aa434284 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs @@ -89,7 +89,8 @@ namespace Orchard.OutputCache.Controllers { IgnoredUrls = settings.IgnoredUrls, DebugMode = settings.DebugMode, ApplyCulture = settings.ApplyCulture, - RouteConfigurations = routeConfigurations + RouteConfigurations = routeConfigurations, + IgnoreNoCache = settings.IgnoreNoCache }; return View(model); @@ -113,6 +114,7 @@ namespace Orchard.OutputCache.Controllers { settings.IgnoredUrls = model.IgnoredUrls; settings.DebugMode = model.DebugMode; settings.ApplyCulture = model.ApplyCulture; + settings.IgnoreNoCache = model.IgnoreNoCache; // invalidates the settings cache _signals.Trigger(CacheSettingsPart.CacheKey); diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index 5a2a2639c..fc8475815 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -70,6 +70,7 @@ namespace Orchard.OutputCache.Filters { private int _maxAge; private string _ignoredUrls; private bool _applyCulture; + private bool _ignoreNoCache; private string _cacheKey; private string _invariantCacheKey; private DateTime _now; @@ -141,6 +142,14 @@ namespace Orchard.OutputCache.Filters { } ); + // caches the default cache duration to prevent a query to the settings + _ignoreNoCache = _cacheManager.Get("CacheSettingsPart.IgnoreNoCache", + context => { + context.Monitor(_signals.When(CacheSettingsPart.CacheKey)); + return _workContext.CurrentSite.As().IgnoreNoCache; + } + ); + // caches the default max age duration to prevent a query to the settings _maxAge = _cacheManager.Get("CacheSettingsPart.MaxAge", context => { @@ -233,7 +242,7 @@ namespace Orchard.OutputCache.Filters { // don't retrieve cache content if refused // in this case the result of the action will update the current cached version - if (filterContext.RequestContext.HttpContext.Request.Headers["Cache-Control"] != "no-cache") { + if (filterContext.RequestContext.HttpContext.Request.Headers["Cache-Control"] != "no-cache" || _ignoreNoCache) { // fetch cached data _cacheItem = _cacheStorageProvider.GetCacheItem(_cacheKey); @@ -475,7 +484,7 @@ namespace Orchard.OutputCache.Filters { if (maxAge.TotalMilliseconds < 0) { maxAge = TimeSpan.FromSeconds(0); } - + response.Cache.SetCacheability(HttpCacheability.Public); response.Cache.SetMaxAge(maxAge); } @@ -499,15 +508,6 @@ namespace Orchard.OutputCache.Filters { 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 - // c.f. http://stackoverflow.com/questions/6007287/outputcache-varybyheader-user-agent-or-varybycustom-browser - response.Cache.SetVaryByCustom("browser"); - - // enabling this would create an entry for each different browser sub-version - // response.Cache.VaryByHeaders.UserAgent = true; - } private string ComputeCacheKey(ControllerContext controllerContext, IEnumerable> parameters) { diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs index 286880e56..862aad85a 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs @@ -38,5 +38,10 @@ namespace Orchard.OutputCache.Models { get { return this.Retrieve(x => x.DebugMode); } set { this.Store(x => x.DebugMode, value); } } + + public bool IgnoreNoCache { + get { return this.Retrieve(x => x.IgnoreNoCache); } + set { this.Store(x => x.IgnoreNoCache, value); } + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs index 39ffac4f6..6067b6cba 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs @@ -13,5 +13,6 @@ namespace Orchard.OutputCache.ViewModels { public bool DebugMode { get; set; } public string VaryQueryStringParameters { get; set; } public string VaryRequestHeaders { get; set; } + public bool IgnoreNoCache { 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 7ef0d1656..9c0baa578 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml @@ -23,8 +23,14 @@ @Html.TextBoxFor(m => m.DefaultMaxAge, new { @class = "text small" }) @T("When defined, a cache-control header with a max-age property will be added. Use this in order to enable kernel cache on IIS.") - - + + +
+ + @Html.TextAreaFor(m => m.IgnoredUrls, new { @class = "text medium" }) + @T("When checked, any request containing a 'Content-Cache: no-cache' header will still return cached values if available.") +
+
@Html.TextBoxFor(m => m.VaryQueryStringParameters, new { @class = "text medium" })