Updated UmbracoModule to support the TransferRequest just like umbraMVCo does using query strings. Added more

unit tests for UmbracoModule, refactored the Umbraco.Web.Routing.Domains to not have static methods and created an
interface for it so that we can unit test it. Changed DocumentRequest stuff to internal. Finally got unit test working for the module
This commit is contained in:
shannon@ShandemVaio
2012-08-07 02:33:08 +06:00
parent fbf94bbf01
commit b68bcba85e
18 changed files with 371 additions and 113 deletions

View File

@@ -44,3 +44,4 @@ build/UmbracoCms.zip
src/Umbraco.Tests/config/applications.config
src/Umbraco.Tests/config/trees.config
src/Umbraco.Web.UI/web.config
src/Umbraco.Tests/config/404handlers.config

View File

@@ -405,6 +405,11 @@ namespace Umbraco.Core
return String.Equals(compare, compareTo, StringComparison.InvariantCultureIgnoreCase);
}
public static bool InvariantStartsWith(this string compare, string compareTo)
{
return compare.StartsWith(compareTo, StringComparison.InvariantCultureIgnoreCase);
}
public static bool InvariantContains(this string compare, string compareTo)
{
return compare.IndexOf(compareTo, StringComparison.OrdinalIgnoreCase) >= 0;

View File

@@ -10,7 +10,7 @@ using GlobalSettings = umbraco.GlobalSettings;
namespace Umbraco.Tests.BusinessLogic
{
[TestFixture]
[TestFixture, RequiresSTA]
public abstract class BaseTest
{
/// <summary>
@@ -47,6 +47,8 @@ namespace Umbraco.Tests.BusinessLogic
{
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)

View File

@@ -60,6 +60,9 @@ namespace Umbraco.Tests.TestHelpers
request.Stub(x => x.ApplicationPath).Return("/");
request.Stub(x => x.Cookies).Return(new HttpCookieCollection());
request.Stub(x => x.ServerVariables).Return(new NameValueCollection());
var queryStrings = HttpUtility.ParseQueryString(fullUrl.Query);
request.Stub(x => x.QueryString).Return(queryStrings);
request.Stub(x => x.Form).Return(new NameValueCollection());
//Cache
var cache = MockRepository.GenerateMock<HttpCachePolicyBase>();

View File

@@ -1,13 +1,28 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml;
using NUnit.Framework;
using SqlCE4Umbraco;
using Umbraco.Core;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.Media.ThumbnailProviders;
using Umbraco.Web.Routing;
using umbraco.BusinessLogic;
using umbraco.DataLayer;
using umbraco.IO;
using umbraco.cms.businesslogic.cache;
using umbraco.cms.businesslogic.language;
using umbraco.cms.businesslogic.template;
using umbraco.cms.businesslogic.web;
using GlobalSettings = umbraco.GlobalSettings;
namespace Umbraco.Tests
{
[TestFixture]
[TestFixture, RequiresSTA]
public class UmbracoModuleTests
{
private UmbracoModule _module;
@@ -24,6 +39,19 @@ namespace Umbraco.Tests
ConfigurationManager.AppSettings.Set("umbracoConfigurationStatus", Umbraco.Core.Configuration.GlobalSettings.CurrentVersion);
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();
//create the not found handlers config
using(var sw = File.CreateText(IOHelper.MapPath(SystemFiles.NotFoundhandlersConfig, false)))
{
sw.Write(@"<NotFoundHandlers>
<notFound assembly='umbraco' type='SearchForAlias' />
<notFound assembly='umbraco' type='SearchForTemplate'/>
<notFound assembly='umbraco' type='SearchForProfile'/>
<notFound assembly='umbraco' type='handle404'/>
</NotFoundHandlers>");
}
}
[TearDown]
@@ -38,6 +66,30 @@ namespace Umbraco.Tests
ConfigurationManager.AppSettings.Set("umbracoConfigurationStatus", "");
ConfigurationManager.AppSettings.Set("umbracoReservedPaths", "");
ConfigurationManager.AppSettings.Set("umbracoReservedUrls", "");
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();
}
}
[TestCase("/umbraco_client/Tree/treeIcons.css", false)]
@@ -78,5 +130,65 @@ namespace Umbraco.Tests
Assert.AreEqual(assert, result);
}
[TestCase("/default.aspx?path=/", true)]
[TestCase("/default.aspx?path=/home.aspx", true)]
[TestCase("/default.aspx?path=/home.aspx?altTemplate=blah", true)]
public void Process_Front_End_Document_Request(string url, bool assert)
{
var httpContextFactory = new FakeHttpContextFactory(url);
var httpContext = httpContextFactory.HttpContext;
var umbracoContext = new UmbracoContext(httpContext, ApplicationContext.Current, new DefaultRoutesCache(false));
StateHelper.HttpContext = httpContext;
//because of so much dependency on the db, we need to create som stuff here, i originally abstracted out stuff but
//was turning out to be quite a deep hole because ultimately we'd have to abstract the old 'Domain' and 'Language' classes
Domain.MakeNew("Test.com", 1000, Language.GetByCultureCode("en-US").id);
//need to create a template with id 1045
var template = Template.MakeNew("test", new User(0));
SetupUmbracoContextForTest(umbracoContext, template);
var result = _module.ProcessFrontEndDocumentRequest(
httpContext,
umbracoContext,
new IDocumentLookup[] {new LookupByNiceUrl()},
new DefaultLastChanceLookup());
Assert.AreEqual(assert, result);
}
private 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;
};
}
}
}

