routing, fix "no content" splash, fix "no template" handling, fix redirects

This commit is contained in:
Stephan
2012-09-28 07:04:33 -02:00
parent d8c2a71531
commit b0e336e01f
5 changed files with 137 additions and 85 deletions

View File

@@ -148,6 +148,11 @@ namespace Umbraco.Core.Configuration
get { return "~/default.aspx"; }
}
internal static string NoContentSplashPage
{
get { return "~/config/splashes/noNodes.aspx"; }
}
/// <summary>
/// Gets a value indicating whether logging is enabled in umbracoSettings.config (/settings/logging/enableLogging).
/// </summary>

View File

@@ -88,6 +88,13 @@ namespace Umbraco.Web
return ConvertToDocument(GetXml(umbracoContext).SelectSingleNode(xpath));
}
public bool HasContent(UmbracoContext umbracoContext)
{
const string xpath = "/root/*[@isDoc]";
var node = GetXml(umbracoContext).SelectSingleNode(xpath);
return node != null;
}
XmlDocument GetXml(UmbracoContext umbracoContext)
{
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");

View File

@@ -9,5 +9,6 @@ namespace Umbraco.Web
{
IDocument GetDocumentByRoute(UmbracoContext umbracoContext, string route, bool? hideTopLevelNode = null);
IDocument GetDocumentByUrlAlias(UmbracoContext umbracoContext, int rootNodeId, string alias);
bool HasContent(UmbracoContext umbracoContext);
}
}

View File

