Updated DocumentRequest so that it doesn't actually do the searching, it acts more like a model.
The DocumentSearcher now performs the searching and sets the properties on the DocumentRequest, this simplifies the dependencies between the contexts. Updated the LookupByNiceUrlTests unit test, now all initialization is working and the test runs which will be the basis for testing all of the IDocumentLookups.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Resolving;
|
||||
@@ -7,40 +9,102 @@ using Umbraco.Tests.Stubs;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Routing;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.cms.businesslogic.cache;
|
||||
using umbraco.cms.businesslogic.template;
|
||||
|
||||
namespace Umbraco.Tests.DocumentLookups
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
[TestFixture, RequiresSTA]
|
||||
public abstract class BaseTest
|
||||
{
|
||||
[SetUp]
|
||||
public virtual void Initialize()
|
||||
{
|
||||
TestHelper.SetupLog4NetForTests();
|
||||
|
||||
TestHelper.InitializeDatabase();
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public virtual void TearDown()
|
||||
{
|
||||
ActionsResolver.Reset();
|
||||
//reset the context on global settings
|
||||
Umbraco.Core.Configuration.GlobalSettings.HttpContext = null;
|
||||
Resolution.IsFrozen = false;
|
||||
TestHelper.ClearDatabase();
|
||||
Cache.ClearAllCache();
|
||||
}
|
||||
|
||||
protected FakeHttpContextFactory GetHttpContextFactory(string url)
|
||||
{
|
||||
var factory = new FakeHttpContextFactory(url);
|
||||
|
||||
//set the state helper
|
||||
StateHelper.HttpContext = factory.HttpContext;
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
protected UmbracoContext GetUmbracoContext(string url)
|
||||
private UmbracoContext GetUmbracoContext(string url, Template template)
|
||||
{
|
||||
return new UmbracoContext(
|
||||
var ctx = new UmbracoContext(
|
||||
GetHttpContextFactory(url).HttpContext,
|
||||
new ApplicationContext(),
|
||||
new NullRoutesCache());
|
||||
new FakeRoutesCache());
|
||||
SetupUmbracoContextForTest(ctx, template);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
protected RoutingContext GetRoutingContext(string url, Template template)
|
||||
{
|
||||
var umbracoContext = GetUmbracoContext(url, template);
|
||||
var contentStore = new ContentStore(umbracoContext);
|
||||
var niceUrls = new NiceUrlProvider(contentStore, umbracoContext);
|
||||
var routingRequest = new RoutingContext(
|
||||
umbracoContext,
|
||||
Enumerable.Empty<IDocumentLookup>(),
|
||||
new FakeLastChanceLookup(),
|
||||
contentStore,
|
||||
niceUrls);
|
||||
return routingRequest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initlializes the UmbracoContext with specific XML
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext"></param>
|
||||
/// <param name="template"></param>
|
||||
protected void SetupUmbracoContextForTest(UmbracoContext umbracoContext, Template template)
|
||||
{
|
||||
umbracoContext.GetXmlDelegate = () =>
|
||||
{
|
||||
var xDoc = new XmlDocument();
|
||||
|
||||
//create a custom xml structure to return
|
||||
|
||||
xDoc.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?><!DOCTYPE root[
|
||||
<!ELEMENT Home ANY>
|
||||
<!ATTLIST Home id ID #REQUIRED>
|
||||
|
||||
]>
|
||||
<root id=""-1"">
|
||||
<Home id=""1046"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + template.Id + @""" sortOrder=""2"" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" nodeName=""Home"" urlName=""home"" writerName=""admin"" creatorName=""admin"" path=""-1,1046"" isDoc=""""><content><![CDATA[]]></content>
|
||||
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + template.Id + @""" sortOrder=""1"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc=""""><content><![CDATA[]]></content>
|
||||
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + template.Id + @""" sortOrder=""1"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + template.Id + @""" sortOrder=""2"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
</Home>
|
||||
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + template.Id + @""" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
</Home>
|
||||
<Home id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + template.Id + @""" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
|
||||
</root>");
|
||||
//return the custom x doc
|
||||
return xDoc;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +116,16 @@ namespace Umbraco.Tests.DocumentLookups
|
||||
[Test]
|
||||
public void Test_Default_ASPX()
|
||||
{
|
||||
var urlAsString = "http://localhost/default.aspx";
|
||||
var ctx = GetUmbracoContext(urlAsString);
|
||||
var cleanUrl = new Uri(urlAsString);
|
||||
var path = ctx.RequestUrl.AbsolutePath.ToLower();
|
||||
var urlAsString = "/default.aspx";
|
||||
var template = Template.MakeNew("test", new User(0));
|
||||
var routingContext = GetRoutingContext(urlAsString, template);
|
||||
var cleanUrl = routingContext.UmbracoContext.HttpContext.Request.Url;
|
||||
var path = routingContext.UmbracoContext.RequestUrl.AbsolutePath.ToLower();
|
||||
UmbracoModule.LegacyCleanUmbPageFromQueryString(ref cleanUrl, ref path);
|
||||
var docRequest = new DocumentRequest(cleanUrl, ctx);
|
||||
var lookup = new LookupByNiceUrl();
|
||||
|
||||
var docRequest = new DocumentRequest(cleanUrl, routingContext);
|
||||
|
||||
var lookup = new LookupByNiceUrl();
|
||||
var result = lookup.TrySetDocument(docRequest);
|
||||
}
|
||||
|
||||
|
||||
12
src/Umbraco.Tests/Stubs/FakeLastChanceLookup.cs
Normal file
12
src/Umbraco.Tests/Stubs/FakeLastChanceLookup.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Stubs
|
||||
{
|
||||
internal class FakeLastChanceLookup : IDocumentLastChanceLookup
|
||||
{
|
||||
public bool TrySetDocument(DocumentRequest docRequest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Tests.Stubs
|
||||
/// <summary>
|
||||
/// Used for testing, does not cache anything
|
||||
/// </summary>
|
||||
public class NullRoutesCache : IRoutesCache
|
||||
public class FakeRoutesCache : IRoutesCache
|
||||
{
|
||||
public void Store(int nodeId, string route)
|
||||
{
|
||||
@@ -1,15 +1,48 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using SqlCE4Umbraco;
|
||||
using log4net.Config;
|
||||
using umbraco;
|
||||
using umbraco.DataLayer;
|
||||
|
||||
namespace Umbraco.Tests.TestHelpers
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Common helper properties and methods useful to testing
|
||||
/// </summary>
|
||||
public static class TestHelper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Clears an initialized database
|
||||
/// </summary>
|
||||
public static void ClearDatabase()
|
||||
{
|
||||
var dataHelper = DataLayerHelper.CreateSqlHelper(GlobalSettings.DbDSN) as SqlCEHelper;
|
||||
if (dataHelper == null)
|
||||
throw new InvalidOperationException("The sql helper for unit tests must be of type SqlCEHelper, check the ensure the connection string used for this test is set to use SQLCE");
|
||||
dataHelper.ClearDatabase();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new database
|
||||
/// </summary>
|
||||
public static void InitializeDatabase()
|
||||
{
|
||||
ConfigurationManager.AppSettings.Set("umbracoDbDSN", @"datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;data source=|DataDirectory|\Umbraco.sdf");
|
||||
|
||||
ClearDatabase();
|
||||
|
||||
var dataHelper = DataLayerHelper.CreateSqlHelper(GlobalSettings.DbDSN);
|
||||
var installer = dataHelper.Utility.CreateInstaller();
|
||||
if (installer.CanConnect)
|
||||
{
|
||||
installer.Install();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current assembly directory.
|
||||
/// </summary>
|
||||
|
||||
@@ -67,7 +67,8 @@
|
||||
<Compile Include="PackageActionsResolverTests.cs" />
|
||||
<Compile Include="PluginManagerExtensions.cs" />
|
||||
<Compile Include="PluginManagerTests.cs" />
|
||||
<Compile Include="Stubs\NullRoutesCache.cs" />
|
||||
<Compile Include="Stubs\FakeLastChanceLookup.cs" />
|
||||
<Compile Include="Stubs\FakeRoutesCache.cs" />
|
||||
<Compile Include="TestHelpers\TestHelper.cs" />
|
||||
<Compile Include="EnumerableExtensionsTests.cs" />
|
||||
<Compile Include="PartialTrust\AbstractPartialTrustFixture.cs" />
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Tests
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedPaths", "~/umbraco,~/install/");
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedUrls", "~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd");
|
||||
Cache.ClearAllCache();
|
||||
InitializeDatabase();
|
||||
TestHelper.InitializeDatabase();
|
||||
|
||||
//create the not found handlers config
|
||||
using(var sw = File.CreateText(IOHelper.MapPath(SystemFiles.NotFoundhandlersConfig, false)))
|
||||
@@ -67,32 +67,10 @@ namespace Umbraco.Tests
|
||||
ConfigurationManager.AppSettings.Set("umbracoConfigurationStatus", "");
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedPaths", "");
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedUrls", "");
|
||||
ClearDatabase();
|
||||
TestHelper.ClearDatabase();
|
||||
Cache.ClearAllCache();
|
||||
}
|
||||
|
||||
private void ClearDatabase()
|
||||
{
|
||||
var dataHelper = DataLayerHelper.CreateSqlHelper(GlobalSettings.DbDSN) as SqlCEHelper;
|
||||
if (dataHelper == null)
|
||||
throw new InvalidOperationException("The sql helper for unit tests must be of type SqlCEHelper, check the ensure the connection string used for this test is set to use SQLCE");
|
||||
dataHelper.ClearDatabase();
|
||||
}
|
||||
|
||||
private void InitializeDatabase()
|
||||
{
|
||||
ConfigurationManager.AppSettings.Set("umbracoDbDSN", @"datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;data source=|DataDirectory|\Umbraco.sdf");
|
||||
|
||||
ClearDatabase();
|
||||
|
||||
var dataHelper = DataLayerHelper.CreateSqlHelper(GlobalSettings.DbDSN);
|
||||
var installer = dataHelper.Utility.CreateInstaller();
|
||||
if (installer.CanConnect)
|
||||
{
|
||||
installer.Install();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initlializes the UmbracoContext with specific XML
|
||||
/// </summary>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Umbraco.Web.Mvc
|
||||
/// </summary>
|
||||
protected UmbracoContext UmbracoContext
|
||||
{
|
||||
get { return DocumentRequest.UmbracoContext; }
|
||||
get { return DocumentRequest.RoutingContext.UmbracoContext; }
|
||||
}
|
||||
|
||||
//TODO: make this protected once we make DocumentRequest not internal after we figure out what it should actually contain
|
||||
|
||||
21
src/Umbraco.Web/Routing/DocumentLookupBase.cs
Normal file
21
src/Umbraco.Web/Routing/DocumentLookupBase.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
///// <summary>
|
||||
///// Abstract DocumentLookup class
|
||||
///// </summary>
|
||||
//internal abstract class DocumentLookupBase : IDocumentLookup
|
||||
//{
|
||||
// public bool TrySetDocument(DocumentRequest docRequest)
|
||||
// {
|
||||
// if (docRequest == null) throw new ArgumentNullException("docRequest");
|
||||
// if (docRequest.RoutingContext == null) throw new ArgumentNullException("docRequest.RoutingContext");
|
||||
// if (docRequest.RoutingContext.UmbracoContext == null) throw new ArgumentNullException("docRequest.UmbracoContext");
|
||||
|
||||
// return TrySetDocument(docRequest, docRequest.RoutingContext, docRequest.UmbracoContext);
|
||||
// }
|
||||
|
||||
// protected abstract bool TrySetDocument(DocumentRequest docRequest, RoutingContext routingContext, UmbracoContext umbracoContext);
|
||||
//}
|
||||
}
|
||||
@@ -13,25 +13,20 @@ using umbraco.NodeFactory;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.cms.businesslogic.template;
|
||||
using umbraco.cms.businesslogic.member;
|
||||
using umbraco.cms.businesslogic.language;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// represents a request for one specified Umbraco document to be rendered
|
||||
/// by one specified template, using one particular culture.
|
||||
/// </summary>
|
||||
internal class DocumentRequest
|
||||
{
|
||||
public DocumentRequest(Uri uri, UmbracoContext umbracoContext)
|
||||
public DocumentRequest(Uri uri, RoutingContext routingContext)
|
||||
{
|
||||
this.Uri = uri;
|
||||
RoutingContext = umbracoContext.RoutingContext;
|
||||
UmbracoContext = umbracoContext;
|
||||
RoutingContext = routingContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,9 +47,7 @@ namespace Umbraco.Web.Routing
|
||||
/// Returns the current RoutingContext
|
||||
/// </summary>
|
||||
public RoutingContext RoutingContext { get; private set; }
|
||||
|
||||
public UmbracoContext UmbracoContext { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The cleaned up Uri used for routing
|
||||
/// </summary>
|
||||
@@ -63,9 +56,9 @@ namespace Umbraco.Web.Routing
|
||||
/// <summary>
|
||||
/// Gets or sets the document request's domain.
|
||||
/// </summary>
|
||||
public Domain Domain { get; private set; }
|
||||
public Domain Domain { get; internal set; }
|
||||
|
||||
public Uri DomainUri { get; private set; }
|
||||
public Uri DomainUri { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the document request has a domain.
|
||||
@@ -158,7 +151,7 @@ namespace Umbraco.Web.Routing
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the requested document could not be found.
|
||||
/// </summary>
|
||||
public bool Is404 { get; private set; }
|
||||
public bool Is404 { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the document request triggers a redirect.
|
||||
@@ -171,326 +164,6 @@ namespace Umbraco.Web.Routing
|
||||
public string RedirectUrl { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lookup
|
||||
|
||||
/// <summary>
|
||||
/// Determines the site root (if any) matching the http request.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether a domain was found.</returns>
|
||||
internal bool LookupDomain()
|
||||
{
|
||||
const string tracePrefix = "LookupDomain: ";
|
||||
|
||||
// note - we are not handling schemes nor ports here.
|
||||
|
||||
LogHelper.Debug<DocumentRequest>("{0}Uri=\"{1}\"", () => tracePrefix, () => this.Uri);
|
||||
|
||||
// try to find a domain matching the current request
|
||||
var domainAndUri = DomainHelper.DomainMatch(Domain.GetDomains(), UmbracoContext.UmbracoUrl, false);
|
||||
|
||||
// handle domain
|
||||
if (domainAndUri != null)
|
||||
{
|
||||
// matching an existing domain
|
||||
LogHelper.Debug<DocumentRequest>("{0}Matches domain=\"{1}\", rootId={2}, culture=\"{3}\"",
|
||||
() => tracePrefix,
|
||||
() => domainAndUri.Domain.Name,
|
||||
() => domainAndUri.Domain.RootNodeId,
|
||||
() => domainAndUri.Domain.Language.CultureAlias);
|
||||
|
||||
this.Domain = domainAndUri.Domain;
|
||||
this.DomainUri = domainAndUri.Uri;
|
||||
this.Culture = new CultureInfo(domainAndUri.Domain.Language.CultureAlias);
|
||||
|
||||
// canonical? not implemented at the moment
|
||||
// if (...)
|
||||
// {
|
||||
// this.RedirectUrl = "...";
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
// not matching any existing domain
|
||||
LogHelper.Debug<DocumentRequest>("{0}Matches no domain", () => tracePrefix);
|
||||
|
||||
var defaultLanguage = Language.GetAllAsList().FirstOrDefault();
|
||||
this.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.CultureAlias);
|
||||
}
|
||||
|
||||
LogHelper.Debug<DocumentRequest>("{0}Culture=\"{1}\"", () => tracePrefix, () => this.Culture.Name);
|
||||
|
||||
return this.Domain != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the Umbraco document (if any) matching the http request.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether a document and template nave been found.</returns>
|
||||
internal bool LookupDocument()
|
||||
{
|
||||
const string tracePrefix = "LookupDocument: ";
|
||||
LogHelper.Debug<DocumentRequest>("{0}Path=\"{1}\"", () => tracePrefix, () => this.Uri.AbsolutePath);
|
||||
|
||||
// look for the document
|
||||
// the first successful resolver, if any, will set this.Node, and may also set this.Template
|
||||
// some lookups may implement caching
|
||||
|
||||
using (DisposableTimer.DebugDuration<PluginManager>(
|
||||
string.Format("{0}Begin resolvers", tracePrefix),
|
||||
string.Format("{0}End resolvers, {1}", tracePrefix, (this.HasNode ? "a document was found" : "no document was found"))))
|
||||
{
|
||||
RoutingContext.DocumentLookups.Any(lookup => lookup.TrySetDocument(this));
|
||||
}
|
||||
|
||||
// fixme - not handling umbracoRedirect
|
||||
// should come after internal redirects
|
||||
// so after ResolveDocument2() => docreq.IsRedirect => handled by the module!
|
||||
|
||||
// handle not-found, redirects, access, template
|
||||
LookupDocument2();
|
||||
|
||||
// handle umbracoRedirect (moved from umbraco.page)
|
||||
FollowRedirect();
|
||||
|
||||
bool resolved = this.HasNode && this.HasTemplate;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the document resolution second pass.
|
||||
/// </summary>
|
||||
/// <remarks>The second pass consists in handling "not found", internal redirects, access validation, and template.</remarks>
|
||||
private void LookupDocument2()
|
||||
{
|
||||
const string tracePrefix = "LookupDocument2: ";
|
||||
|
||||
// handle "not found", follow internal redirects, validate access, template
|
||||
// because these might loop, we have to have some sort of infinite loop detection
|
||||
int i = 0, j = 0;
|
||||
const int maxLoop = 12;
|
||||
do
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}{1}", () => tracePrefix, () => (i == 0 ? "Begin" : "Loop"));
|
||||
|
||||
// handle not found
|
||||
if (!this.HasNode)
|
||||
{
|
||||
this.Is404 = true;
|
||||
LogHelper.Debug<DocumentRequest>("{0}No document, try last chance lookup", () => tracePrefix);
|
||||
|
||||
// if it fails then give up, there isn't much more that we can do
|
||||
var lastChance = RoutingContext.DocumentLastChanceLookup;
|
||||
if (lastChance == null || !lastChance.TrySetDocument(this))
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Failed to find a document, give up", () => tracePrefix);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Found a document", () => tracePrefix);
|
||||
}
|
||||
}
|
||||
|
||||
// follow internal redirects as long as it's not running out of control ie infinite loop of some sort
|
||||
j = 0;
|
||||
while (FollowInternalRedirects() && j++ < maxLoop) ;
|
||||
if (j == maxLoop) // we're running out of control
|
||||
break;
|
||||
|
||||
// ensure access
|
||||
if (this.HasNode)
|
||||
EnsureNodeAccess();
|
||||
|
||||
// resolve template
|
||||
if (this.HasNode)
|
||||
LookupTemplate();
|
||||
|
||||
// loop while we don't have page, ie the redirect or access
|
||||
// got us to nowhere and now we need to run the notFoundLookup again
|
||||
// as long as it's not running out of control ie infinite loop of some sort
|
||||
|
||||
} while (!this.HasNode && i++ < maxLoop);
|
||||
|
||||
if (i == maxLoop || j == maxLoop)
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Looks like we're running into an infinite loop, abort", () => tracePrefix);
|
||||
this.XmlNode = null;
|
||||
}
|
||||
LogHelper.Debug<DocumentRequest>("{0}End", () => tracePrefix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
private bool FollowInternalRedirects()
|
||||
{
|
||||
const string tracePrefix = "FollowInternalRedirects: ";
|
||||
|
||||
if (this.XmlNode == null)
|
||||
throw new InvalidOperationException("There is no node.");
|
||||
|
||||
bool redirect = false;
|
||||
string internalRedirect = RoutingContext.ContentStore.GetNodeProperty(this.XmlNode, "umbracoInternalRedirectId");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(internalRedirect))
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Found umbracoInternalRedirectId={1}", () => tracePrefix, () => internalRedirect);
|
||||
|
||||
int internalRedirectId;
|
||||
if (!int.TryParse(internalRedirect, out internalRedirectId))
|
||||
internalRedirectId = -1;
|
||||
|
||||
if (internalRedirectId <= 0)
|
||||
{
|
||||
// bad redirect
|
||||
this.XmlNode = null;
|
||||
LogHelper.Debug<DocumentRequest>("{0}Failed to redirect to id={1}: invalid value", () => tracePrefix, () => internalRedirect);
|
||||
}
|
||||
else if (internalRedirectId == this.NodeId)
|
||||
{
|
||||
// redirect to self
|
||||
LogHelper.Debug<DocumentRequest>("{0}Redirecting to self, ignore", () => tracePrefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
// redirect to another page
|
||||
var node = RoutingContext.ContentStore.GetNodeById(internalRedirectId);
|
||||
this.XmlNode = node;
|
||||
if (node != null)
|
||||
{
|
||||
redirect = true;
|
||||
LogHelper.Debug<DocumentRequest>("{0}Redirecting to id={1}", () => tracePrefix, () => internalRedirectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Failed to redirect to id={1}: no such published document", () => tracePrefix, () => internalRedirectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that access to current node is permitted.
|
||||
/// </summary>
|
||||
/// <remarks>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</remarks>
|
||||
private void EnsureNodeAccess()
|
||||
{
|
||||
const string tracePrefix = "EnsurePageAccess: ";
|
||||
|
||||
if (this.XmlNode == null)
|
||||
throw new InvalidOperationException("There is no node.");
|
||||
|
||||
var path = RoutingContext.ContentStore.GetNodeProperty(this.XmlNode, "@path");
|
||||
|
||||
if (Access.IsProtected(this.NodeId, path))
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Page is protected, check for access", () => tracePrefix);
|
||||
|
||||
var user = System.Web.Security.Membership.GetUser();
|
||||
|
||||
if (user == null || !Member.IsLoggedOn())
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Not logged in, redirect to login page", () => tracePrefix);
|
||||
var loginPageId = Access.GetLoginPage(path);
|
||||
if (loginPageId != this.NodeId)
|
||||
this.XmlNode = RoutingContext.ContentStore.GetNodeById(loginPageId);
|
||||
}
|
||||
else if (!Access.HasAccces(this.NodeId, user.ProviderUserKey))
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Current member has not access, redirect to error page", () => tracePrefix);
|
||||
var errorPageId = Access.GetErrorPage(path);
|
||||
if (errorPageId != this.NodeId)
|
||||
this.XmlNode = RoutingContext.ContentStore.GetNodeById(errorPageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Current member has access", () => tracePrefix);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Page is not protected", () => tracePrefix);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a template for the current node.
|
||||
/// </summary>
|
||||
private void LookupTemplate()
|
||||
{
|
||||
const string tracePrefix = "LookupTemplate: ";
|
||||
|
||||
if (this.XmlNode == null)
|
||||
throw new InvalidOperationException("There is no node.");
|
||||
|
||||
var templateAlias = UmbracoContext.HttpContext.Request.QueryString["altTemplate"];
|
||||
if (string.IsNullOrWhiteSpace(templateAlias))
|
||||
templateAlias = UmbracoContext.HttpContext.Request.Form["altTemplate"];
|
||||
|
||||
// fixme - we might want to support cookies?!? NO but provide a hook to change the template
|
||||
|
||||
if (!this.HasTemplate || !string.IsNullOrWhiteSpace(templateAlias))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(templateAlias))
|
||||
{
|
||||
templateAlias = RoutingContext.ContentStore.GetNodeProperty(this.XmlNode, "@template");
|
||||
LogHelper.Debug<DocumentRequest>("{0}Look for template id={1}", () => tracePrefix, () => templateAlias);
|
||||
int templateId;
|
||||
if (!int.TryParse(templateAlias, out templateId))
|
||||
templateId = 0;
|
||||
this.Template = templateId > 0 ? new Template(templateId) : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Look for template alias=\"{1}\" (altTemplate)", () => tracePrefix, () => templateAlias);
|
||||
this.Template = Template.GetByAlias(templateAlias);
|
||||
}
|
||||
|
||||
if (!this.HasTemplate)
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}No template was found", () => tracePrefix);
|
||||
|
||||
//TODO: I like the idea of this new setting, but lets get this in to the core at a later time, for now lets just get the basics working.
|
||||
//if (Settings.HandleMissingTemplateAs404)
|
||||
//{
|
||||
// this.Node = null;
|
||||
// LogHelper.Debug<DocumentRequest>("{0}Assume page not found (404)", tracePrefix);
|
||||
//}
|
||||
|
||||
// else we have no template
|
||||
// and there isn't much more we can do about it
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Found", () => tracePrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Follows external redirection through <c>umbracoRedirect</c> document property.
|
||||
/// </summary>
|
||||
private void FollowRedirect()
|
||||
{
|
||||
if (this.HasNode)
|
||||
{
|
||||
int redirectId;
|
||||
if (!int.TryParse(RoutingContext.ContentStore.GetNodeProperty(this.XmlNode, "umbracoRedirect"), out redirectId))
|
||||
redirectId = -1;
|
||||
string redirectUrl = "#";
|
||||
if (redirectId > 0)
|
||||
redirectUrl = RoutingContext.NiceUrlProvider.GetNiceUrl(redirectId);
|
||||
if (redirectUrl != "#")
|
||||
this.RedirectUrl = redirectUrl;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
343
src/Umbraco.Web/Routing/DocumentSearcher.cs
Normal file
343
src/Umbraco.Web/Routing/DocumentSearcher.cs
Normal file
@@ -0,0 +1,343 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using umbraco.cms.businesslogic.language;
|
||||
using umbraco.cms.businesslogic.member;
|
||||
using umbraco.cms.businesslogic.template;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
internal class DocumentSearcher
|
||||
{
|
||||
private readonly DocumentRequest _documentRequest;
|
||||
private readonly UmbracoContext _umbracoContext;
|
||||
private readonly RoutingContext _routingContext;
|
||||
|
||||
public DocumentSearcher(DocumentRequest documentRequest)
|
||||
{
|
||||
_documentRequest = documentRequest;
|
||||
_umbracoContext = documentRequest.RoutingContext.UmbracoContext;
|
||||
_routingContext = documentRequest.RoutingContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the site root (if any) matching the http request.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether a domain was found.</returns>
|
||||
internal bool LookupDomain()
|
||||
{
|
||||
const string tracePrefix = "LookupDomain: ";
|
||||
|
||||
// note - we are not handling schemes nor ports here.
|
||||
|
||||
LogHelper.Debug<DocumentRequest>("{0}Uri=\"{1}\"", () => tracePrefix, () => _documentRequest.Uri);
|
||||
|
||||
// try to find a domain matching the current request
|
||||
var domainAndUri = DomainHelper.DomainMatch(Domain.GetDomains(), _umbracoContext.UmbracoUrl, false);
|
||||
|
||||
// handle domain
|
||||
if (domainAndUri != null)
|
||||
{
|
||||
// matching an existing domain
|
||||
LogHelper.Debug<DocumentRequest>("{0}Matches domain=\"{1}\", rootId={2}, culture=\"{3}\"",
|
||||
() => tracePrefix,
|
||||
() => domainAndUri.Domain.Name,
|
||||
() => domainAndUri.Domain.RootNodeId,
|
||||
() => domainAndUri.Domain.Language.CultureAlias);
|
||||
|
||||
_documentRequest.Domain = domainAndUri.Domain;
|
||||
_documentRequest.DomainUri = domainAndUri.Uri;
|
||||
_documentRequest.Culture = new CultureInfo(domainAndUri.Domain.Language.CultureAlias);
|
||||
|
||||
// canonical? not implemented at the moment
|
||||
// if (...)
|
||||
// {
|
||||
// this.RedirectUrl = "...";
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
// not matching any existing domain
|
||||
LogHelper.Debug<DocumentRequest>("{0}Matches no domain", () => tracePrefix);
|
||||
|
||||
var defaultLanguage = Language.GetAllAsList().FirstOrDefault();
|
||||
_documentRequest.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.CultureAlias);
|
||||
}
|
||||
|
||||
LogHelper.Debug<DocumentRequest>("{0}Culture=\"{1}\"", () => tracePrefix, () => _documentRequest.Culture.Name);
|
||||
|
||||
return _documentRequest.Domain != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the Umbraco document (if any) matching the http request.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether a document and template nave been found.</returns>
|
||||
internal bool LookupDocument()
|
||||
{
|
||||
const string tracePrefix = "LookupDocument: ";
|
||||
LogHelper.Debug<DocumentRequest>("{0}Path=\"{1}\"", () => tracePrefix, () => _documentRequest.Uri.AbsolutePath);
|
||||
|
||||
// look for the document
|
||||
// the first successful resolver, if any, will set this.Node, and may also set this.Template
|
||||
// some lookups may implement caching
|
||||
|
||||
using (DisposableTimer.DebugDuration<PluginManager>(
|
||||
string.Format("{0}Begin resolvers", tracePrefix),
|
||||
string.Format("{0}End resolvers, {1}", tracePrefix, (_documentRequest.HasNode ? "a document was found" : "no document was found"))))
|
||||
{
|
||||
_routingContext.DocumentLookups.Any(lookup => lookup.TrySetDocument(_documentRequest));
|
||||
}
|
||||
|
||||
// fixme - not handling umbracoRedirect
|
||||
// should come after internal redirects
|
||||
// so after ResolveDocument2() => docreq.IsRedirect => handled by the module!
|
||||
|
||||
// handle not-found, redirects, access, template
|
||||
LookupDocument2();
|
||||
|
||||
// handle umbracoRedirect (moved from umbraco.page)
|
||||
FollowRedirect();
|
||||
|
||||
bool resolved = _documentRequest.HasNode && _documentRequest.HasTemplate;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the document resolution second pass.
|
||||
/// </summary>
|
||||
/// <remarks>The second pass consists in handling "not found", internal redirects, access validation, and template.</remarks>
|
||||
private void LookupDocument2()
|
||||
{
|
||||
const string tracePrefix = "LookupDocument2: ";
|
||||
|
||||
// handle "not found", follow internal redirects, validate access, template
|
||||
// because these might loop, we have to have some sort of infinite loop detection
|
||||
int i = 0, j = 0;
|
||||
const int maxLoop = 12;
|
||||
do
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}{1}", () => tracePrefix, () => (i == 0 ? "Begin" : "Loop"));
|
||||
|
||||
// handle not found
|
||||
if (!_documentRequest.HasNode)
|
||||
{
|
||||
_documentRequest.Is404 = true;
|
||||
LogHelper.Debug<DocumentRequest>("{0}No document, try last chance lookup", () => tracePrefix);
|
||||
|
||||
// if it fails then give up, there isn't much more that we can do
|
||||
var lastChance = _routingContext.DocumentLastChanceLookup;
|
||||
if (lastChance == null || !lastChance.TrySetDocument(_documentRequest))
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Failed to find a document, give up", () => tracePrefix);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Found a document", () => tracePrefix);
|
||||
}
|
||||
}
|
||||
|
||||
// follow internal redirects as long as it's not running out of control ie infinite loop of some sort
|
||||
j = 0;
|
||||
while (FollowInternalRedirects() && j++ < maxLoop) ;
|
||||
if (j == maxLoop) // we're running out of control
|
||||
break;
|
||||
|
||||
// ensure access
|
||||
if (_documentRequest.HasNode)
|
||||
EnsureNodeAccess();
|
||||
|
||||
// resolve template
|
||||
if (_documentRequest.HasNode)
|
||||
LookupTemplate();
|
||||
|
||||
// loop while we don't have page, ie the redirect or access
|
||||
// got us to nowhere and now we need to run the notFoundLookup again
|
||||
// as long as it's not running out of control ie infinite loop of some sort
|
||||
|
||||
} while (!_documentRequest.HasNode && i++ < maxLoop);
|
||||
|
||||
if (i == maxLoop || j == maxLoop)
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Looks like we're running into an infinite loop, abort", () => tracePrefix);
|
||||
_documentRequest.XmlNode = null;
|
||||
}
|
||||
LogHelper.Debug<DocumentRequest>("{0}End", () => tracePrefix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
private bool FollowInternalRedirects()
|
||||
{
|
||||
const string tracePrefix = "FollowInternalRedirects: ";
|
||||
|
||||
if (_documentRequest.XmlNode == null)
|
||||
throw new InvalidOperationException("There is no node.");
|
||||
|
||||
bool redirect = false;
|
||||
string internalRedirect = _routingContext.ContentStore.GetNodeProperty(_documentRequest.XmlNode, "umbracoInternalRedirectId");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(internalRedirect))
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Found umbracoInternalRedirectId={1}", () => tracePrefix, () => internalRedirect);
|
||||
|
||||
int internalRedirectId;
|
||||
if (!int.TryParse(internalRedirect, out internalRedirectId))
|
||||
internalRedirectId = -1;
|
||||
|
||||
if (internalRedirectId <= 0)
|
||||
{
|
||||
// bad redirect
|
||||
_documentRequest.XmlNode = null;
|
||||
LogHelper.Debug<DocumentRequest>("{0}Failed to redirect to id={1}: invalid value", () => tracePrefix, () => internalRedirect);
|
||||
}
|
||||
else if (internalRedirectId == _documentRequest.NodeId)
|
||||
{
|
||||
// redirect to self
|
||||
LogHelper.Debug<DocumentRequest>("{0}Redirecting to self, ignore", () => tracePrefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
// redirect to another page
|
||||
var node = _routingContext.ContentStore.GetNodeById(internalRedirectId);
|
||||
_documentRequest.XmlNode = node;
|
||||
if (node != null)
|
||||
{
|
||||
redirect = true;
|
||||
LogHelper.Debug<DocumentRequest>("{0}Redirecting to id={1}", () => tracePrefix, () => internalRedirectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Failed to redirect to id={1}: no such published document", () => tracePrefix, () => internalRedirectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that access to current node is permitted.
|
||||
/// </summary>
|
||||
/// <remarks>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</remarks>
|
||||
private void EnsureNodeAccess()
|
||||
{
|
||||
const string tracePrefix = "EnsurePageAccess: ";
|
||||
|
||||
if (_documentRequest.XmlNode == null)
|
||||
throw new InvalidOperationException("There is no node.");
|
||||
|
||||
var path = _routingContext.ContentStore.GetNodeProperty(_documentRequest.XmlNode, "@path");
|
||||
|
||||
if (Access.IsProtected(_documentRequest.NodeId, path))
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Page is protected, check for access", () => tracePrefix);
|
||||
|
||||
var user = System.Web.Security.Membership.GetUser();
|
||||
|
||||
if (user == null || !Member.IsLoggedOn())
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Not logged in, redirect to login page", () => tracePrefix);
|
||||
var loginPageId = Access.GetLoginPage(path);
|
||||
if (loginPageId != _documentRequest.NodeId)
|
||||
_documentRequest.XmlNode = _routingContext.ContentStore.GetNodeById(loginPageId);
|
||||
}
|
||||
else if (!Access.HasAccces(_documentRequest.NodeId, user.ProviderUserKey))
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Current member has not access, redirect to error page", () => tracePrefix);
|
||||
var errorPageId = Access.GetErrorPage(path);
|
||||
if (errorPageId != _documentRequest.NodeId)
|
||||
_documentRequest.XmlNode = _routingContext.ContentStore.GetNodeById(errorPageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Current member has access", () => tracePrefix);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Page is not protected", () => tracePrefix);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a template for the current node.
|
||||
/// </summary>
|
||||
private void LookupTemplate()
|
||||
{
|
||||
const string tracePrefix = "LookupTemplate: ";
|
||||
|
||||
if (_documentRequest.XmlNode == null)
|
||||
throw new InvalidOperationException("There is no node.");
|
||||
|
||||
var templateAlias = _umbracoContext.HttpContext.Request.QueryString["altTemplate"];
|
||||
if (string.IsNullOrWhiteSpace(templateAlias))
|
||||
templateAlias = _umbracoContext.HttpContext.Request.Form["altTemplate"];
|
||||
|
||||
// fixme - we might want to support cookies?!? NO but provide a hook to change the template
|
||||
|
||||
if (!_documentRequest.HasTemplate || !string.IsNullOrWhiteSpace(templateAlias))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(templateAlias))
|
||||
{
|
||||
templateAlias = _routingContext.ContentStore.GetNodeProperty(_documentRequest.XmlNode, "@template");
|
||||
LogHelper.Debug<DocumentRequest>("{0}Look for template id={1}", () => tracePrefix, () => templateAlias);
|
||||
int templateId;
|
||||
if (!int.TryParse(templateAlias, out templateId))
|
||||
templateId = 0;
|
||||
_documentRequest.Template = templateId > 0 ? new Template(templateId) : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Look for template alias=\"{1}\" (altTemplate)", () => tracePrefix, () => templateAlias);
|
||||
_documentRequest.Template = Template.GetByAlias(templateAlias);
|
||||
}
|
||||
|
||||
if (!_documentRequest.HasTemplate)
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}No template was found", () => tracePrefix);
|
||||
|
||||
//TODO: I like the idea of this new setting, but lets get this in to the core at a later time, for now lets just get the basics working.
|
||||
//if (Settings.HandleMissingTemplateAs404)
|
||||
//{
|
||||
// this.Node = null;
|
||||
// LogHelper.Debug<DocumentRequest>("{0}Assume page not found (404)", tracePrefix);
|
||||
//}
|
||||
|
||||
// else we have no template
|
||||
// and there isn't much more we can do about it
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<DocumentRequest>("{0}Found", () => tracePrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Follows external redirection through <c>umbracoRedirect</c> document property.
|
||||
/// </summary>
|
||||
private void FollowRedirect()
|
||||
{
|
||||
if (_documentRequest.HasNode)
|
||||
{
|
||||
int redirectId;
|
||||
if (!int.TryParse(_routingContext.ContentStore.GetNodeProperty(_documentRequest.XmlNode, "umbracoRedirect"), out redirectId))
|
||||
redirectId = -1;
|
||||
string redirectUrl = "#";
|
||||
if (redirectId > 0)
|
||||
redirectUrl = _routingContext.NiceUrlProvider.GetNiceUrl(redirectId);
|
||||
if (redirectUrl != "#")
|
||||
_documentRequest.RedirectUrl = redirectUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,32 +13,31 @@ namespace Umbraco.Web.Routing
|
||||
/// <para>The alias is the full path to the document. There can be more than one alias, separated by commas.</para>
|
||||
/// </remarks>
|
||||
//[ResolutionWeight(50)]
|
||||
internal class LookupByAlias : IDocumentLookup
|
||||
internal class LookupByAlias : IDocumentLookup
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find and assign an Umbraco document to a <c>DocumentRequest</c>.
|
||||
/// </summary>
|
||||
/// <param name="docreq">The <c>DocumentRequest</c>.</param>
|
||||
/// <param name="docRequest">The <c>DocumentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TrySetDocument(DocumentRequest docreq)
|
||||
{
|
||||
XmlNode node = null;
|
||||
public bool TrySetDocument(DocumentRequest docRequest)
|
||||
{
|
||||
XmlNode node = null;
|
||||
|
||||
if (docreq.Uri.AbsolutePath != "/") // no alias if "/"
|
||||
{
|
||||
node = docreq.RoutingContext.ContentStore.GetNodeByUrlAlias(docreq.HasDomain ? docreq.Domain.RootNodeId : 0, docreq.Uri.AbsolutePath);
|
||||
if (node != null)
|
||||
{
|
||||
LogHelper.Debug<LookupByAlias>("Path \"{0}\" is an alias for id={1}", () => docreq.Uri.AbsolutePath, () => docreq.NodeId);
|
||||
docreq.XmlNode = node;
|
||||
}
|
||||
}
|
||||
if (docRequest.Uri.AbsolutePath != "/") // no alias if "/"
|
||||
{
|
||||
node = docRequest.RoutingContext.ContentStore.GetNodeByUrlAlias(docRequest.HasDomain ? docRequest.Domain.RootNodeId : 0, docRequest.Uri.AbsolutePath);
|
||||
if (node != null)
|
||||
{
|
||||
LogHelper.Debug<LookupByAlias>("Path \"{0}\" is an alias for id={1}", () => docRequest.Uri.AbsolutePath, () => docRequest.NodeId);
|
||||
docRequest.XmlNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
if (node == null)
|
||||
if (node == null)
|
||||
LogHelper.Debug<LookupByAlias>("Not an alias");
|
||||
|
||||
return node != null;
|
||||
}
|
||||
return node != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,21 +13,21 @@ namespace Umbraco.Web.Routing
|
||||
/// <para>Handles <c>/1234</c> where <c>1234</c> is the identified of a document.</para>
|
||||
/// </remarks>
|
||||
//[ResolutionWeight(20)]
|
||||
internal class LookupById : IDocumentLookup
|
||||
internal class LookupById : IDocumentLookup
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to find and assign an Umbraco document to a <c>DocumentRequest</c>.
|
||||
/// </summary>
|
||||
/// <param name="docreq">The <c>DocumentRequest</c>.</param>
|
||||
/// <param name="docRequest">The <c>DocumentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TrySetDocument(DocumentRequest docreq)
|
||||
public bool TrySetDocument(DocumentRequest docRequest)
|
||||
{
|
||||
XmlNode node = null;
|
||||
|
||||
int nodeId = -1;
|
||||
if (docreq.Uri.AbsolutePath != "/") // no id if "/"
|
||||
if (docRequest.Uri.AbsolutePath != "/") // no id if "/"
|
||||
{
|
||||
string noSlashPath = docreq.Uri.AbsolutePath.Substring(1);
|
||||
string noSlashPath = docRequest.Uri.AbsolutePath.Substring(1);
|
||||
|
||||
if (!Int32.TryParse(noSlashPath, out nodeId))
|
||||
nodeId = -1;
|
||||
@@ -35,11 +35,11 @@ namespace Umbraco.Web.Routing
|
||||
if (nodeId > 0)
|
||||
{
|
||||
LogHelper.Debug<LookupById>("Id={0}", () => nodeId);
|
||||
node = docreq.RoutingContext.ContentStore.GetNodeById(nodeId);
|
||||
node = docRequest.RoutingContext.ContentStore.GetNodeById(nodeId);
|
||||
if (node != null)
|
||||
{
|
||||
docreq.XmlNode = node;
|
||||
LogHelper.Debug<LookupById>("Found node with id={0}", () => docreq.NodeId);
|
||||
docRequest.XmlNode = node;
|
||||
LogHelper.Debug<LookupById>("Found node with id={0}", () => docRequest.NodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -12,21 +12,20 @@ namespace Umbraco.Web.Routing
|
||||
/// <para>Handles <c>/foo/bar</c> where <c>/foo/bar</c> is the nice url of a document.</para>
|
||||
/// </remarks>
|
||||
//[ResolutionWeight(10)]
|
||||
internal class LookupByNiceUrl : IDocumentLookup
|
||||
internal class LookupByNiceUrl : IDocumentLookup
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find and assign an Umbraco document to a <c>DocumentRequest</c>.
|
||||
/// </summary>
|
||||
/// <param name="docreq">The <c>DocumentRequest</c>.</param>
|
||||
/// <param name="docRequest">The <c>DocumentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public virtual bool TrySetDocument(DocumentRequest docreq)
|
||||
public virtual bool TrySetDocument(DocumentRequest docRequest)
|
||||
{
|
||||
string route;
|
||||
if (docreq.HasDomain)
|
||||
route = docreq.Domain.RootNodeId.ToString() + DomainHelper.PathRelativeToDomain(docreq.DomainUri, docreq.Uri.AbsolutePath);
|
||||
if (docRequest.HasDomain)
|
||||
route = docRequest.Domain.RootNodeId.ToString() + DomainHelper.PathRelativeToDomain(docRequest.DomainUri, docRequest.Uri.AbsolutePath);
|
||||
else
|
||||
route = docreq.Uri.AbsolutePath;
|
||||
route = docRequest.Uri.AbsolutePath;
|
||||
|
||||
//TODO: When this is not IIS 7, this does not work for the root '/' request since it comes through as default.aspx!!
|
||||
// this needs fixing.
|
||||
@@ -34,7 +33,7 @@ namespace Umbraco.Web.Routing
|
||||
//format the path, thsi needs fixing when pre-IIS7
|
||||
route = route.Replace(".aspx", "");
|
||||
|
||||
var node = LookupDocumentNode(docreq, route);
|
||||
var node = LookupDocumentNode(docRequest, route);
|
||||
return node != null;
|
||||
}
|
||||
|
||||
@@ -49,8 +48,8 @@ namespace Umbraco.Web.Routing
|
||||
LogHelper.Debug<LookupByNiceUrl>("Test route \"{0}\"", () => route);
|
||||
|
||||
//return '0' if in preview mode!
|
||||
var nodeId = !docreq.UmbracoContext.InPreviewMode
|
||||
? docreq.UmbracoContext.RoutesCache.GetNodeId(route)
|
||||
var nodeId = !docreq.RoutingContext.UmbracoContext.InPreviewMode
|
||||
? docreq.RoutingContext.UmbracoContext.RoutesCache.GetNodeId(route)
|
||||
: 0;
|
||||
|
||||
|
||||
@@ -65,7 +64,7 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
else
|
||||
{
|
||||
docreq.UmbracoContext.RoutesCache.ClearNode(nodeId);
|
||||
docreq.RoutingContext.UmbracoContext.RoutesCache.ClearNode(nodeId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +77,9 @@ namespace Umbraco.Web.Routing
|
||||
docreq.XmlNode = node;
|
||||
LogHelper.Debug<LookupByNiceUrl>("Query matches, id={0}", () => docreq.NodeId);
|
||||
|
||||
if (!docreq.UmbracoContext.InPreviewMode)
|
||||
if (!docreq.RoutingContext.UmbracoContext.InPreviewMode)
|
||||
{
|
||||
docreq.UmbracoContext.RoutesCache.Store(docreq.NodeId, route); // will not write if previewing
|
||||
docreq.RoutingContext.UmbracoContext.RoutesCache.Store(docreq.NodeId, route); // will not write if previewing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,20 +19,20 @@ namespace Umbraco.Web.Routing
|
||||
/// <summary>
|
||||
/// Tries to find and assign an Umbraco document to a <c>DocumentRequest</c>.
|
||||
/// </summary>
|
||||
/// <param name="docreq">The <c>DocumentRequest</c>.</param>
|
||||
/// <param name="docRequest">The <c>DocumentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
/// <remarks>If successful, also assigns the template.</remarks>
|
||||
public override bool TrySetDocument(DocumentRequest docreq)
|
||||
public override bool TrySetDocument(DocumentRequest docRequest)
|
||||
{
|
||||
XmlNode node = null;
|
||||
string path = docreq.Uri.AbsolutePath;
|
||||
string path = docRequest.Uri.AbsolutePath;
|
||||
|
||||
if (docreq.HasDomain)
|
||||
path = DomainHelper.PathRelativeToDomain(docreq.DomainUri, path);
|
||||
if (docRequest.HasDomain)
|
||||
path = DomainHelper.PathRelativeToDomain(docRequest.DomainUri, path);
|
||||
if (path != "/") // no template if "/"
|
||||
{
|
||||
var pos = docreq.Uri.AbsolutePath.LastIndexOf('/');
|
||||
var templateAlias = docreq.Uri.AbsolutePath.Substring(pos + 1);
|
||||
var pos = docRequest.Uri.AbsolutePath.LastIndexOf('/');
|
||||
var templateAlias = docRequest.Uri.AbsolutePath.Substring(pos + 1);
|
||||
path = path.Substring(0, pos);
|
||||
|
||||
var template = Template.GetByAlias(templateAlias);
|
||||
@@ -40,11 +40,11 @@ namespace Umbraco.Web.Routing
|
||||
{
|
||||
LogHelper.Debug<LookupByNiceUrlAndTemplate>("Valid template: \"{0}\"", () => templateAlias);
|
||||
|
||||
var route = docreq.HasDomain ? (docreq.Domain.RootNodeId.ToString() + path) : path;
|
||||
node = LookupDocumentNode(docreq, route);
|
||||
var route = docRequest.HasDomain ? (docRequest.Domain.RootNodeId.ToString() + path) : path;
|
||||
node = LookupDocumentNode(docRequest, route);
|
||||
|
||||
if (node != null)
|
||||
docreq.Template = template;
|
||||
docRequest.Template = template;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -15,37 +15,36 @@ namespace Umbraco.Web.Routing
|
||||
/// We keep it for backward compatility reasons.</para>
|
||||
/// </remarks>
|
||||
//[ResolutionWeight(40)]
|
||||
internal class LookupByProfile : LookupByNiceUrl, IDocumentLookup
|
||||
internal class LookupByProfile : LookupByNiceUrl
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find and assign an Umbraco document to a <c>DocumentRequest</c>.
|
||||
/// </summary>
|
||||
/// <param name="docreq">The <c>DocumentRequest</c>.</param>
|
||||
/// <param name="docRequest">The <c>DocumentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public override bool TrySetDocument(DocumentRequest docreq)
|
||||
public override bool TrySetDocument(DocumentRequest docRequest)
|
||||
{
|
||||
XmlNode node = null;
|
||||
|
||||
bool isProfile = false;
|
||||
var pos = docreq.Uri.AbsolutePath.LastIndexOf('/');
|
||||
var pos = docRequest.Uri.AbsolutePath.LastIndexOf('/');
|
||||
if (pos > 0)
|
||||
{
|
||||
var memberLogin = docreq.Uri.AbsolutePath.Substring(pos + 1);
|
||||
var path = docreq.Uri.AbsolutePath.Substring(0, pos);
|
||||
var memberLogin = docRequest.Uri.AbsolutePath.Substring(pos + 1);
|
||||
var path = docRequest.Uri.AbsolutePath.Substring(0, pos);
|
||||
|
||||
if (path == GlobalSettings.ProfileUrl)
|
||||
{
|
||||
isProfile = true;
|
||||
LogHelper.Debug<LookupByProfile>("Path \"{0}\" is the profile path", () => path);
|
||||
LogHelper.Debug<LookupByProfile>("Path \"{0}\" is the profile path", () => path);
|
||||
|
||||
var route = docreq.HasDomain ? (docreq.Domain.RootNodeId.ToString() + path) : path;
|
||||
node = LookupDocumentNode(docreq, route);
|
||||
var route = docRequest.HasDomain ? (docRequest.Domain.RootNodeId.ToString() + path) : path;
|
||||
node = LookupDocumentNode(docRequest, route);
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
//TODO: Should be handled by Context Items class manager (http://issues.umbraco.org/issue/U4-61)
|
||||
docreq.UmbracoContext.HttpContext.Items["umbMemberLogin"] = memberLogin;
|
||||
docRequest.RoutingContext.UmbracoContext.HttpContext.Items["umbMemberLogin"] = memberLogin;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -12,29 +12,28 @@ namespace Umbraco.Web.Routing
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RoutingContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext">The Umbraco context.</param>
|
||||
/// <param name="documentLookups">The document lookups resolver.</param>
|
||||
/// <param name="documentLastChanceLookup"> </param>
|
||||
/// <param name="contentStore">The content store.</param>
|
||||
/// <param name="niceUrlResolver">The nice urls resolver.</param>
|
||||
internal RoutingContext(
|
||||
//UmbracoContext umbracoContext,
|
||||
UmbracoContext umbracoContext,
|
||||
IEnumerable<IDocumentLookup> documentLookups,
|
||||
IDocumentLastChanceLookup documentLastChanceLookup,
|
||||
ContentStore contentStore,
|
||||
NiceUrlProvider niceUrlResolver)
|
||||
{
|
||||
//this.UmbracoContext = umbracoContext;
|
||||
this.UmbracoContext = umbracoContext;
|
||||
this.DocumentLookups = documentLookups;
|
||||
DocumentLastChanceLookup = documentLastChanceLookup;
|
||||
this.ContentStore = contentStore;
|
||||
this.NiceUrlProvider = niceUrlResolver;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Gets the Umbraco context.
|
||||
///// </summary>
|
||||
//public UmbracoContext UmbracoContext { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the Umbraco context.
|
||||
/// </summary>
|
||||
public UmbracoContext UmbracoContext { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the document lookups resolver.
|
||||
|
||||
@@ -254,6 +254,8 @@
|
||||
<Compile Include="Mvc\RenderViewPage.cs" />
|
||||
<Compile Include="Mvc\RouteDefinition.cs" />
|
||||
<Compile Include="RouteValueDictionaryExtensions.cs" />
|
||||
<Compile Include="Routing\DocumentLookupBase.cs" />
|
||||
<Compile Include="Routing\DocumentSearcher.cs" />
|
||||
<Compile Include="WebBootManager.cs" />
|
||||
<Compile Include="LegacyRequestInitializer.cs" />
|
||||
<Compile Include="Mvc\ControllerExtensions.cs" />
|
||||
|
||||
@@ -193,20 +193,20 @@ namespace Umbraco.Web
|
||||
/// <summary>
|
||||
/// Boolean value indicating whether the current request is a front-end umbraco request
|
||||
/// </summary>
|
||||
public bool IsFrontEndUmbracoRequest
|
||||
{
|
||||
get { return DocumentRequest != null; }
|
||||
}
|
||||
public bool IsFrontEndUmbracoRequest
|
||||
{
|
||||
get { return DocumentRequest != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the RoutingContext object
|
||||
/// </summary>
|
||||
internal RoutingContext RoutingContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the DocumentRequest object
|
||||
/// </summary>
|
||||
internal DocumentRequest DocumentRequest { get; set; }
|
||||
/// <summary>
|
||||
/// Gets/sets the DocumentRequest object
|
||||
/// </summary>
|
||||
internal DocumentRequest DocumentRequest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Exposes the HttpContext for the current request
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace Umbraco.Web
|
||||
var niceUrls = new NiceUrlProvider(contentStore, umbracoContext);
|
||||
//create the RoutingContext
|
||||
var routingContext = new RoutingContext(
|
||||
umbracoContext,
|
||||
DocumentLookupsResolver.Current.DocumentLookups,
|
||||
LastChanceLookupResolver.Current.LastChanceLookup,
|
||||
contentStore,
|
||||
@@ -83,8 +84,8 @@ namespace Umbraco.Web
|
||||
//Create a document request since we are rendering a document on the front-end
|
||||
|
||||
// create the new document request which will cleanup the uri once and for all
|
||||
var docreq = new DocumentRequest(uri, umbracoContext);
|
||||
//assign the routing context to the umbraco context
|
||||
var docreq = new DocumentRequest(uri, 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
|
||||
@@ -95,14 +96,21 @@ namespace Umbraco.Web
|
||||
// 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
|
||||
|
||||
docreq.LookupDomain();
|
||||
//create the searcher
|
||||
var searcher = new DocumentSearcher(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;
|
||||
docreq.LookupDocument();
|
||||
//find the document
|
||||
searcher.LookupDocument();
|
||||
//redirect if it has been flagged
|
||||
if (docreq.IsRedirect)
|
||||
httpContext.Response.Redirect(docreq.RedirectUrl, true);
|
||||
|
||||
//if no doc is found, send to our not found handler
|
||||
if (docreq.Is404)
|
||||
{
|
||||
httpContext.RemapHandler(new DocumentNotFoundHttpHandler());
|
||||
|
||||
Reference in New Issue
Block a user