diff --git a/src/Umbraco.Web/Routing/ContentFinderByLegacy404.cs b/src/Umbraco.Web/Routing/ContentFinderByLegacy404.cs index c092668ea3..660c88e979 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByLegacy404.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByLegacy404.cs @@ -7,15 +7,11 @@ using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using umbraco; -using umbraco.interfaces; - namespace Umbraco.Web.Routing { /// /// Provides an implementation of that runs the legacy 404 logic. /// - /// Should be used as a last chance finder. internal class ContentFinderByLegacy404 : IContentFinder { /// @@ -25,8 +21,9 @@ namespace Umbraco.Web.Routing /// A value indicating whether an Umbraco document was found and assigned. public bool TryFindDocument(PublishedContentRequest pcr) { - LogHelper.Debug("Looking for a page to handler 404."); + LogHelper.Debug("Looking for a page to handle 404."); + // TODO - replace the whole logic and stop calling into library! var error404 = global::umbraco.library.GetCurrentNotFoundPageId(); var id = int.Parse(error404); @@ -51,6 +48,7 @@ namespace Umbraco.Web.Routing } pcr.PublishedContent = content; + pcr.SetIs404(); return content != null; } } diff --git a/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs b/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs index f46f393135..0824918dee 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs @@ -21,9 +21,6 @@ namespace Umbraco.Web.Routing // at the moment we load the legacy INotFoundHandler // excluding those that have been replaced by proper finders, // and run them. - // - // code from requestHandler.handle404 has been moved over to - // the new ContentFinderByLegacy404 finder. /// /// Tries to find and assign an Umbraco document to a PublishedContentRequest. @@ -32,34 +29,71 @@ namespace Umbraco.Web.Routing /// A value indicating whether an Umbraco document was found and assigned. public bool TryFindDocument(PublishedContentRequest docRequest) { - docRequest.PublishedContent = HandlePageNotFound(docRequest); + HandlePageNotFound(docRequest); return docRequest.HasPublishedContent; } - #region Copied over from presentation.requestHandler + #region Copied over and adapted from presentation.requestHandler //FIXME: this is temporary and should be obsoleted - IPublishedContent HandlePageNotFound(PublishedContentRequest docRequest) + void HandlePageNotFound(PublishedContentRequest docRequest) { LogHelper.Debug("Running for url='{0}'.", () => docRequest.Uri.AbsolutePath); - //XmlNode currentPage = null; - IPublishedContent currentPage = null; var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers(); foreach (var handler in GetNotFoundHandlers()) { + IContentFinder finder = null; + + LogHelper.Debug("Handler '{0}'.", () => handler.GetType().FullName); + + // replace with our own implementation + if (handler is global::umbraco.SearchForAlias) + finder = new ContentFinderByUrlAlias(); + else if (handler is global::umbraco.SearchForProfile) + finder = new ContentFinderByProfile(); + else if (handler is global::umbraco.SearchForTemplate) + finder = new ContentFinderByNiceUrlAndTemplate(); + else if (handler is global::umbraco.handle404) + finder = new ContentFinderByLegacy404(); + + if (finder != null) + { + LogHelper.Debug("Replace handler '{0}' by new finder '{1}'.", () => handler.GetType().FullName, () => finder.GetType().FullName); + if (finder.TryFindDocument(docRequest)) + { + // do NOT set docRequest.PublishedContent again here as + // it would clear any template that the finder might have set + LogHelper.Debug("Finder '{0}' found node with id={1}.", () => finder.GetType().FullName, () => docRequest.PublishedContent.Id); + if (docRequest.Is404) + LogHelper.Debug("Finder '{0}' set status to 404.", () => finder.GetType().FullName); + return; + } + } + + // else it's a legacy handler, run + if (handler.Execute(url) && handler.redirectID > 0) { - //currentPage = umbracoContent.GetElementById(handler.redirectID.ToString()); - currentPage = docRequest.RoutingContext.PublishedContentStore.GetDocumentById( + docRequest.PublishedContent = docRequest.RoutingContext.PublishedContentStore.GetDocumentById( docRequest.RoutingContext.UmbracoContext, handler.redirectID); - // FIXME - could it be null? + if (!docRequest.HasPublishedContent) + { + LogHelper.Debug("Handler '{0}' found node with id={1} which is not valid.", () => handler.GetType().FullName, () => handler.redirectID); + break; + } - LogHelper.Debug("Handler '{0}' found node with id={1}.", () => handler.GetType().FullName, () => handler.redirectID); + LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handler.GetType().FullName, () => handler.redirectID); + + if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404) + { + LogHelper.Debug("Handler '{0}' set status code to 404.", () => handler.GetType().FullName); + docRequest.Is404 = true; + } //// check for caching //if (handler.CacheUrl) @@ -78,60 +112,6 @@ namespace Umbraco.Web.Routing break; } } - - return currentPage; - } - - static IEnumerable _customHandlerTypes = null; - static readonly object CustomHandlerTypesLock = new object(); - - IEnumerable InitializeNotFoundHandlers() - { - // initialize handlers - // create the definition cache - - LogHelper.Debug("Registering custom handlers."); - - var customHandlerTypes = new List(); - - var customHandlers = new XmlDocument(); - customHandlers.Load(Umbraco.Core.IO.IOHelper.MapPath(Umbraco.Core.IO.SystemFiles.NotFoundhandlersConfig)); - - foreach (XmlNode n in customHandlers.DocumentElement.SelectNodes("notFound")) - { - var assemblyName = n.Attributes.GetNamedItem("assembly").Value; - - // skip those that are in umbraco.dll because we have replaced them with finders - if (assemblyName == "umbraco") - continue; - - var typeName = n.Attributes.GetNamedItem("type").Value; - string ns = assemblyName; - var nsAttr = n.Attributes.GetNamedItem("namespace"); - if (nsAttr != null && !string.IsNullOrWhiteSpace(nsAttr.Value)) - ns = nsAttr.Value; - - LogHelper.Debug("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName); - - Type type = null; - try - { - //TODO: This isn't a good way to load the assembly, its already in the Domain so we should be getting the type - // this loads the assembly into the wrong assembly load context!! - - var assembly = Assembly.LoadFrom(Umbraco.Core.IO.IOHelper.MapPath(Umbraco.Core.IO.SystemDirectories.Bin + "/" + assemblyName + ".dll")); - type = assembly.GetType(ns + "." + typeName); - } - catch (Exception e) - { - LogHelper.Error("Error registering handler, ignoring.", e); - } - - if (type != null) - customHandlerTypes.Add(type); - } - - return customHandlerTypes; } IEnumerable GetNotFoundHandlers() @@ -139,15 +119,9 @@ namespace Umbraco.Web.Routing // instanciate new handlers // using definition cache - lock (CustomHandlerTypesLock) - { - if (_customHandlerTypes == null) - _customHandlerTypes = InitializeNotFoundHandlers(); - } - var handlers = new List(); - foreach (var type in _customHandlerTypes) + foreach (var type in NotFoundHandlerHelper.CustomHandlerTypes) { try { diff --git a/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs b/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs index 1442642e6f..cc0a3e6a3a 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs @@ -23,7 +23,6 @@ namespace Umbraco.Web.Routing /// A value indicating whether an Umbraco document was found and assigned. public bool TryFindDocument(PublishedContentRequest docRequest) { - IPublishedContent node = null; if (docRequest.Uri.AbsolutePath != "/") // no alias if "/" diff --git a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs index 94cdb5aeaf..082e28c35a 100644 --- a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs +++ b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs @@ -3,14 +3,24 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; +using System.Xml; +using System.Reflection; + +using Umbraco.Core; +using Umbraco.Core.Logging; namespace Umbraco.Web.Routing { // provides internal access to legacy url -- should get rid of it eventually - internal static class NotFoundHandlerHelper + internal class NotFoundHandlerHelper { const string ContextKey = "Umbraco.Web.Routing.NotFoundHandlerHelper.Url"; + static NotFoundHandlerHelper() + { + InitializeNotFoundHandlers(); + } + public static string GetLegacyUrlForNotFoundHandlers() { // that's not backward-compatible because when requesting "/foo.aspx" @@ -70,5 +80,60 @@ namespace Umbraco.Web.Routing httpContext.Items[ContextKey] = tmp; return tmp; } - } + + static IEnumerable _customHandlerTypes = null; + + static void InitializeNotFoundHandlers() + { + // initialize handlers + // create the definition cache + + LogHelper.Debug("Registering custom handlers."); + + var customHandlerTypes = new List(); + + var customHandlers = new XmlDocument(); + customHandlers.Load(Umbraco.Core.IO.IOHelper.MapPath(Umbraco.Core.IO.SystemFiles.NotFoundhandlersConfig)); + + foreach (XmlNode n in customHandlers.DocumentElement.SelectNodes("notFound")) + { + var assemblyName = n.Attributes.GetNamedItem("assembly").Value; + var typeName = n.Attributes.GetNamedItem("type").Value; + + string ns = assemblyName; + var nsAttr = n.Attributes.GetNamedItem("namespace"); + if (nsAttr != null && !string.IsNullOrWhiteSpace(nsAttr.Value)) + ns = nsAttr.Value; + + LogHelper.Debug("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName); + + Type type = null; + try + { + //TODO: This isn't a good way to load the assembly, its already in the Domain so we should be getting the type + // this loads the assembly into the wrong assembly load context!! + + var assembly = Assembly.LoadFrom(Umbraco.Core.IO.IOHelper.MapPath(Umbraco.Core.IO.SystemDirectories.Bin + "/" + assemblyName + ".dll")); + type = assembly.GetType(ns + "." + typeName); + } + catch (Exception e) + { + LogHelper.Error("Error registering handler, ignoring.", e); + } + + if (type != null) + customHandlerTypes.Add(type); + } + + _customHandlerTypes = customHandlerTypes; + } + + public static IEnumerable CustomHandlerTypes + { + get + { + return _customHandlerTypes; + } + } + } } diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 1d89a71018..b8cc3a346c 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -189,7 +189,9 @@ namespace Umbraco.Web typeof (RenderControllerFactory) }); - ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver(new ContentFinderByLegacy404()); + // the legacy 404 will run from within ContentFinderByNotFoundHandlers below + // so for the time being there is no last chance finder + ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver(); ContentFinderResolver.Current = new ContentFinderResolver( //add all known resolvers in the correct order, devs can then modify this list on application startup either by binding to events @@ -199,9 +201,11 @@ namespace Umbraco.Web typeof (ContentFinderByPageIdQuery), typeof (ContentFinderByNiceUrl), typeof (ContentFinderByIdPath), - typeof (ContentFinderByNiceUrlAndTemplate), - typeof (ContentFinderByProfile), - typeof (ContentFinderByUrlAlias), + // these will be handled by ContentFinderByNotFoundHandlers + // so they can be enabled/disabled even though resolvers are not public yet + //typeof (ContentFinderByNiceUrlAndTemplate), + //typeof (ContentFinderByProfile), + //typeof (ContentFinderByUrlAlias), typeof (ContentFinderByNotFoundHandlers) });