// 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, PublishedContentRequest pcr) { var end = false; var response = context.Response; LogHelper.Debug <UmbracoModule>("Response status: Redirect={0}, Is404={1}, StatusCode={2}", () => pcr.IsRedirect ? (pcr.IsRedirectPermanent ? "permanent" : "redirect") : "none", () => pcr.Is404 ? "true" : "false", () => pcr.ResponseStatusCode); 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 = UmbracoSettings.For <WebRouting>().TrySkipIisCustomErrors; } 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) { 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? LogHelper.Debug <UmbracoModule>("Response status: redirecting, complete request now."); } return(end); }
/// <summary> /// Sets the requested content, following an internal redirect. /// </summary> /// <param name="content">The requested content.</param> /// <remarks>Depending on <c>UmbracoSettings.InternalRedirectPreservesTemplate</c>, will /// preserve or reset the template, if any.</remarks> public void SetInternalRedirectPublishedContent(IPublishedContent content) { EnsureWriteable(); // unless a template has been set already by the finder, // template should be null at that point. var initial = IsInitialPublishedContent; var template = _template; PublishedContent = content; IsInternalRedirectPublishedContent = (initial && !IsInitialPublishedContent); if (IsInternalRedirectPublishedContent && UmbracoSettings.For <WebRouting>().InternalRedirectPreservesTemplate) { _template = template; } }
/// <summary> /// Sets the requested content, following an internal redirect. /// </summary> /// <param name="content">The requested content.</param> /// <remarks>Depending on <c>UmbracoSettings.InternalRedirectPreservesTemplate</c>, will /// preserve or reset the template, if any.</remarks> public void SetInternalRedirectPublishedContent(IPublishedContent content) { EnsureWriteable(); // unless a template has been set already by the finder, // template should be null at that point. // IsInternalRedirect if IsInitial, or already IsInternalRedirect var isInternalRedirect = IsInitialPublishedContent || IsInternalRedirectPublishedContent; // redirecting to self if (content.Id == PublishedContent.Id) // neither can be null { // no need to set PublishedContent, we're done IsInternalRedirectPublishedContent = isInternalRedirect; return; } // else // save var template = _template; var renderingEngine = RenderingEngine; // set published content - this resets the template, and sets IsInternalRedirect to false PublishedContent = content; IsInternalRedirectPublishedContent = isInternalRedirect; // must restore the template if it's an internal redirect & the config option is set if (isInternalRedirect && UmbracoSettings.For <WebRouting>().InternalRedirectPreservesTemplate) { // restore _template = template; RenderingEngine = renderingEngine; } }
/// <summary> /// Finds a template for the current node, if any. /// </summary> private void FindTemplate() { // NOTE: at the moment there is only 1 way to find a template, and then ppl must // use the Prepared event to change the template if they wish. Should we also // implement an ITemplateFinder logic? const string tracePrefix = "FindTemplate: "; if (_pcr.PublishedContent == null) { _pcr.TemplateModel = null; return; } // read the alternate template alias, from querystring, form, cookie or server vars, // only if the published content is the initial once, else the alternate template // does not apply // + optionnally, apply the alternate template on internal redirects var useAltTemplate = _pcr.IsInitialPublishedContent || (UmbracoSettings.For <WebRouting>().InternalRedirectPreservesTemplate&& _pcr.IsInternalRedirectPublishedContent); string altTemplate = useAltTemplate ? _routingContext.UmbracoContext.HttpContext.Request[Constants.Conventions.Url.AltTemplate] : null; if (string.IsNullOrWhiteSpace(altTemplate)) { // we don't have an alternate template specified. use the current one if there's one already, // which can happen if a content lookup also set the template (LookupByNiceUrlAndTemplate...), // else lookup the template id on the document then lookup the template with that id. if (_pcr.HasTemplate) { LogHelper.Debug <PublishedContentRequest>("{0}Has a template already, and no alternate template.", () => tracePrefix); return; } // TODO: When we remove the need for a database for templates, then this id should be irrelavent, // not sure how were going to do this nicely. var templateId = _pcr.PublishedContent.TemplateId; if (templateId > 0) { LogHelper.Debug <PublishedContentRequestEngine>("{0}Look for template id={1}", () => tracePrefix, () => templateId); var template = ApplicationContext.Current.Services.FileService.GetTemplate(templateId); if (template == null) { throw new InvalidOperationException("The template with Id " + templateId + " does not exist, the page cannot render"); } _pcr.TemplateModel = template; LogHelper.Debug <PublishedContentRequestEngine>("{0}Got template id={1} alias=\"{2}\"", () => tracePrefix, () => template.Id, () => template.Alias); } else { LogHelper.Debug <PublishedContentRequestEngine>("{0}No specified template.", () => tracePrefix); } } else { // we have an alternate template specified. lookup the template with that alias // this means the we override any template that a content lookup might have set // so /path/to/page/template1?altTemplate=template2 will use template2 // ignore if the alias does not match - just trace if (_pcr.HasTemplate) { LogHelper.Debug <PublishedContentRequestEngine>("{0}Has a template already, but also an alternate template.", () => tracePrefix); } LogHelper.Debug <PublishedContentRequestEngine>("{0}Look for alternate template alias=\"{1}\"", () => tracePrefix, () => altTemplate); var template = ApplicationContext.Current.Services.FileService.GetTemplate(altTemplate); if (template != null) { _pcr.TemplateModel = template; LogHelper.Debug <PublishedContentRequestEngine>("{0}Got template id={1} alias=\"{2}\"", () => tracePrefix, () => template.Id, () => template.Alias); } else { LogHelper.Debug <PublishedContentRequestEngine>("{0}The template with alias=\"{1}\" does not exist, ignoring.", () => tracePrefix, () => altTemplate); } } if (!_pcr.HasTemplate) { LogHelper.Debug <PublishedContentRequestEngine>("{0}No template was found.", () => tracePrefix); // initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true // then reset _pcr.Document to null to force a 404. // // but: because we want to let MVC hijack routes even though no template is defined, we decide that // a missing template is OK but the request will then be forwarded to MVC, which will need to take // care of everything. // // so, don't set _pcr.Document to null here } else { LogHelper.Debug <PublishedContentRequestEngine>("{0}Running with template id={1} alias=\"{2}\"", () => tracePrefix, () => _pcr.TemplateModel.Id, () => _pcr.TemplateModel.Alias); } }