View File

@@ -11,7 +11,7 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Provides utilities to handle domains.
/// </summary>
public class Domains
internal class DomainHelper
{
/// <summary>
/// Represents an Umbraco domain and its normalized uri.
@@ -20,7 +20,7 @@ namespace Umbraco.Web.Routing
/// <para>In Umbraco it is valid to create domains with name such as <c>example.com</c>, <c>https://www.example.com</c>, <c>example.com/foo/</c>.</para>
/// <para>The normalized uri of a domain begins with a scheme and ends with no slash, eg <c>http://example.com/</c>, <c>https://www.example.com/</c>, <c>http://example.com/foo/</c>.</para>
/// </remarks>
public class DomainAndUri
internal class DomainAndUri
{
/// <summary>
/// The Umbraco domain.

View File

@@ -4,6 +4,7 @@ using System.Diagnostics;
using System.Reflection;
using System.Web;
using System.Xml;
using Umbraco.Core.Logging;
using umbraco.IO;
using umbraco.interfaces;
@@ -14,7 +15,6 @@ namespace Umbraco.Web.Routing
/// </summary>
internal class DefaultLastChanceLookup : IDocumentLastChanceLookup
{
static TraceSource _trace = new TraceSource("DefaultLastChanceLookup");
/// <summary>
/// Tries to find and assign an Umbraco document to a <c>DocumentRequest</c>.
@@ -33,7 +33,8 @@ namespace Umbraco.Web.Routing
XmlNode HandlePageNotFound(DocumentRequest docRequest)
{
HttpContext.Current.Trace.Write("NotFoundHandler", string.Format("Running for url='{0}'.", docRequest.Uri.AbsolutePath));
LogHelper.Debug<DefaultLastChanceLookup>("Running for url='{0}'.", () => docRequest.Uri.AbsolutePath);
XmlNode currentPage = null;
foreach (var handler in GetNotFoundHandlers())
@@ -45,8 +46,7 @@ namespace Umbraco.Web.Routing
// FIXME - could it be null?
HttpContext.Current.Trace.Write("NotFoundHandler",
string.Format("Handler '{0}' found node with id={1}.", handler.GetType().FullName, handler.redirectID));
LogHelper.Debug<DefaultLastChanceLookup>("Handler '{0}' found node with id={1}.", () => handler.GetType().FullName, () => handler.redirectID);
//// check for caching
//if (handler.CacheUrl)
@@ -77,7 +77,7 @@ namespace Umbraco.Web.Routing
// initialize handlers
// create the definition cache
HttpContext.Current.Trace.Write("NotFoundHandler", "Registering custom handlers.");
LogHelper.Debug<DefaultLastChanceLookup>("Registering custom handlers.");
_customHandlerTypes = new List<Type>();
@@ -101,17 +101,19 @@ namespace Umbraco.Web.Routing
ns = nsAttr.Value;
Type type = null;
HttpContext.Current.Trace.Write("NotFoundHandler",
string.Format("Registering '{0}.{1},{2}'.", ns, typeName, assemblyName));
LogHelper.Debug<DefaultLastChanceLookup>("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName);
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(IOHelper.MapPath(SystemDirectories.Bin + "/" + assemblyName + ".dll"));
type = assembly.GetType(ns + "." + typeName);
}
catch (Exception e)
{
HttpContext.Current.Trace.Warn("NotFoundHandler", "Error registering handler, ignoring.", e);
LogHelper.Error<DefaultLastChanceLookup>("Error registering handler, ignoring.", e);
}
if (type != null)
@@ -142,9 +144,7 @@ namespace Umbraco.Web.Routing
}
catch (Exception e)
{
HttpContext.Current.Trace.Warn("NotFoundHandler",
string.Format("Error instanciating handler {0}, ignoring.", type.FullName),
e);
LogHelper.Error<DefaultLastChanceLookup>(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e);
}
}

View File

@@ -22,9 +22,9 @@ namespace Umbraco.Web.Routing
/// represents a request for one specified Umbraco document to be rendered
/// by one specified template, using one particular culture.
/// </summary>
public class DocumentRequest
internal class DocumentRequest
{
public DocumentRequest(Uri uri, RoutingContext routingContext)
public DocumentRequest(Uri uri, RoutingContext routingContext)
{
this.Uri = uri;
RoutingContext = routingContext;
@@ -159,7 +159,7 @@ namespace Umbraco.Web.Routing
LogHelper.Debug<DocumentRequest>("{0}Uri=\"{1}\"", () => tracePrefix, () => this.Uri);
// try to find a domain matching the current request
var domainAndUri = Domains.DomainMatch(Domain.GetDomains(), RoutingContext.UmbracoContext.UmbracoUrl, false);
var domainAndUri = DomainHelper.DomainMatch(Domain.GetDomains(), RoutingContext.UmbracoContext.UmbracoUrl, false);
// handle domain
if (domainAndUri != null)

View File

@@ -3,7 +3,7 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Provides a method to try to find an assign an Umbraco document to a <c>DocumentRequest</c>.
/// </summary>
public interface IDocumentLookup
internal interface IDocumentLookup
{
/// <summary>
/// Tries to find and assign an Umbraco document to a <c>DocumentRequest</c>.

View File

@@ -24,7 +24,7 @@ namespace Umbraco.Web.Routing
{
string route;
if (docreq.HasDomain)
route = docreq.Domain.RootNodeId.ToString() + Domains.PathRelativeToDomain(docreq.DomainUri, docreq.Uri.AbsolutePath);
route = docreq.Domain.RootNodeId.ToString() + DomainHelper.PathRelativeToDomain(docreq.DomainUri, docreq.Uri.AbsolutePath);
else
route = docreq.Uri.AbsolutePath;

View File

@@ -28,7 +28,7 @@ namespace Umbraco.Web.Routing
string path = docreq.Uri.AbsolutePath;
if (docreq.HasDomain)
path = Domains.PathRelativeToDomain(docreq.DomainUri, path);
path = DomainHelper.PathRelativeToDomain(docreq.DomainUri, path);
if (path != "/") // no template if "/"
{
var pos = docreq.Uri.AbsolutePath.LastIndexOf('/');

View File

@@ -25,11 +25,11 @@ namespace Umbraco.Web.Routing
public NiceUrlProvider(ContentStore contentStore, UmbracoContext umbracoContext)
{
_umbracoContext = umbracoContext;
_contentStore = contentStore;
_contentStore = contentStore;
}
private readonly UmbracoContext _umbracoContext;
private readonly ContentStore _contentStore;
private readonly ContentStore _contentStore;
// note: this could be a parameter...
const string UrlNameProperty = "@urlName";
@@ -207,7 +207,7 @@ namespace Umbraco.Web.Routing
return null;
// apply filter on domains defined on that node
var domainAndUri = Domains.DomainMatch(Domain.GetDomainsById(nodeId), current, true);
var domainAndUri = DomainHelper.DomainMatch(Domain.GetDomainsById(nodeId), current, true);
return domainAndUri == null ? null : domainAndUri.Uri;
}
@@ -217,7 +217,7 @@ namespace Umbraco.Web.Routing
if (nodeId <= 0)
return new Uri[] { };
var domainAndUris = Domains.DomainMatches(Domain.GetDomainsById(nodeId), current);
var domainAndUris = DomainHelper.DomainMatches(Domain.GetDomainsById(nodeId), current);
return domainAndUris.Select(d => d.Uri);
}

View File

@@ -258,7 +258,7 @@
<Compile Include="Routing\LookupByProfile.cs" />
<Compile Include="Routing\NiceUrlProvider.cs" />
<Compile Include="PluginManagerExtensions.cs" />
<Compile Include="Routing\Domains.cs" />
<Compile Include="Routing\DefaultDomainHelper.cs" />
<Compile Include="Routing\DocumentLookupsResolver.cs" />
<Compile Include="Routing\DocumentRequest.cs" />
<Compile Include="Routing\IDocumentLookup.cs" />

View File

@@ -189,6 +189,14 @@ namespace Umbraco.Web
return GetXmlDelegate();
}
/// <summary>
/// Boolean value indicating whether the current request is a front-end umbraco request
/// </summary>
public bool IsFrontEndUmbracoRequest
{
get { return DocumentRequest != null; }
}
/// <summary>
/// Gets/sets the DocumentRequest object
/// </summary>

View File

@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Web.Routing;
@@ -22,6 +25,87 @@ namespace Umbraco.Web
public class UmbracoModule : IHttpModule
{
/// <summary>
/// Checks if the current request should process the request as a front-end umbraco request, if this is tru
/// it then creates the DocumentRequest object, finds the document, domain and culture and stores this back
/// to the UmbracoContext
/// </summary>
/// <param name="httpContext"></param>
/// <param name="umbracoContext"> </param>
/// <param name="docLookups"> </param>
/// <param name="lastChanceLookup"> </param>
internal bool ProcessFrontEndDocumentRequest(
HttpContextBase httpContext,
UmbracoContext umbracoContext,
IEnumerable<IDocumentLookup> docLookups,
IDocumentLastChanceLookup lastChanceLookup)
{
if (httpContext == null) throw new ArgumentNullException("httpContext");
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
if (httpContext.Request.Url.LocalPath.InvariantStartsWith("/default.aspx")
&& !string.IsNullOrWhiteSpace(httpContext.Request.QueryString["path"]))
{
//the path is the original path that the request came in on before we've rewritten it,
//this is required because TransferRequest does not maintain the httpcontext
var path = httpContext.Request.QueryString["path"];
var qry = httpContext.Request.QueryString["qry"];
Uri uri;
try
{
uri = UriUtility.ToFullUrl(path + qry, httpContext);
}
catch (Exception ex)
{
//if this fails then the path could not be parsed to a Uri which could be something malicious
LogHelper.Error<UmbracoModule>(string.Format("Could not parse the path {0} into a full Uri", path), ex);
return false;
}
//create request based objects (one per http request)...
//create a content store
var contentStore = new ContentStore(umbracoContext);
//create the nice urls
var niceUrls = new NiceUrlProvider(contentStore, umbracoContext);
//create the RoutingContext
var routingContext = new RoutingContext(
umbracoContext,
docLookups,
lastChanceLookup,
contentStore,
niceUrls);
// create the new document request which will cleanup the uri once and for all
var docreq = new DocumentRequest(uri, routingContext);
// initialize the DocumentRequest on the UmbracoContext (this is circular dependency but i think in this case is ok)
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
docreq.LookupDomain();
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = docreq.Culture;
docreq.LookupDocument();
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
if (docreq.Is404)
httpContext.Response.StatusCode = 404;
// it is up to default.aspx to figure out what to display in case
// there is no document (ugly 404 page?) or no template (blank page?)
return true;
}
return false;
}
/// <summary>
/// This is a performance tweak to check if this is a .css, .js or .ico file request since
@@ -32,7 +116,7 @@ namespace Umbraco.Web
/// <returns></returns>
internal bool IsClientSideRequest(Uri url)
{
var toIgnore = new[] {".js", ".css", ".ico"};
var toIgnore = new[] { ".js", ".css", ".ico" };
return toIgnore.Any(x => Path.GetExtension(url.LocalPath).InvariantEquals(x));
}
@@ -69,12 +153,9 @@ namespace Umbraco.Web
{
LogHelper.Debug<UmbracoModule>("Start processing request");
var uri = httpContext.Request.Url;
var lpath = uri.AbsolutePath.ToLower();
if (IsClientSideRequest(uri))
if (IsClientSideRequest(httpContext.Request.Url))
{
LogHelper.Debug<UmbracoModule>("End processing request, not transfering to handler, this is a client side file request {0}", () => uri);
LogHelper.Debug<UmbracoModule>("End processing request, not transfering to handler, this is a client side file request {0}", () => httpContext.Request.Url);
return;
}
@@ -83,8 +164,12 @@ namespace Umbraco.Web
httpContext.Response.AddHeader("X-Umbraco-Version", string.Format("{0}.{1}", GlobalSettings.VersionMajor, GlobalSettings.VersionMinor));
//create the legacy UmbracoContext
global::umbraco.presentation.UmbracoContext.Current
= new global::umbraco.presentation.UmbracoContext(httpContext);
global::umbraco.presentation.UmbracoContext.Current = new global::umbraco.presentation.UmbracoContext(httpContext);
//create the LegacyRequestInitializer
var legacyRequestInitializer = new LegacyRequestInitializer(httpContext.Request.Url, httpContext);
// legacy - initialize legacy stuff
legacyRequestInitializer.InitializeRequest();
//create the UmbracoContext singleton, one per request!!
var umbracoContext = new UmbracoContext(
@@ -93,66 +178,32 @@ namespace Umbraco.Web
RoutesCacheResolver.Current.RoutesCache);
UmbracoContext.Current = umbracoContext;
//create request based objects (one per http request)...
//create a content store
var contentStore = new ContentStore(umbracoContext);
//create the nice urls
var niceUrls = new NiceUrlProvider(contentStore, umbracoContext);
//create the RoutingContext
var routingContext = new RoutingContext(
umbracoContext,
//Does a check to see if this current request contains the information in order to process the
//request as a front-end request. If not, then its because the rewrite hasn't taken place yet.
//if we need to rewrite, then we'll cleanup the query strings and rewrite to the front end handler.
if (!ProcessFrontEndDocumentRequest(httpContext, umbracoContext,
DocumentLookupsResolver.Current.DocumentLookups,
LastChanceLookupResolver.Current.LastChanceLookup,
contentStore,
niceUrls);
// create the new document request which will cleanup the uri once and for all
var docreq = new DocumentRequest(uri, routingContext);
// initialize the DocumentRequest on the UmbracoContext (this is circular dependency but i think in this case is ok)
umbracoContext.DocumentRequest = docreq;
//create the LegacyRequestInitializer
var legacyRequestInitializer = new LegacyRequestInitializer(httpContext.Request.Url, httpContext);
// legacy - initialize legacy stuff
legacyRequestInitializer.InitializeRequest();
// 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
//do not continue if this request is not a front-end routable page
if (!EnsureUmbracoRoutablePage(uri, lpath, httpContext))
LastChanceLookupResolver.Current.LastChanceLookup))
{
LogHelper.Debug<UmbracoModule>("End processing request, not transfering to handler {0}", () => uri);
return;
}
var uri = httpContext.Request.Url;
var lpath = uri.AbsolutePath.ToLower();
// legacy - no idea what this is
LegacyCleanUmbPageFromQueryString(ref uri, ref lpath);
// legacy - no idea what this is
LegacyCleanUmbPageFromQueryString(ref uri, ref lpath);
//**THERE** we should create the doc request
// before, we're not sure we handling a doc request
docreq.LookupDomain();
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = docreq.Culture;
docreq.LookupDocument();
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
//do not continue if this request is not a front-end routable page
if (EnsureUmbracoRoutablePage(uri, lpath, httpContext))
{
RewriteToPath<Page>(HttpContext.Current, lpath, uri.Query);
//RewriteToPath<Page>(HttpContext.Current, "", docreq.Uri.Query);
}
else
{
LogHelper.Debug<UmbracoModule>("End processing request, not transfering to handler {0}", () => uri);
}
}
if (docreq.Is404)
httpContext.Response.StatusCode = 404;
TransferRequest("~/default.aspx" + docreq.Uri.Query, httpContext);
// it is up to default.aspx to figure out what to display in case
// there is no document (ugly 404 page?) or no template (blank page?)
}
/// <summary>
@@ -245,7 +296,11 @@ namespace Umbraco.Web
// fixme ?orgurl=... ?retry=...
}
TransferRequest(bootUrl, httpContext);
//RewriteToPath<Page>(HttpContext.Current, bootUrl, "", "");
//TransferRequest(bootUrl, httpContext);
httpContext.RewritePath(bootUrl);
return false;
}
@@ -291,37 +346,70 @@ namespace Umbraco.Web
return true;
}
// transfers the request using the fastest method available on the server
void TransferRequest(string path, HttpContextBase httpContext)
private static void RewriteToPath<THandler>(HttpContext context, string currentPath, string currentQuery)
where THandler : IHttpHandler
{
LogHelper.Debug<UmbracoModule>("Transfering to " + path);
var integrated = HttpRuntime.UsingIntegratedPipeline;
if ((context.CurrentHandler is THandler)) return;
// fixme - are we doing this properly?
// fixme - handle virtual directory?
// fixme - this does not work 'cos it resets the HttpContext
// so we should move the DocumentRequest stuff etc back to default.aspx?
// but, also, with TransferRequest, auth & co will run on the new (default.aspx) url,
// is that really what we want? I need to talk about it with others. @zpqrtbnk
var rewritePath = "~/default.aspx?path="
+ context.Server.UrlEncode(currentPath)
+ "&qry="
+ context.Server.UrlEncode(currentQuery);
// NOTE: SD: Need to look at how umbraMVCo does this. It is true that the TransferRequest initializes a new HttpContext,
// what we need to do is when we transfer to the handler we send a query string with the found page Id to be looked up
// after we have done our routing check. This however needs some though as we don't want to have to query for this
// page twice. Again, I'll check how umbraMVCo is doing it as I had though about that when i created it :)
if (currentPath.StartsWith(rewritePath, StringComparison.InvariantCultureIgnoreCase)) return;
integrated = false;
var isMvc = TypeHelper.IsTypeAssignableFrom<THandler>(typeof(MvcHandler));
// http://msmvps.com/blogs/luisabreu/archive/2007/10/09/are-you-using-the-new-transferrequest.aspx
// http://msdn.microsoft.com/en-us/library/aa344903.aspx
// http://forums.iis.net/t/1146511.aspx
LogHelper.Debug<UmbracoModule>("Transfering to " + rewritePath);
if (integrated)
httpContext.Server.TransferRequest(path);
if (HttpRuntime.UsingIntegratedPipeline)
{
context.Server.TransferRequest(rewritePath, true);
}
else
httpContext.RewritePath(path);
{
// Pre MVC 3
context.RewritePath(rewritePath, false);
if (isMvc)
{
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(context);
}
}
}
//// transfers the request using the fastest method available on the server
//void TransferRequest(string path, HttpContextBase httpContext)
//{
// LogHelper.Debug<UmbracoModule>("Transfering to " + path);
// var integrated = HttpRuntime.UsingIntegratedPipeline;
// // fixme - are we doing this properly?
// // fixme - handle virtual directory?
// // fixme - this does not work 'cos it resets the HttpContext
// // so we should move the DocumentRequest stuff etc back to default.aspx?
// // but, also, with TransferRequest, auth & co will run on the new (default.aspx) url,
// // is that really what we want? I need to talk about it with others. @zpqrtbnk
// // NOTE: SD: Need to look at how umbraMVCo does this. It is true that the TransferRequest initializes a new HttpContext,
// // what we need to do is when we transfer to the handler we send a query string with the found page Id to be looked up
// // after we have done our routing check. This however needs some though as we don't want to have to query for this
// // page twice. Again, I'll check how umbraMVCo is doing it as I had though about that when i created it :)
// integrated = false;
// // http://msmvps.com/blogs/luisabreu/archive/2007/10/09/are-you-using-the-new-transferrequest.aspx
// // http://msdn.microsoft.com/en-us/library/aa344903.aspx
// // http://forums.iis.net/t/1146511.aspx
// if (integrated)
// httpContext.Server.TransferRequest(path);
// else
// httpContext.RewritePath(path);
//}
#region Legacy
@@ -380,7 +468,7 @@ namespace Umbraco.Web
// used to be done in PostAuthorizeRequest but then it disabled OutputCaching due
// to rewriting happening too early in the chain (Alex Norcliffe 2010-02).
//app.PostResolveRequestCache += (sender, e) =>
//SD: changed to post map request handler so we can know what the handler actually is, this is a better fit for
//when we handle the routing
app.PostMapRequestHandler += (sender, e) =>

View File

@@ -157,5 +157,30 @@ namespace Umbraco.Web
}
#endregion
/// <summary>
/// Returns an faull url with the host, port, etc...
/// </summary>
/// <param name="absolutePath">An absolute path (i.e. starts with a '/' )</param>
/// <param name="httpContext"> </param>
/// <returns></returns>
/// <remarks>
/// Based on http://stackoverflow.com/questions/3681052/get-absolute-url-from-relative-path-refactored-method
/// </remarks>
internal static Uri ToFullUrl(string absolutePath, HttpContextBase httpContext)
{
if (httpContext == null) throw new ArgumentNullException("httpContext");
if (string.IsNullOrEmpty(absolutePath))
throw new ArgumentNullException("absolutePath");
if (!absolutePath.StartsWith("/"))
throw new FormatException("The absolutePath specified does not start with a '/'");
var url = httpContext.Request.Url;
var port = url.Port != 80 ? (":" + url.Port) : String.Empty;
return new Uri(string.Format("{0}://{1}{2}{3}", url.Scheme, url.Host, port, absolutePath));
}
}
}

View File

@@ -24,7 +24,8 @@ namespace umbraco.cms.businesslogic.web
static private Hashtable _checkedPages = new Hashtable();
static private XmlDocument _accessXmlContent;
//must be volatile for double check lock to work
static private volatile XmlDocument _accessXmlContent;
static private string _accessXmlSource;
private static void clearCheckPages()
@@ -54,6 +55,11 @@ namespace umbraco.cms.businesslogic.web
if (!System.IO.File.Exists(_accessXmlSource))
{
var file = new FileInfo(_accessXmlSource);
if (!Directory.Exists(file.DirectoryName))
{
Directory.CreateDirectory(file.Directory.FullName); //ensure the folder exists!
}
System.IO.FileStream f = System.IO.File.Open(_accessXmlSource, FileMode.Create);
System.IO.StreamWriter sw = new StreamWriter(f);
sw.WriteLine("<access/>");

View File

@@ -29,6 +29,14 @@ namespace umbraco.cms.businesslogic.web
get { return Application.SqlHelper; }
}
/// <summary>
/// Empty ctor used for unit tests to create a custom domain
/// </summary>
internal Domain()
{
}
public Domain(int Id)
{
initDomain(Id);