/// <summary> /// Save all items that we know are used for rendering execution to variables so we can restore after rendering /// </summary> private void SaveExistingItems(out PublishedRequest oldPublishedRequest, out object oldAltTemplate) { //Many objects require that these legacy items are in the http context items... before we render this template we need to first //save the values in them so that we can re-set them after we render so the rest of the execution works as per normal oldPublishedRequest = _umbracoContextAccessor.UmbracoContext.PublishedRequest; oldAltTemplate = _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate]; }
private void ExecuteTemplateRendering(TextWriter sw, PublishedRequest request) { //NOTE: Before we used to build up the query strings here but this is not necessary because when we do a // Server.Execute in the TemplateRenderer, we pass in a 'true' to 'preserveForm' which automatically preserves all current // query strings so there's no need for this. HOWEVER, once we get MVC involved, we might have to do some fun things, // though this will happen in the TemplateRenderer. //var queryString = _umbracoContext.HttpContext.Request.QueryString.AllKeys // .ToDictionary(key => key, key => context.Request.QueryString[key]); var requestContext = new RequestContext(_umbracoContextAccessor.UmbracoContext.HttpContext, new RouteData() { Route = RouteTable.Routes["Umbraco_default"] }); var routeHandler = new RenderRouteHandler(_umbracoContextAccessor, ControllerBuilder.Current.GetControllerFactory()); var routeDef = routeHandler.GetUmbracoRouteDefinition(requestContext, request); var renderModel = new ContentModel(request.PublishedContent); //manually add the action/controller, this is required by mvc requestContext.RouteData.Values.Add("action", routeDef.ActionName); requestContext.RouteData.Values.Add("controller", routeDef.ControllerName); //add the rest of the required route data routeHandler.SetupRouteDataForRequest(renderModel, requestContext, request); var stringOutput = RenderUmbracoRequestToString(requestContext); sw.Write(stringOutput); }
public override bool TryFindContent(PublishedRequest contentRequest) { string route; if (contentRequest.HasDomain) { route = contentRequest.Domain.ContentId.ToString() + DomainHelper.PathRelativeToDomain(contentRequest.Domain.Uri, contentRequest.Uri.GetAbsolutePathDecoded()); } else { route = contentRequest.Uri.GetAbsolutePathDecoded(); } // This simple logic should do the trick: basically if I find an url with more than 4 segments (the 3 date parts and the slug) // I leave the last segment (the slug), remove the 3 date parts, and keep all the rest. var segmentLength = contentRequest.Uri.Segments.Length; if (segmentLength > 4) { var stringDate = contentRequest.Uri.Segments[segmentLength - 4] + contentRequest.Uri.Segments[segmentLength - 3] + contentRequest.Uri.Segments[segmentLength - 2].TrimEnd("/"); DateTime postDate; try { postDate = DateTime.ParseExact(stringDate, "yyyy/MM/dd", CultureInfo.InvariantCulture); } catch (FormatException) { return(false); } var newRoute = string.Empty; for (int i = 0; i < segmentLength; i++) { if (i < segmentLength - 4 || i > segmentLength - 2) { newRoute += contentRequest.Uri.Segments[i]; } } var node = FindContent(contentRequest, newRoute); contentRequest.PublishedContent = null; // If by chance something matches the format pattern I check again if there is sucn a node and if it's an articulate post if (node == null || (node.ContentType.Alias != "ArticulateRichText" && node.ContentType.Alias != "ArticulateMarkdown")) { return(false); } if (!node.Parent.Parent.Value <bool>("useDateFormatForUrl")) { return(false); } if (node.Value <DateTime>("publishedDate").Date != postDate.Date) { return(false); } contentRequest.PublishedContent = node; return(true); } return(false); }
/// <summary> /// This assigns the published content to the request, developers can override this to specify /// any other custom attributes required. /// </summary> /// <param name="request"></param> /// <param name="filterContext"></param> protected virtual void ConfigurePublishedContentRequest(PublishedRequest request, ActionExecutedContext filterContext) { if (_contentId.HasValue) { var content = Umbraco.Content(_contentId.Value); if (content == null) { throw new InvalidOperationException("Could not resolve content with id " + _contentId); } request.PublishedContent = content; } else if (_dataTokenName.IsNullOrWhiteSpace() == false) { var result = filterContext.RouteData.DataTokens[_dataTokenName]; if (result == null) { throw new InvalidOperationException("No data token could be found with the name " + _dataTokenName); } if (result is IPublishedContent == false) { throw new InvalidOperationException("The data token resolved with name " + _dataTokenName + " was not an instance of " + typeof(IPublishedContent)); } request.PublishedContent = (IPublishedContent)result; } PublishedRouter.PrepareRequest(request); }
public bool TryFindContent(PublishedRequest request) { if (request == null) { return(false); } var path = request.Uri.GetAbsolutePathDecoded().Replace($"/{ApplicationConstants.ApiRoutePrefix}/", "/").Replace($"/{ApplicationConstants.ApiRoutePrefix}", "/"); var parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); var publishedContent = request.UmbracoContext.Content.GetByRoute(path); if (publishedContent.HasValue()) { request.PublishedContent = publishedContent; } else if (parts.Length == 2) { var nodeIdValue = parts.LastOrDefault(); int nodeId = int.TryParse(nodeIdValue, out nodeId) ? nodeId : 0; request.PublishedContent = request.UmbracoContext.Content.GetById(nodeId); } return(request.PublishedContent != null); }
internal IHttpHandler GetHandlerOnMissingTemplate(PublishedRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } // missing template, so we're in a 404 here // so the content, if any, is a custom 404 page of some sort if (request.HasPublishedContent == false) { // means the builder could not find a proper document to handle 404 return(new PublishedContentNotFoundHandler()); } if (request.HasTemplate == false) { // means the engine could find a proper document, but the document has no template // at that point there isn't much we can do and there is no point returning // to Mvc since Mvc can't do much return(new PublishedContentNotFoundHandler("In addition, no template exists to render the custom 404.")); } return(null); }
protected override void PreparePublishedContentRequest(PublishedRequest request) { var def = new RouteDefinition { ActionName = request.UmbracoContext.HttpContext.Request.RequestContext.RouteData.GetRequiredString("action"), ControllerName = request.UmbracoContext.HttpContext.Request.RequestContext.RouteData.GetRequiredString("controller"), PublishedRequest = request }; // Set the special data token to the current route definition request.UmbracoContext.HttpContext.Request.RequestContext.RouteData.DataTokens[Umbraco.Core.Constants.Web.UmbracoRouteDefinitionDataToken] = def; request.UmbracoContext.HttpContext.Request.RequestContext.RouteData.Values["action"] = request.PublishedContent.GetTemplateAlias(); // We set it here again, because it gets overwritten in the pipeline. Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(Umbraco.Web.Composing.Current.VariationContextAccessor.VariationContext.Culture); // Since Umbraco 8.10 they show a "Exit Preview mode" message if you visit the site in preview mode. We don't want this in this package. // They check if the message should be shown by using a cookie. If this cookie doesn't exists, we set the cookie with the same expiration. if (request.UmbracoContext.HttpContext != null && request.UmbracoContext.HttpContext.Request.Cookies.Get(AcceptPreviewMode) == null) { request.UmbracoContext.HttpContext.Response.Cookies.Set(new HttpCookie(AcceptPreviewMode, "true") { Expires = DateTime.Now.AddMinutes(5) }); } }
/// <summary> /// Rewrites to the Umbraco handler - we always send the request via our MVC rendering engine, this will deal with /// requests destined for webforms. /// </summary> /// <param name="context"></param> /// <param name="pcr"> </param> private void RewriteToUmbracoHandler(HttpContextBase context, PublishedRequest pcr) { // NOTE: we do not want to use TransferRequest even though many docs say it is better with IIS7, turns out this is // not what we need. The purpose of TransferRequest is to ensure that .net processes all of the rules for the newly // rewritten URL, but this is not what we want! // read: http://forums.iis.net/t/1146511.aspx var query = pcr.Uri.Query.TrimStart('?'); // GlobalSettings.Path has already been through IOHelper.ResolveUrl() so it begins with / and vdir (if any) var rewritePath = _globalSettings.Path.TrimEnd('/') + "/RenderMvc"; // rewrite the path to the path of the handler (i.e. /umbraco/RenderMvc) context.RewritePath(rewritePath, "", query, false); //if it is MVC we need to do something special, we are not using TransferRequest as this will //require us to rewrite the path with query strings and then re-parse the query strings, this would //also mean that we need to handle IIS 7 vs pre-IIS 7 differently. Instead we are just going to create //an instance of the UrlRoutingModule and call it's PostResolveRequestCache method. This does: // * Looks up the route based on the new rewritten URL // * Creates the RequestContext with all route parameters and then executes the correct handler that matches the route //we also cannot re-create this functionality because the setter for the HttpContext.Request.RequestContext is internal //so really, this is pretty much the only way without using Server.TransferRequest and if we did that, we'd have to rethink //a bunch of things! var urlRouting = new UrlRoutingModule(); urlRouting.PostResolveRequestCache(context); }
public bool TryFindContent(PublishedRequest contentRequest) { //find the root node with a matching domain to the incoming request var url = contentRequest.Uri.ToString(); var allDomains = _domainService.GetAll(true); var domain = allDomains?.Where(f => f.DomainName == contentRequest.Uri.Authority || f.DomainName == "https://" + contentRequest.Uri.Authority).FirstOrDefault(); var siteId = domain != null ? domain.RootContentId : (allDomains.Any() ? allDomains.FirstOrDefault().RootContentId : null); var siteRoot = contentRequest.UmbracoContext.Content.GetById(false, siteId ?? -1); if (siteRoot == null) { siteRoot = contentRequest.UmbracoContext.Content.GetAtRoot().FirstOrDefault(); } if (siteRoot == null) { return(false); } //assuming the 404 page is in the root of the language site with alias fourOhFourPageAlias IPublishedContent notFoundNode = siteRoot.Children.FirstOrDefault(f => f.ContentType.Alias == "page404"); if (notFoundNode != null) { contentRequest.PublishedContent = notFoundNode; } // return true or false depending on whether our custom 404 page was found return(contentRequest.PublishedContent != null); }
public bool TryFindContent(PublishedRequest contentRequest) { if (!contentRequest.Is404) { return(contentRequest.PublishedContent != null); } return(contentRequest.PublishedContent != null); }
private void SetNewItemsOnContextObjects(PublishedRequest request) { // handlers like default.aspx will want it and most macros currently need it request.UmbracoPage = new page(request); //now, set the new ones for this page execution _umbracoContext.HttpContext.Items["pageElements"] = request.UmbracoPage.Elements; _umbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null; _umbracoContext.PublishedRequest = request; }
protected override void OnPreInit(EventArgs e) { base.OnPreInit(e); using (Current.ProfilingLogger.DebugDuration <UmbracoDefault>("PreInit")) { // handle the infamous umbDebugShowTrace, etc Page.Trace.IsEnabled &= GlobalSettings.DebugMode && string.IsNullOrWhiteSpace(Request["umbDebugShowTrace"]) == false; // get the document request and the page _frequest = UmbracoContext.Current.PublishedRequest; _upage = _frequest.UmbracoPage; var args = new RequestInitEventArgs() { Page = _upage, PageId = _upage.PageID, Context = Context }; FireBeforeRequestInit(args); //if we are cancelling then return and don't proceed if (args.Cancel) { return; } var template = Current.Services.FileService.GetTemplate(_upage.Template); if (template != null) { var alias = template.MasterTemplateAlias; var file = alias.Replace(" ", "") + ".master"; var path = SystemDirectories.Masterpages + "/" + file; if (File.Exists(IOHelper.MapPath(VirtualPathUtility.ToAbsolute(path)))) { this.MasterPageFile = path; } else { this.MasterPageFile = SystemDirectories.Umbraco + "/masterPages/default.master"; } } // reset the friendly path so it's used by forms, etc. Context.RewritePath(UmbracoContext.Current.OriginalRequestUrl.PathAndQuery); //fire the init finished event FireAfterRequestInit(args); } }
public bool TryFindContent(PublishedRequest request) { //Check the table var matchedRedirect = _repository.FindRedirect(request.Uri); if (matchedRedirect == null) { return(false); } request.SetRedirect(matchedRedirect.GetNewUrl(request.Uri), matchedRedirect.RedirectCode); return(true); }
/// <inheritdoc /> public bool TryFindContent(PublishedRequest request) { var path = request.Uri.AbsolutePath; if ("/robots.txt".Equals(path, StringComparison.OrdinalIgnoreCase)) { request.PublishedContent = request.UmbracoContext.Content.GetSingleByXPath("//robotsTxt"); } else if (Regex.IsMatch(path, @"^/sitemap-\w{2}\.xml$", RegexOptions.IgnoreCase)) { request.PublishedContent = request.UmbracoContext.Content.GetSingleByXPath("//sitemapXml"); } return(request.PublishedContent != null); }
public bool TryFindContent(PublishedRequest request) { var path = request.UmbracoContext.HttpContext.Request.Url.AbsolutePath; // TODO: actually handle this in a nice way! if (path.Contains("/ip-not-allowed")) { request.UmbracoContext.HttpContext.Response.StatusCode = 403; request.UmbracoContext.HttpContext.Response.Write("Access Denied"); return(true); } return(false); }
public bool TryFindContent(PublishedRequest contentRequest) { var uriAuthority = contentRequest.Uri.Authority; var domain = _domainService.GetByName(uriAuthority); var notFoundNode = _cmsService.GetError404(domain.RootContentId.Value); if (notFoundNode != null) { contentRequest.PublishedContent = notFoundNode; } // return true or false depending on whether our custom 404 page was found return(contentRequest.PublishedContent != null); }
private Domain GetUmbracoDomain(HttpRequest request) { // Get the Umbraco request (it may be NULL) PublishedRequest pcr = _umbracoContextAccessor.UmbracoContext?.PublishedRequest; // Return the domain of the Umbraco request if (pcr != null) { return(pcr.Domain); } // Find domain via DomainService based on current request domain var domain = DomainUtils.FindDomainForUri(_domains, request.Url); return(domain); }
public bool TryFindContent(PublishedRequest frequest) { int pageId; if (int.TryParse(frequest.UmbracoContext.HttpContext.Request["umbPageID"], out pageId)) { var doc = frequest.UmbracoContext.ContentCache.GetById(pageId); if (doc != null) { frequest.PublishedContent = doc; return(true); } } return(false); }
protected override void PreparePublishedContentRequest(PublishedRequest request) { var def = new RouteDefinition { ActionName = request.UmbracoContext.HttpContext.Request.RequestContext.RouteData.GetRequiredString("action"), ControllerName = request.UmbracoContext.HttpContext.Request.RequestContext.RouteData.GetRequiredString("controller"), PublishedRequest = request }; // set the special data token to the current route definition request.UmbracoContext.HttpContext.Request.RequestContext.RouteData.DataTokens[Umbraco.Core.Constants.Web.UmbracoRouteDefinitionDataToken] = def; request.UmbracoContext.HttpContext.Request.RequestContext.RouteData.Values["action"] = request.PublishedContent.GetTemplateAlias(); // We set it here again, because it gets overwritten in the pipeline. Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(Umbraco.Web.Composing.Current.VariationContextAccessor.VariationContext.Culture); }
public bool TryFindContent(PublishedRequest request) { //Get the requested URL path + query var path = request.Uri.PathAndQuery.ToLower(); //Check the table var matchedRedirect = _redirectRepository.FindRedirect(path); if (matchedRedirect == null) { return(false); } //Found one, set the 301 redirect on the request and return request.SetRedirectPermanent(matchedRedirect.NewUrl); return(true); }
public bool TryFindContent(PublishedRequest contentRequest) { // handle all requests beginning /website... var path = contentRequest.Uri.AbsolutePath; HttpContextBase wrapper = new HttpContextWrapper(HttpContext.Current); UmbracoBackOfficeIdentity user = wrapper.GetCurrentIdentity(true); bool isLoggedIn = user != null; if (!isLoggedIn) { if (path.StartsWith("/" + StandingData.UmbracoRootFolderUrl)) { contentRequest.Is404 = true; HttpContext.Current.Response.Redirect(path.Replace("/" + StandingData.UmbracoRootFolderUrl, "")); } } return(true); }
/// <summary> /// Initializes a new instance of the <see cref="PublishedContentHashtableConverter"/> class for a published document request. /// </summary> /// <param name="frequest">The <see cref="PublishedRequest"/> pointing to the document.</param> /// <remarks> /// The difference between creating the page with PublishedContentRequest vs an IPublishedContent item is /// that the PublishedContentRequest takes into account how a template is assigned during the routing process whereas /// with an IPublishedContent item, the template id is assigned purely based on the default. /// </remarks> internal PublishedContentHashtableConverter(PublishedRequest frequest) { if (!frequest.HasPublishedContent) { throw new ArgumentException("Document request has no node.", nameof(frequest)); } PopulatePageData(frequest.PublishedContent.Id, frequest.PublishedContent.Name, frequest.PublishedContent.ContentType.Id, frequest.PublishedContent.ContentType.Alias, frequest.PublishedContent.WriterName, frequest.PublishedContent.CreatorName, frequest.PublishedContent.CreateDate, frequest.PublishedContent.UpdateDate, frequest.PublishedContent.Path, frequest.PublishedContent.Parent?.Id ?? -1); if (frequest.HasTemplate) { Elements["template"] = frequest.TemplateModel.Id.ToString(); } PopulateElementData(frequest.PublishedContent); }
/// <summary> /// Initializes a new instance of the <see cref="page"/> class for a published document request. /// </summary> /// <param name="frequest">The <see cref="PublishedRequest"/> pointing to the document.</param> /// <remarks> /// The difference between creating the page with PublishedContentRequest vs an IPublishedContent item is /// that the PublishedContentRequest takes into account how a template is assigned during the routing process whereas /// with an IPublishedContent item, the template id is asssigned purely based on the default. /// </remarks> internal page(PublishedRequest frequest) { if (!frequest.HasPublishedContent) { throw new ArgumentException("Document request has no node.", "frequest"); } populatePageData(frequest.PublishedContent.Id, frequest.PublishedContent.Name, frequest.PublishedContent.ContentType.Id, frequest.PublishedContent.ContentType.Alias, frequest.PublishedContent.WriterName, frequest.PublishedContent.CreatorName, frequest.PublishedContent.CreateDate, frequest.PublishedContent.UpdateDate, frequest.PublishedContent.Path, frequest.PublishedContent.Parent == null ? -1 : frequest.PublishedContent.Parent.Id); if (frequest.HasTemplate) { this._template = frequest.TemplateModel.Id; _elements["template"] = _template.ToString(); } PopulateElementData(frequest.PublishedContent); }
private void ExecuteTemplateRendering(TextWriter sw, PublishedRequest request) { //NOTE: Before we used to build up the query strings here but this is not necessary because when we do a // Server.Execute in the TemplateRenderer, we pass in a 'true' to 'preserveForm' which automatically preserves all current // query strings so there's no need for this. HOWEVER, once we get MVC involved, we might have to do some fun things, // though this will happen in the TemplateRenderer. //var queryString = _umbracoContext.HttpContext.Request.QueryString.AllKeys // .ToDictionary(key => key, key => context.Request.QueryString[key]); switch (request.RenderingEngine) { case RenderingEngine.Mvc: var requestContext = new RequestContext(_umbracoContext.HttpContext, new RouteData() { Route = RouteTable.Routes["Umbraco_default"] }); var routeHandler = new RenderRouteHandler(_umbracoContext, ControllerBuilder.Current.GetControllerFactory()); var routeDef = routeHandler.GetUmbracoRouteDefinition(requestContext, request); var renderModel = new ContentModel(request.PublishedContent); //manually add the action/controller, this is required by mvc requestContext.RouteData.Values.Add("action", routeDef.ActionName); requestContext.RouteData.Values.Add("controller", routeDef.ControllerName); //add the rest of the required route data routeHandler.SetupRouteDataForRequest(renderModel, requestContext, request); var stringOutput = RenderUmbracoRequestToString(requestContext); sw.Write(stringOutput); break; case RenderingEngine.WebForms: default: var webFormshandler = (UmbracoDefault)BuildManager .CreateInstanceFromVirtualPath("~/default.aspx", typeof(UmbracoDefault)); //the 'true' parameter will ensure that the current query strings are carried through, we don't have // to build up the url again, it will just work. _umbracoContext.HttpContext.Server.Execute(webFormshandler, sw, true); break; } }
public bool TryFindContent(PublishedRequest contentRequest) { var _runtimeCache = Current.AppCaches.RuntimeCache; var _umbracoContext = contentRequest.UmbracoContext; var cachedVirtualNodeUrls = _runtimeCache.GetCacheItem <Dictionary <string, int> >("CachedVirtualNodes"); var path = contentRequest.Uri.AbsolutePath; // If found in the cached dictionary if ((cachedVirtualNodeUrls != null) && cachedVirtualNodeUrls.ContainsKey(path)) { var nodeId = cachedVirtualNodeUrls[path]; contentRequest.PublishedContent = _umbracoContext.Content.GetById(nodeId); return(true); } // If not found in the cached dictionary, traverse nodes and find the node that corresponds to the URL var rootNodes = _umbracoContext.Content.GetAtRoot(); var item = rootNodes.DescendantsOrSelf <IPublishedContent>().Where(x => (x.Url == (path + "/") || (x.Url == path))).FirstOrDefault(); // If item is found, return it after adding it to the cache so we don't have to go through the same process again. if (cachedVirtualNodeUrls == null) { cachedVirtualNodeUrls = new Dictionary <string, int>(); } // If we have found a node that corresponds to the URL given if (item != null) { // Update cache _runtimeCache.InsertCacheItem("CachedVirtualNodes", () => cachedVirtualNodeUrls, null, false, CacheItemPriority.High); // That's all folks contentRequest.PublishedContent = item; return(true); } return(false); }
public bool TryFindContent(PublishedRequest request) { var status = _allowedIpService.GetStatus(); if (!status.Enabled) { return(false); } var ip = request.UmbracoContext.HttpContext.Request.UserHostAddress; var item = _allowedIpService.GetByIpAddress(ip); if (item == null) { request.SetRedirect("/ip-not-allowed"); return(true); } return(false); }
public bool TryFindContent(PublishedRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } var matchedRouteType = MatchStoolballRouteType(request.Uri); if (matchedRouteType.HasValue) { // Direct the response to the 'Stoolball router' document type to be handled by StoolballRouterController var router = request.UmbracoContext.Content.GetSingleByXPath("//stoolballRouter"); if (router != null) { request.PublishedContent = router; request.TrySetTemplate(matchedRouteType.Value.ToString()); return(request.HasTemplate && router.IsAllowedTemplate(request.TemplateAlias)); } } return(false); }
/// <summary> /// Restores all items back to their context's to continue normal page rendering execution /// </summary> private void RestoreItems(PublishedRequest oldPublishedRequest, object oldAltTemplate) { _umbracoContextAccessor.UmbracoContext.PublishedRequest = oldPublishedRequest; _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = oldAltTemplate; }
private void SetNewItemsOnContextObjects(PublishedRequest request) { //now, set the new ones for this page execution _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null; _umbracoContextAccessor.UmbracoContext.PublishedRequest = request; }
// returns a value indicating whether redirection took place and the request has // been completed - because we don't want to Response.End() here to terminate // everything properly. internal static bool HandleHttpResponseStatus(HttpContextBase context, PublishedRequest pcr, ILogger logger) { var end = false; var response = context.Response; logger.Debug <UmbracoModule>("Response status: Redirect={Redirect}, Is404={Is404}, StatusCode={ResponseStatusCode}", pcr.IsRedirect ? (pcr.IsRedirectPermanent ? "permanent" : "redirect") : "none", pcr.Is404 ? "true" : "false", pcr.ResponseStatusCode); if (pcr.Cacheability != default) { response.Cache.SetCacheability(pcr.Cacheability); } foreach (var cacheExtension in pcr.CacheExtensions) { response.Cache.AppendCacheExtension(cacheExtension); } foreach (var header in pcr.Headers) { response.AppendHeader(header.Key, header.Value); } if (pcr.IsRedirect) { if (pcr.IsRedirectPermanent) { response.RedirectPermanent(pcr.RedirectUrl, false); // do not end response } else { response.Redirect(pcr.RedirectUrl, false); // do not end response } end = true; } else if (pcr.Is404) { response.StatusCode = 404; response.TrySkipIisCustomErrors = Current.Configs.Settings().WebRouting.TrySkipIisCustomErrors; if (response.TrySkipIisCustomErrors == false) { logger.Warn <UmbracoModule>("Status code is 404 yet TrySkipIisCustomErrors is false - IIS will take over."); } } if (pcr.ResponseStatusCode > 0) { // set status code -- even for redirects response.StatusCode = pcr.ResponseStatusCode; response.StatusDescription = pcr.ResponseStatusDescription; } //if (pcr.IsRedirect) // response.End(); // end response -- kills the thread and does not return! if (pcr.IsRedirect == false) { return(end); } response.Flush(); // bypass everything and directly execute EndRequest event -- but returns context.ApplicationInstance.CompleteRequest(); // though some say that .CompleteRequest() does not properly shutdown the response // and the request will hang until the whole code has run... would need to test? logger.Debug <UmbracoModule>("Response status: redirecting, complete request now."); return(end); }