diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index 4d67cc78d6..2ead709124 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -5,6 +5,7 @@ using System.Web; using System.Web.Configuration; using System.Xml; using Umbraco.Core.IO; +using Umbraco.Core.Logging; namespace Umbraco.Core.Configuration { @@ -20,6 +21,35 @@ namespace Umbraco.Core.Configuration /// internal class GlobalSettings { + + private static HttpContextBase _customHttpContext; + + /// + /// Gets/sets the HttpContext object, this is generally used for unit testing. By default this will + /// use the HttpContext.Current + /// + internal static HttpContextBase HttpContext + { + get + { + if (_customHttpContext == null && System.Web.HttpContext.Current != null) + { + //return the current HttpContxt, do NOT store this in the _customHttpContext field + //as it will persist across reqeusts! + return new HttpContextWrapper(System.Web.HttpContext.Current); + } + + if (_customHttpContext == null && System.Web.HttpContext.Current == null) + { + //throw new NullReferenceException("The HttpContext property has not been set or the object execution is not running inside of an HttpContext"); + //NOTE: We should throw an exception here but the legacy code checks for null so we need to stick witht he legacy code for now. + return null; + } + return _customHttpContext; + } + set { _customHttpContext = value; } + } + #region Private static fields // CURRENT UMBRACO VERSION ID @@ -39,7 +69,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return ConfigurationManager.AppSettings["umbracoReservedUrls"]; return String.Empty; } @@ -53,7 +83,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return ConfigurationManager.AppSettings["umbracoReservedPaths"]; return String.Empty; } @@ -337,7 +367,7 @@ namespace Umbraco.Core.Configuration get { int versionCheckPeriod = 7; - if (HttpContext.Current != null) + if (HttpContext != null) { if (int.TryParse(ConfigurationManager.AppSettings["umbracoVersionCheckPeriod"], out versionCheckPeriod)) return versionCheckPeriod; @@ -355,7 +385,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return ConfigurationManager.AppSettings["umbracoUrlForbittenCharacters"]; return ""; } @@ -369,7 +399,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return ConfigurationManager.AppSettings["umbracoUrlSpaceCharacter"]; return ""; } @@ -407,7 +437,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return ConfigurationManager.AppSettings["umbracoDisableXsltExtensions"]; return ""; } @@ -421,7 +451,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return ConfigurationManager.AppSettings["umbracoEditXhtmlMode"]; return ""; } @@ -435,7 +465,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return ConfigurationManager.AppSettings["umbracoDefaultUILanguage"]; return ""; } @@ -449,7 +479,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return ConfigurationManager.AppSettings["umbracoProfileUrl"]; return ""; } @@ -465,7 +495,7 @@ namespace Umbraco.Core.Configuration { get { - if (HttpContext.Current != null) + if (HttpContext != null) return bool.Parse(ConfigurationManager.AppSettings["umbracoHideTopLevelNodeFromPath"]); return false; } @@ -584,7 +614,7 @@ namespace Umbraco.Core.Configuration { string license = "the open source license MIT. The umbraco UI is freeware licensed under the umbraco license."; - if (HttpContext.Current != null) + if (HttpContext != null) { var versionDoc = new XmlDocument(); var versionReader = new XmlTextReader(IOHelper.MapPath(SystemDirectories.Umbraco + "/version.xml")); @@ -624,31 +654,28 @@ namespace Umbraco.Core.Configuration internal static bool Test { get - { - try - { - HttpContext.Current.Response.Write("ContentXML :" + ContentXml + "\n"); - HttpContext.Current.Response.Write("DbDSN :" + DbDsn + "\n"); - HttpContext.Current.Response.Write("DebugMode :" + DebugMode + "\n"); - HttpContext.Current.Response.Write("DefaultUILanguage :" + DefaultUILanguage + "\n"); - HttpContext.Current.Response.Write("VersionCheckPeriod :" + VersionCheckPeriod + "\n"); - HttpContext.Current.Response.Write("DisableXsltExtensions :" + DisableXsltExtensions + "\n"); - HttpContext.Current.Response.Write("EditXhtmlMode :" + EditXhtmlMode + "\n"); - HttpContext.Current.Response.Write("HideTopLevelNodeFromPath :" + HideTopLevelNodeFromPath + "\n"); - HttpContext.Current.Response.Write("Path :" + Path + "\n"); - HttpContext.Current.Response.Write("ProfileUrl :" + ProfileUrl + "\n"); - HttpContext.Current.Response.Write("ReservedPaths :" + ReservedPaths + "\n"); - HttpContext.Current.Response.Write("ReservedUrls :" + ReservedUrls + "\n"); - HttpContext.Current.Response.Write("StorageDirectory :" + StorageDirectory + "\n"); - HttpContext.Current.Response.Write("TimeOutInMinutes :" + TimeOutInMinutes + "\n"); - HttpContext.Current.Response.Write("UrlForbittenCharacters :" + UrlForbittenCharacters + "\n"); - HttpContext.Current.Response.Write("UrlSpaceCharacter :" + UrlSpaceCharacter + "\n"); - HttpContext.Current.Response.Write("UseDirectoryUrls :" + UseDirectoryUrls + "\n"); - return true; - } - catch - { - } + { + if (HttpContext != null) + { + HttpContext.Response.Write("ContentXML :" + ContentXml + "\n"); + HttpContext.Response.Write("DbDSN :" + DbDsn + "\n"); + HttpContext.Response.Write("DebugMode :" + DebugMode + "\n"); + HttpContext.Response.Write("DefaultUILanguage :" + DefaultUILanguage + "\n"); + HttpContext.Response.Write("VersionCheckPeriod :" + VersionCheckPeriod + "\n"); + HttpContext.Response.Write("DisableXsltExtensions :" + DisableXsltExtensions + "\n"); + HttpContext.Response.Write("EditXhtmlMode :" + EditXhtmlMode + "\n"); + HttpContext.Response.Write("HideTopLevelNodeFromPath :" + HideTopLevelNodeFromPath + "\n"); + HttpContext.Response.Write("Path :" + Path + "\n"); + HttpContext.Response.Write("ProfileUrl :" + ProfileUrl + "\n"); + HttpContext.Response.Write("ReservedPaths :" + ReservedPaths + "\n"); + HttpContext.Response.Write("ReservedUrls :" + ReservedUrls + "\n"); + HttpContext.Response.Write("StorageDirectory :" + StorageDirectory + "\n"); + HttpContext.Response.Write("TimeOutInMinutes :" + TimeOutInMinutes + "\n"); + HttpContext.Response.Write("UrlForbittenCharacters :" + UrlForbittenCharacters + "\n"); + HttpContext.Response.Write("UrlSpaceCharacter :" + UrlSpaceCharacter + "\n"); + HttpContext.Response.Write("UseDirectoryUrls :" + UseDirectoryUrls + "\n"); + return true; + } return false; } } @@ -701,7 +728,7 @@ namespace Umbraco.Core.Configuration foreach (string st in _reservedList._list.Keys) res += st + ","; - HttpContext.Current.Trace.Write("umbracoGlobalsettings", "reserverd urls: '" + res + "'"); + LogHelper.Debug("reserverd urls: '" + res + "'"); // return true if url starts with an element of the reserved list return _reservedList.StartsWith(url.ToLower()); diff --git a/src/Umbraco.Tests/BusinessLogic/BaseTest.cs b/src/Umbraco.Tests/BusinessLogic/BaseTest.cs index e97198a898..0fe0cb4059 100644 --- a/src/Umbraco.Tests/BusinessLogic/BaseTest.cs +++ b/src/Umbraco.Tests/BusinessLogic/BaseTest.cs @@ -20,6 +20,7 @@ namespace Umbraco.Tests.BusinessLogic public void Dispose() { ClearDatabase(); + ConfigurationManager.AppSettings.Set("umbracoDbDSN", ""); } /// diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index f836a5788e..4762eef385 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -79,6 +79,7 @@ + diff --git a/src/Umbraco.Tests/UmbracoModuleTests.cs b/src/Umbraco.Tests/UmbracoModuleTests.cs new file mode 100644 index 0000000000..27eb37ec71 --- /dev/null +++ b/src/Umbraco.Tests/UmbracoModuleTests.cs @@ -0,0 +1,67 @@ +using System.Configuration; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Tests.TestHelpers; +using Umbraco.Web; + +namespace Umbraco.Tests +{ + [TestFixture] + public class UmbracoModuleTests + { + private UmbracoModule _module; + + [SetUp] + public void Initialize() + { + TestHelper.SetupLog4NetForTests(); + ApplicationContext.Current = new ApplicationContext() + { + IsReady = true + }; + _module = new UmbracoModule(); + 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"); + } + + [TearDown] + public void TearDown() + { + _module.Dispose(); + //reset the context on global settings + Umbraco.Core.Configuration.GlobalSettings.HttpContext = null; + //reset the app context + ApplicationContext.Current = null; + //reset the app config + ConfigurationManager.AppSettings.Set("umbracoConfigurationStatus", ""); + ConfigurationManager.AppSettings.Set("umbracoReservedPaths", ""); + ConfigurationManager.AppSettings.Set("umbracoReservedUrls", ""); + } + + [TestCase("/umbraco_client/Tree/treeIcons.css", false)] + [TestCase("/umbraco_client/Tree/Themes/umbraco/style.css?cdv=37", false)] + [TestCase("/umbraco_client/scrollingmenu/style.css?cdv=37", false)] + [TestCase("/umbraco/umbraco.aspx", false)] + [TestCase("/umbraco/editContent.aspx", false)] + [TestCase("/install/default.aspx", false)] + [TestCase("/install/test.aspx", false)] + [TestCase("/base/somebasehandler", false)] + [TestCase("/", true)] + [TestCase("/home.aspx", true)] + public void Ensure_Request_Routable(string url, bool assert) + { + var httpContextFactory = new FakeHttpContextFactory(url); + var httpContext = httpContextFactory.HttpContext; + //set the context on global settings + Umbraco.Core.Configuration.GlobalSettings.HttpContext = httpContext; + var uri = httpContext.Request.Url; + var lpath = uri.AbsolutePath.ToLower(); + + var result = _module.EnsureRequestRoutable(uri, lpath, httpContext); + + Assert.AreEqual(assert, result); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/web.Template.ShandemVaio.Debug.config b/src/Umbraco.Web.UI/web.Template.ShandemVaio.Debug.config index ca20bd8113..8b87c0b713 100644 --- a/src/Umbraco.Web.UI/web.Template.ShandemVaio.Debug.config +++ b/src/Umbraco.Web.UI/web.Template.ShandemVaio.Debug.config @@ -27,6 +27,7 @@ + - - + diff --git a/src/Umbraco.Web/Routing/DocumentRequest.cs b/src/Umbraco.Web/Routing/DocumentRequest.cs index 3f54cf5866..6806861d96 100644 --- a/src/Umbraco.Web/Routing/DocumentRequest.cs +++ b/src/Umbraco.Web/Routing/DocumentRequest.cs @@ -15,12 +15,15 @@ using umbraco.cms.businesslogic.member; using umbraco.cms.businesslogic.language; namespace Umbraco.Web.Routing { - // represents a request for one specified Umbraco document to be rendered - // by one specified template, using one particular culture. - // + + + + /// + /// represents a request for one specified Umbraco document to be rendered + /// by one specified template, using one particular culture. + /// public class DocumentRequest { - public DocumentRequest(Uri uri, RoutingContext routingContext) { this.Uri = uri; diff --git a/src/Umbraco.Web/UmbracoApplication.cs.orig b/src/Umbraco.Web/UmbracoApplication.cs.orig deleted file mode 100644 index 402929c4c2..0000000000 --- a/src/Umbraco.Web/UmbracoApplication.cs.orig +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Web.Mvc; -using Umbraco.Core; -using Umbraco.Web.Routing; -using umbraco.businesslogic; - -namespace Umbraco.Web -{ - /// - /// The Umbraco global.asax class - /// - public class UmbracoApplication : System.Web.HttpApplication - { - public static event EventHandler ApplicationStarting; - - public static event EventHandler ApplicationStarted; - - /// - /// Initializes the Umbraco application - /// - /// - /// - protected void Application_Start(object sender, EventArgs e) - { - using (DisposableTimer.TraceDuration( - "Umbraco application starting", - "Umbraco application startup complete")) - { - // Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK] - ClientDependency.Core.CompositeFiles.Providers.XmlFileMapper.FileMapVirtualFolder = "~/App_Data/TEMP/ClientDependency"; - ClientDependency.Core.CompositeFiles.Providers.BaseCompositeFileProcessingProvider.UrlTypeDefault = ClientDependency.Core.CompositeFiles.Providers.CompositeUrlType.Base64QueryStrings; - - //create the ApplicationContext - ApplicationContext.Current = new ApplicationContext() - { - IsReady = true // fixme - }; - - //find and initialize the application startup handlers - ApplicationStartupHandler.RegisterHandlers(); - - OnApplicationStarting(sender, e); - - //all resolvers are now frozen and cannot be modified - Umbraco.Core.Resolving.Resolution.Freeze(); - - OnApplicationStarted(sender, e); - } - } - - /// - /// Developers can override this method to modify objects on startup - /// - /// - /// - protected virtual void OnApplicationStarting(object sender, EventArgs e) - { - if (ApplicationStarting != null) - ApplicationStarting(sender, e); - } - - /// - /// Developers can override this method to do anything they need to do once the application startup routine is completed. - /// - /// - /// - protected virtual void OnApplicationStarted(object sender, EventArgs e) - { - if (ApplicationStarted != null) - ApplicationStarted(sender, e); - } - - protected virtual void Application_Error(object sender, EventArgs e) - { - - } - - protected virtual void Application_End(object sender, EventArgs e) - { - - } - } -} diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 428f6ecd2e..b6b7f4e09a 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -22,6 +22,31 @@ namespace Umbraco.Web public class UmbracoModule : IHttpModule { + /// + /// Checks the current request and ensures that it is routable based on the structure of the request and URI + /// + /// + /// + /// + /// + internal bool EnsureRequestRoutable(Uri uri, string lpath, HttpContextBase httpContext) + { + // ensure this is a document request + if (!EnsureDocumentRequest(httpContext, uri, lpath)) + return false; + // ensure Umbraco is ready to serve documents + if (!EnsureIsReady(httpContext, uri)) + return false; + // ensure Umbraco is properly configured to serve documents + if (!EnsureIsConfigured(httpContext, uri)) + return false; + // ensure that its not a base rest handler + if ((UmbracoSettings.EnableBaseRestHandler) && !EnsureNotBaseRestHandler(lpath)) + return false; + + return true; + } + /// /// Entry point for a request /// @@ -30,14 +55,17 @@ namespace Umbraco.Web { LogHelper.Debug("Start processing request"); - //TODO: We need to ensure the below only executes for real requests (i.e. not css, favicon, etc...) - // I'm pretty sure we need to bind to the PostHandlerAssigned (or whatever event) and follow the same - // practices that is in umbraMVCo - var uri = httpContext.Request.Url; var lpath = uri.AbsolutePath.ToLower(); + //do not continue if this request is not routablehttpContextFactory + if (!EnsureRequestRoutable(uri, lpath, httpContext)) + { + LogHelper.Debug("End processing request, not transfering to handler"); + return; + } + // add Umbraco's signature header if (!UmbracoSettings.RemoveUmbracoVersionHeader) httpContext.Response.AddHeader("X-Umbraco-Version", string.Format("{0}.{1}", GlobalSettings.VersionMajor, GlobalSettings.VersionMinor)); @@ -86,27 +114,20 @@ 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 - - var ok = true; - - // ensure this is a document request - ok = ok && EnsureDocumentRequest(httpContext, uri, lpath); - // ensure Umbraco is ready to serve documents - ok = ok && EnsureIsReady(httpContext, uri); - // ensure Umbraco is properly configured to serve documents - ok = ok && EnsureIsConfigured(httpContext, uri); - ok = ok && (!UmbracoSettings.EnableBaseRestHandler || EnsureNotBaseRestHandler(httpContext, lpath)); - ok = ok && (EnsureNotBaseRestHandler(httpContext, lpath)); - - if (!ok) - { - LogHelper.Debug("End processing request, not transfering to handler"); - return; - } + // legacy - no idea what this is LegacyCleanUmbPageFromQueryString(ref uri, ref lpath); + + //TODO: Before this happens, we need to : + // * move all of this logic into a custom IHttpHandler (maybe) + // ** This is because of TransferRequest actual makes an internal request and the HttpContext is reset + // which means that all HttpContext.Items setting need to occur after + // * need to figure out if we can execute default.aspx as a handler from our IHttpHandler instead of rewriting to it + // * same goes for MVC + // * perhaps its even possible to do all of this without any Rewriting or TransferRequest! + //**THERE** we should create the doc request // before, we're not sure we handling a doc request docreq.LookupDomain(); @@ -120,7 +141,7 @@ namespace Umbraco.Web if (docreq.Is404) httpContext.Response.StatusCode = 404; - TransferRequest("~/default.aspx" + docreq.Uri.Query); + 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?) @@ -216,7 +237,7 @@ namespace Umbraco.Web // fixme ?orgurl=... ?retry=... } - TransferRequest(bootUrl); + TransferRequest(bootUrl, httpContext); return false; } @@ -242,7 +263,7 @@ namespace Umbraco.Web // checks if the current request is a /base REST handler request // returns false if it is, otherwise true - bool EnsureNotBaseRestHandler(HttpContextBase httpContext, string lpath) + bool EnsureNotBaseRestHandler(string lpath) { // the /base REST handler still lives in umbraco.dll and has // not been refactored at the moment. it still is a module, @@ -263,7 +284,7 @@ namespace Umbraco.Web } // transfers the request using the fastest method available on the server - void TransferRequest(string path) + void TransferRequest(string path, HttpContextBase httpContext) { LogHelper.Debug("Transfering to " + path); @@ -288,9 +309,9 @@ namespace Umbraco.Web // http://forums.iis.net/t/1146511.aspx if (integrated) - HttpContext.Current.Server.TransferRequest(path); + httpContext.Server.TransferRequest(path); else - HttpContext.Current.RewritePath(path); + httpContext.RewritePath(path); } @@ -350,7 +371,11 @@ 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) => + //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) => { var httpContext = ((HttpApplication)sender).Context; ProcessRequest(new HttpContextWrapper(httpContext)); diff --git a/src/umbraco.businesslogic/StateHelper.cs b/src/umbraco.businesslogic/StateHelper.cs index 3884549f3f..607a729634 100644 --- a/src/umbraco.businesslogic/StateHelper.cs +++ b/src/umbraco.businesslogic/StateHelper.cs @@ -11,7 +11,7 @@ namespace umbraco.BusinessLogic public class StateHelper { - private static HttpContextBase _httpContext; + private static HttpContextBase _customHttpContext; /// /// Gets/sets the HttpContext object, this is generally used for unit testing. By default this will @@ -21,17 +21,20 @@ namespace umbraco.BusinessLogic { get { - if (_httpContext == null && System.Web.HttpContext.Current != null) + if (_customHttpContext == null && System.Web.HttpContext.Current != null) { - _httpContext = new HttpContextWrapper(System.Web.HttpContext.Current); + //return the current HttpContxt, do NOT store this in the _customHttpContext field + //as it will persist across reqeusts! + return new HttpContextWrapper(System.Web.HttpContext.Current); } - else if (_httpContext == null && System.Web.HttpContext.Current == null) + + if (_customHttpContext == null && System.Web.HttpContext.Current == null) { throw new NullReferenceException("The HttpContext property has not been set or the object execution is not running inside of an HttpContext"); } - return _httpContext; + return _customHttpContext; } - set { _httpContext = value; } + set { _customHttpContext = value; } } #region Session Helpers diff --git a/src/umbraco.cms/Actions/Action.cs b/src/umbraco.cms/Actions/Action.cs index d7d290b66f..b86379ce71 100644 --- a/src/umbraco.cms/Actions/Action.cs +++ b/src/umbraco.cms/Actions/Action.cs @@ -148,7 +148,9 @@ namespace umbraco.BusinessLogic.Actions /// public static List GetJavaScriptFileReferences() { - return ActionsResolver.Current.Actions.Select(x => x.JsSource).ToList(); + return ActionsResolver.Current.Actions + .Where(x => !string.IsNullOrWhiteSpace(x.JsSource)) + .Select(x => x.JsSource).ToList(); //return ActionJsReference; }