@@ -231,7 +231,10 @@ namespace Umbraco.Web.Routing
/// Follows internal redirections through the <c>umbracoInternalRedirectId</c> document property.
/// </summary>
/// <returns>A value indicating whether redirection took place and led to a new published document.</returns>
/// <remarks>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</remarks>
/// <remarks>
/// <para>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</para>
/// <para>As per legacy, if the redirect does not work, we just ignore it.</para>
/// </remarks>
private bool FollowInternalRedirects()
{
const string tracePrefix = "FollowInternalRedirects: ";
@@ -252,8 +255,8 @@ namespace Umbraco.Web.Routing
if (internalRedirectId <= 0)
{
// bad redirect
_documentRequest.Document = null;
// bad redirect - log and display the current page (legacy behavior)
//_documentRequest.Document = null; // no! that would be to force a 404
LogHelper.Debug<DocumentRequest>("{0}Failed to redirect to id={1}: invalid value", () => tracePrefix, () => internalRedirect);
}
else if (internalRedirectId == _documentRequest.DocumentId)
@@ -375,18 +378,22 @@ namespace Umbraco.Web.Routing
if (!_documentRequest.HasTemplate)
{
LogHelper.Debug<DocumentRequest>("{0}No template was found.");
// do not do it if we're already 404 else it creates an infinite loop
if (Umbraco.Core.Configuration.UmbracoSettings.HandleMissingTemplateAs404 && !_documentRequest.Is404)
{
LogHelper.Debug<DocumentRequest>("{0}Assume page not found (404).");
_documentRequest.Document = null;
}
// initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true
// then reset _documentRequest.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 _documentRequest.Document to null here
}
}
/// <summary>
/// Follows external redirection through <c>umbracoRedirect</c> document property.
/// </summary>
/// <remarks>As per legacy, if the redirect does not work, we just ignore it.</remarks>
private void FollowRedirect()
{
if (_documentRequest.HasNode)

View File

@@ -34,9 +34,12 @@ namespace Umbraco.Web
/// <param name="httpContext"></param>
void BeginRequest(HttpContextBase httpContext)
{
// do not process if client-side request
if (IsClientSideRequest(httpContext.Request.Url))
return;
// ok, process
// create the LegacyRequestInitializer
// and initialize legacy stuff
var legacyRequestInitializer = new LegacyRequestInitializer(httpContext.Request.Url, httpContext);
@@ -68,95 +71,100 @@ namespace Umbraco.Web
/// <param name="httpContext"></param>
void ProcessRequest(HttpContextBase httpContext)
{
// do not process if client-side request
if (IsClientSideRequest(httpContext.Request.Url))
return;
var umbracoContext = UmbracoContext.Current;
var routingContext = umbracoContext.RoutingContext;
// remap to handler if it is a base rest request
// do not process but remap to handler if it is a base rest request
if (BaseRest.BaseRestHandler.IsBaseRestRequest(umbracoContext.RequestUrl))
{
httpContext.RemapHandler(new BaseRest.BaseRestHandler());
return;
}
else
//do not continue if this request is not a front-end routable page
if (EnsureUmbracoRoutablePage(umbracoContext, httpContext))
// do not process if this request is not a front-end routable page
if (!EnsureUmbracoRoutablePage(umbracoContext, httpContext))
return;
// ok, process
var uri = umbracoContext.RequestUrl;
// legacy - no idea what this is
LegacyCleanUmbPageFromQueryString(ref uri);
// create the new document request since we're rendering a document on the front-end
var docreq = new DocumentRequest(
umbracoContext.UmbracoUrl, //very important to use this url! it is the path only lowercased version of the current URL.
routingContext);
//assign the document request to the umbraco context now that we know its a front end request
umbracoContext.DocumentRequest = docreq;
// note - at that point the original legacy module did something do handle IIS custom 404 errors
// ie pages looking like /anything.aspx?404;/path/to/document - I guess the reason was to support
// "directory urls" without having to do wildcard mapping to ASP.NET on old IIS. This is a pain
// to maintain and probably not used anymore - removed as of 06/2012. @zpqrtbnk.
//
// to trigger Umbraco's not-found, one should configure IIS and/or ASP.NET custom 404 errors
// so that they point to a non-existing page eg /redirect-404.aspx
// TODO: SD: We need more information on this for when we release 4.10.0 as I'm not sure what this means.
//create the searcher
var searcher = new DocumentRequestBuilder(docreq);
//find domain
searcher.LookupDomain();
// redirect if it has been flagged
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
//set the culture on the thread
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = docreq.Culture;
//find the document, found will be true if the doc request has found BOTH a node and a template
// though currently we don't use this value.
var found = searcher.LookupDocument();
//this could be called in the LookupDocument method, but I've just put it here for clarity.
searcher.DetermineRenderingEngine();
//TODO: here we should launch an event so that people can modify the doc request to do whatever they want.
// redirect if it has been flagged
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
// handle 404
if (docreq.Is404)
{
httpContext.Response.StatusCode = 404;
if (!docreq.HasNode)
{
var uri = umbracoContext.RequestUrl;
// legacy - no idea what this is
LegacyCleanUmbPageFromQueryString(ref uri);
//Create a document request since we are rendering a document on the front-end
// create the new document request
var docreq = new DocumentRequest(
umbracoContext.UmbracoUrl, //very important to use this url! it is the path only lowercased version of the current URL.
routingContext);
//assign the document request to the umbraco context now that we know its a front end request
umbracoContext.DocumentRequest = docreq;
// note - at that point the original legacy module did something do handle IIS custom 404 errors
// ie pages looking like /anything.aspx?404;/path/to/document - I guess the reason was to support
// "directory urls" without having to do wildcard mapping to ASP.NET on old IIS. This is a pain
// to maintain and probably not used anymore - removed as of 06/2012. @zpqrtbnk.
//
// to trigger Umbraco's not-found, one should configure IIS and/or ASP.NET custom 404 errors
// so that they point to a non-existing page eg /redirect-404.aspx
// TODO: SD: We need more information on this for when we release 4.10.0 as I'm not sure what this means.
//create the searcher
var searcher = new DocumentRequestBuilder(docreq);
//find domain
searcher.LookupDomain();
// redirect if it has been flagged
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
//set the culture on the thread
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = docreq.Culture;
//find the document, found will be true if the doc request has found BOTH a node and a template
// though currently we don't use this value.
var found = searcher.LookupDocument();
//this could be called in the LookupDocument method, but I've just put it here for clarity.
searcher.DetermineRenderingEngine();
//TODO: here we should launch an event so that people can modify the doc request to do whatever they want.
// redirect if it has been flagged
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
// handle 404
if (docreq.Is404)
{
httpContext.Response.StatusCode = 404;
if (!docreq.HasNode)
httpContext.RemapHandler(new DocumentNotFoundHandler());
else if (!docreq.HasTemplate)
httpContext.RemapHandler(new NoTemplateHandler());
// else we have a document to render
}
if (docreq.HasNode && docreq.HasTemplate)
{
// everything is ready to pass off to our handlers (mvc or webforms)
// still need to setup a few things to deal with legacy code
// assign the legagcy page back to the docrequest
// handlers like default.aspx will want it
docreq.UmbracoPage = new page(docreq);
// these two are used by many legacy objects
httpContext.Items["pageID"] = docreq.DocumentId;
httpContext.Items["pageElements"] = docreq.UmbracoPage.Elements;
RewriteToUmbracoHandler(HttpContext.Current, uri.Query, docreq.RenderingEngine);
}
httpContext.RemapHandler(new DocumentNotFoundHandler());
return;
}
// else we have a document to render
// not having a template is ok here, MVC will take care of it
}
// just be safe - should never ever happen
if (!docreq.HasNode)
throw new Exception("No document to render.");
// render even though we might have no template
// to give MVC a chance to hijack routes
// pass off to our handlers (mvc or webforms)
// assign the legacy page back to the docrequest
// handlers like default.aspx will want it
docreq.UmbracoPage = new page(docreq);
// these two are used by many legacy objects
httpContext.Items["pageID"] = docreq.DocumentId;
httpContext.Items["pageElements"] = docreq.UmbracoPage.Elements;
RewriteToUmbracoHandler(HttpContext.Current, uri.Query, docreq.RenderingEngine);
}
/// <summary>
@@ -212,6 +220,9 @@ namespace Umbraco.Web
// ensure Umbraco is properly configured to serve documents
if (!EnsureIsConfigured(httpContext, uri))
return false;
// ensure Umbraco has documents to serve
if (!EnsureHasContent(httpContext))
return false;
return true;
}
@@ -298,6 +309,27 @@ namespace Umbraco.Web
return true;
}
// ensures Umbraco has at least one published node
// if not, rewrites to splash and return false
// if yes, return true
bool EnsureHasContent(HttpContextBase httpContext)
{
var context = UmbracoContext.Current;
var store = context.RoutingContext.PublishedContentStore;
if (!store.HasContent(context))
{
LogHelper.Warn<UmbracoModule>("Umbraco has not content");
var noContentUrl = UriUtility.ToAbsolute(UmbracoSettings.NoContentSplashPage);
httpContext.RewritePath(noContentUrl);
return false;
}
else
{
return true;
}
}
// ensures Umbraco is configured
// if not, redirect to install and return false
// if yes, return true