private void HandleResponseForClientCache(PortalContextInitInfo initInfo) { // binaryhandler if (initInfo.BinaryHandlerRequestedNodeHead != null) { var bhMaxAge = Settings.GetValue(PortalSettings.SETTINGSNAME, PortalSettings.SETTINGS_BINARYHANDLER_MAXAGE, initInfo.RepositoryPath, 0); if (bhMaxAge > 0) { HttpHeaderTools.SetCacheControlHeaders(bhMaxAge); // We're only handling these if the visitor has permissions to the node if (CheckVisitorPermissions(initInfo.RequestedNodeHead)) { // handle If-Modified-Since and Last-Modified headers HttpHeaderTools.EndResponseForClientCache(initInfo.BinaryHandlerRequestedNodeHead.ModificationDate); } else { //otherwise store the value for later use initInfo.ModificationDateForClient = initInfo.BinaryHandlerRequestedNodeHead.ModificationDate; } return; } } if (initInfo.IsWebdavRequest || initInfo.IsOfficeProtocolRequest) { //HttpHeaderTools.SetCacheControlHeaders(0, HttpCacheability.NoCache); //HttpContext.Current.Response.Headers.Add("Cache-Control", "no-store, no-cache, private"); HttpContext.Current.Response.Headers.Add("Pragma", "no-cache"); //HTTP 1.0 HttpContext.Current.Response.Headers.Add("Expires", "Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past return; } // get requested nodehead if (initInfo.RequestedNodeHead == null) { return; } // if action name is given, do not do shortcircuit (eg. myscript.js?action=Edit should be a server-rendered page) if (!string.IsNullOrEmpty(initInfo.ActionName)) { return; } // ********************************************************** // Image content check is moved to OnAuthorize event handler, because it needs the // fully loaded node. Here we handle only other content - e.g. js/css files. // ********************************************************** if (!initInfo.RequestedNodeHead.GetNodeType().IsInstaceOfOrDerivedFrom(typeof(Image).Name)) { var cacheSetting = GetCacheHeaderSetting(initInfo.RequestUri, initInfo.RequestedNodeHead); if (cacheSetting.HasValue) { HttpHeaderTools.SetCacheControlHeaders(cacheSetting.Value); // We're only handling these if the visitor has permissions to the node if (CheckVisitorPermissions(initInfo.RequestedNodeHead)) { // handle If-Modified-Since and Last-Modified headers HttpHeaderTools.EndResponseForClientCache(initInfo.RequestedNodeHead.ModificationDate); } else { //otherwise store the value for later use initInfo.ModificationDateForClient = initInfo.RequestedNodeHead.ModificationDate; } return; } } // applications Application app; // elevate to sysadmin, as we are startupuser here, and group 'everyone' should have permissions to application without elevation using (new SystemAccount()) { //load the application, or the node itself if it is an application if (initInfo.RequestedNodeHead.GetNodeType().IsInstaceOfOrDerivedFrom("Application")) { app = Node.LoadNode(initInfo.RequestedNodeHead) as Application; } else { app = ApplicationStorage.Instance.GetApplication(initInfo.ActionName, initInfo.RequestedNodeHead, initInfo.DeviceName); } } if (app == null) { return; } var maxAge = app.NumericMaxAge; var cacheControl = app.CacheControlEnumValue; if (cacheControl.HasValue && maxAge.HasValue) { HttpHeaderTools.SetCacheControlHeaders(maxAge.Value, cacheControl.Value); // We're only handling these if the visitor has permissions to the node if (CheckVisitorPermissions(initInfo.RequestedNodeHead)) { // handle If-Modified-Since and Last-Modified headers HttpHeaderTools.EndResponseForClientCache(initInfo.RequestedNodeHead.ModificationDate); } else { //otherwise store the value for later use initInfo.ModificationDateForClient = initInfo.RequestedNodeHead.ModificationDate; } } }
void OnAuthorize(object sender, EventArgs e) { //At this point the user has at least some permissions for the requested content. This means //we can respond with a 304 status if the content has not changed, without opening a security hole. //This value could be set earlier by the HandleResponseForClientCache method //(e.g. because of binaryhandler or application client cache values). if (PortalContext.Current.ModificationDateForClient.HasValue) { HttpHeaderTools.EndResponseForClientCache(PortalContext.Current.ModificationDateForClient.Value); } //check requested nodehead if (PortalContext.Current.ContextNodeHead == null) { return; } // Check if the requested content is executable (e.g. an aspx file) and has the correct file type. We must // call this here instead of OnEnter because the user must be authenticated for the check algorithm to work. CheckExecutableType(PortalContext.Current.ContextNodeHead, PortalContext.Current.ActionName); var modificationDate = PortalContext.Current.ContextNodeHead.ModificationDate; //If action name is given, do not do shortcircuit (eg. myimage.jpg?action=Edit //should be a server-rendered page) - except if this is an image resizer application. if (!string.IsNullOrEmpty(PortalContext.Current.ActionName)) { var remapAction = PortalContext.Current.CurrentAction as RemapHttpAction; if (remapAction == null || remapAction.HttpHandlerNode == null) { return; } if (!remapAction.HttpHandlerNode.GetNodeType().IsInstaceOfOrDerivedFrom(typeof(ImgResizeApplication).Name)) { return; } //check if the image resizer app was modified since the last request if (remapAction.HttpHandlerNode.ModificationDate > modificationDate) { modificationDate = remapAction.HttpHandlerNode.ModificationDate; } } //set cache values for images, js/css files var cacheSetting = GetCacheHeaderSetting(PortalContext.Current.RequestedUri, PortalContext.Current.ContextNodeHead); if (cacheSetting.HasValue) { HttpHeaderTools.SetCacheControlHeaders(cacheSetting.Value); //in case of preview images do NOT return 304, because _undetectable_ permission changes //(on the image or on one of its parents) may change the preview image (e.g. display redaction or not). if (DocumentPreviewProvider.Current == null || !DocumentPreviewProvider.Current.IsPreviewOrThumbnailImage(PortalContext.Current.ContextNodeHead)) { //end response, if the content has not changed since the value posted by the client HttpHeaderTools.EndResponseForClientCache(modificationDate); } } }