diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
index 1304b284de..2c7e2a00d3 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
@@ -148,6 +148,11 @@ namespace Umbraco.Core.Configuration
get { return "~/default.aspx"; }
}
+ internal static string NoContentSplashPage
+ {
+ get { return "~/config/splashes/noNodes.aspx"; }
+ }
+
///
/// Gets a value indicating whether logging is enabled in umbracoSettings.config (/settings/logging/enableLogging).
///
diff --git a/src/Umbraco.Web/DefaultPublishedContentStore.cs b/src/Umbraco.Web/DefaultPublishedContentStore.cs
index 69df99713e..52fba94835 100644
--- a/src/Umbraco.Web/DefaultPublishedContentStore.cs
+++ b/src/Umbraco.Web/DefaultPublishedContentStore.cs
@@ -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");
diff --git a/src/Umbraco.Web/IPublishedContentStore.cs b/src/Umbraco.Web/IPublishedContentStore.cs
index 9195e8bc7d..c603b58c44 100644
--- a/src/Umbraco.Web/IPublishedContentStore.cs
+++ b/src/Umbraco.Web/IPublishedContentStore.cs
@@ -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);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Routing/DocumentRequestBuilder.cs b/src/Umbraco.Web/Routing/DocumentRequestBuilder.cs
index 6ab2df3e38..0a12206f84 100644
--- a/src/Umbraco.Web/Routing/DocumentRequestBuilder.cs
+++ b/src/Umbraco.Web/Routing/DocumentRequestBuilder.cs
@@ -231,7 +231,10 @@ namespace Umbraco.Web.Routing
/// Follows internal redirections through the umbracoInternalRedirectId document property.
///
/// A value indicating whether redirection took place and led to a new published document.
- /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.
+ ///
+ /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.
+ /// As per legacy, if the redirect does not work, we just ignore it.
+ ///
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("{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("{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("{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
}
}
///
/// Follows external redirection through umbracoRedirect document property.
///
+ /// As per legacy, if the redirect does not work, we just ignore it.
private void FollowRedirect()
{
if (_documentRequest.HasNode)
diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs
index beccdf1f12..d35cd99f91 100644
--- a/src/Umbraco.Web/UmbracoModule.cs
+++ b/src/Umbraco.Web/UmbracoModule.cs
@@ -34,9 +34,12 @@ namespace Umbraco.Web
///
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
///
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);
}
///
@@ -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("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