Moves UrlExtensions methods to new service and reduce the huge amount of allocated strings during routing

This commit is contained in:
Shannon
2021-01-08 17:21:35 +11:00
parent e1e3200313
commit 0ce90cf359
29 changed files with 473 additions and 521 deletions

View File

@@ -24,6 +24,7 @@ using Umbraco.Core.Mail;
using Umbraco.Core.Manifest;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Routing;
using Umbraco.Core.Runtime;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
@@ -146,6 +147,7 @@ namespace Umbraco.Core.DependencyInjection
this.AddNotificationHandler<UmbracoApplicationStarting, EssentialDirectoryCreator>();
Services.AddSingleton<ManifestWatcher>();
Services.AddSingleton<UmbracoRequestPaths>();
this.AddNotificationHandler<UmbracoApplicationStarting, AppPluginsManifestWatcherNotificationHandler>();
Services.AddUnique<InstallStatusTracker>();

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Options;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
namespace Umbraco.Core.Routing
{
/// <summary>
/// Utility for checking paths
/// </summary>
public class UmbracoRequestPaths
{
private readonly string _backOfficePath;
private readonly string _mvcArea;
private readonly string _backOfficeMvcPath;
private readonly string _previewMvcPath;
private readonly string _installPath;
private readonly string _appPath;
private readonly List<string> _aspLegacyJsExt = new List<string> { ".asmx/", ".aspx/", ".ashx/", ".axd/", ".svc/" };
private readonly List<string> _aspLegacyExt = new List<string> { ".asmx", ".aspx", ".ashx", ".axd", ".svc" };
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoRequestPaths"/> class.
/// </summary>
public UmbracoRequestPaths(IOptions<GlobalSettings> globalSettings, IHostingEnvironment hostingEnvironment)
{
var applicationPath = hostingEnvironment.ApplicationVirtualPath;
_appPath = applicationPath.TrimStart('/');
_backOfficePath = globalSettings.Value.GetBackOfficePath(hostingEnvironment)
.EnsureStartsWith('/').TrimStart(_appPath.EnsureStartsWith('/')).EnsureStartsWith('/');
_mvcArea = globalSettings.Value.GetUmbracoMvcArea(hostingEnvironment);
_backOfficeMvcPath = "/" + _mvcArea + "/BackOffice/";
_previewMvcPath = "/" + _mvcArea + "/Preview/";
_installPath = hostingEnvironment.ToAbsolute(Constants.SystemDirectories.Install);
}
/// <summary>
/// Checks if the current uri is a back office request
/// </summary>
/// <remarks>
/// There are some special routes we need to check to properly determine this:
///
/// If any route has an extension in the path like .aspx = back office
///
/// These are def back office:
/// /Umbraco/BackOffice = back office
/// /Umbraco/Preview = back office
/// If it's not any of the above, and there's no extension then we cannot determine if it's back office or front-end
/// so we can only assume that it is not back office. This will occur if people use an UmbracoApiController for the backoffice
/// but do not inherit from UmbracoAuthorizedApiController and do not use [IsBackOffice] attribute.
///
/// These are def front-end:
/// /Umbraco/Surface = front-end
/// /Umbraco/Api = front-end
/// But if we've got this far we'll just have to assume it's front-end anyways.
///
/// </remarks>
public bool IsBackOfficeRequest(string absPath)
{
var fullUrlPath = absPath.TrimStart('/');
var urlPath = fullUrlPath.TrimStart(_appPath).EnsureStartsWith('/');
// check if this is in the umbraco back office
var isUmbracoPath = urlPath.InvariantStartsWith(_backOfficePath);
// if not, then def not back office
if (isUmbracoPath == false)
{
return false;
}
// if its the normal /umbraco path
if (urlPath.InvariantEquals("/" + _mvcArea)
|| urlPath.InvariantEquals("/" + _mvcArea + "/"))
{
return true;
}
// check for a file extension
var extension = Path.GetExtension(absPath);
// has an extension, def back office
if (extension.IsNullOrWhiteSpace() == false)
{
return true;
}
// check for special case asp.net calls like:
// /umbraco/webservices/legacyAjaxCalls.asmx/js which will return a null file extension but are still considered requests with an extension
if (_aspLegacyJsExt.Any(x => urlPath.InvariantContains(x)))
{
return true;
}
// check for special back office paths
if (urlPath.InvariantStartsWith(_backOfficeMvcPath)
|| urlPath.InvariantStartsWith(_previewMvcPath))
{
return true;
}
// check for special front-end paths
// TODO: These should be constants - will need to update when we do front-end routing
if (urlPath.InvariantStartsWith("/" + _mvcArea + "/Surface/")
|| urlPath.InvariantStartsWith("/" + _mvcArea + "/Api/"))
{
return false;
}
// if its none of the above, we will have to try to detect if it's a PluginController route, we can detect this by
// checking how many parts the route has, for example, all PluginController routes will be routed like
// Umbraco/MYPLUGINAREA/MYCONTROLLERNAME/{action}/{id}
// so if the path contains at a minimum 3 parts: Umbraco + MYPLUGINAREA + MYCONTROLLERNAME then we will have to assume it is a
// plugin controller for the front-end.
if (urlPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Length >= 3)
{
return false;
}
// if its anything else we can assume it's back office
return true;
}
/// <summary>
/// Checks if the current uri is an install request
/// </summary>
public bool IsInstallerRequest(string absPath) => absPath.InvariantStartsWith(_installPath);
/// <summary>
/// Rudimentary check to see if it's not a server side request
/// </summary>
public bool IsClientSideRequest(string absPath)
{
var ext = Path.GetExtension(absPath);
if (ext.IsNullOrWhiteSpace())
{
return false;
}
return _aspLegacyExt.Any(ext.InvariantEquals) == false;
}
}
}

View File

@@ -13,151 +13,6 @@ namespace Umbraco.Core
/// </summary>
public static class UriExtensions
{
/// <summary>
/// Checks if the current uri is a back office request
/// </summary>
/// <param name="url"></param>
/// <param name="globalSettings"></param>
/// <param name="hostingEnvironment"></param>
/// <returns></returns>
/// <remarks>
/// There are some special routes we need to check to properly determine this:
///
/// If any route has an extension in the path like .aspx = back office
///
/// These are def back office:
/// /Umbraco/BackOffice = back office
/// /Umbraco/Preview = back office
/// If it's not any of the above, and there's no extension then we cannot determine if it's back office or front-end
/// so we can only assume that it is not back office. This will occur if people use an UmbracoApiController for the backoffice
/// but do not inherit from UmbracoAuthorizedApiController and do not use [IsBackOffice] attribute.
///
/// These are def front-end:
/// /Umbraco/Surface = front-end
/// /Umbraco/Api = front-end
/// But if we've got this far we'll just have to assume it's front-end anyways.
///
/// </remarks>
public static bool IsBackOfficeRequest(this Uri url, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment)
{
var applicationPath = hostingEnvironment.ApplicationVirtualPath;
var fullUrlPath = url.AbsolutePath.TrimStart(new[] {'/'});
var appPath = applicationPath.TrimStart(new[] {'/'});
var urlPath = fullUrlPath.TrimStart(appPath).EnsureStartsWith('/');
//check if this is in the umbraco back office
var backOfficePath = globalSettings.GetBackOfficePath(hostingEnvironment);
var isUmbracoPath = urlPath.InvariantStartsWith(backOfficePath.EnsureStartsWith('/').TrimStart(appPath.EnsureStartsWith('/')).EnsureStartsWith('/'));
//if not, then def not back office
if (isUmbracoPath == false) return false;
var mvcArea = globalSettings.GetUmbracoMvcArea(hostingEnvironment);
//if its the normal /umbraco path
if (urlPath.InvariantEquals("/" + mvcArea)
|| urlPath.InvariantEquals("/" + mvcArea + "/"))
{
return true;
}
//check for a file extension
var extension = Path.GetExtension(url.LocalPath);
//has an extension, def back office
if (extension.IsNullOrWhiteSpace() == false) return true;
//check for special case asp.net calls like:
// /umbraco/webservices/legacyAjaxCalls.asmx/js which will return a null file extension but are still considered requests with an extension
if (urlPath.InvariantContains(".asmx/")
|| urlPath.InvariantContains(".aspx/")
|| urlPath.InvariantContains(".ashx/")
|| urlPath.InvariantContains(".axd/")
|| urlPath.InvariantContains(".svc/"))
{
return true;
}
//check for special back office paths
if (urlPath.InvariantStartsWith("/" + mvcArea + "/BackOffice/")
|| urlPath.InvariantStartsWith("/" + mvcArea + "/Preview/"))
{
return true;
}
//check for special front-end paths
// TODO: These should be constants - will need to update when we do front-end routing
if (urlPath.InvariantStartsWith("/" + mvcArea + "/Surface/")
|| urlPath.InvariantStartsWith("/" + mvcArea + "/Api/"))
{
return false;
}
//if its none of the above, we will have to try to detect if it's a PluginController route, we can detect this by
// checking how many parts the route has, for example, all PluginController routes will be routed like
// Umbraco/MYPLUGINAREA/MYCONTROLLERNAME/{action}/{id}
// so if the path contains at a minimum 3 parts: Umbraco + MYPLUGINAREA + MYCONTROLLERNAME then we will have to assume it is a
// plugin controller for the front-end.
if (urlPath.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries).Length >= 3)
{
return false;
}
// if its anything else we can assume it's back office
return true;
}
/// <summary>
/// Checks if the current uri is an install request
/// </summary>
public static bool IsInstallerRequest(this Uri url, IHostingEnvironment hostingEnvironment)
{
var authority = url.GetLeftPart(UriPartial.Authority);
var afterAuthority = url.GetLeftPart(UriPartial.Query)
.TrimStart(authority)
.TrimStart("/");
// check if this is in the umbraco back office
return afterAuthority.InvariantStartsWith(hostingEnvironment.ToAbsolute(Constants.SystemDirectories.Install).TrimStart("/"));
}
/// <summary>
/// Checks if the uri is a request for the default back office page
/// </summary>
public static bool IsDefaultBackOfficeRequest(this Uri url, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment)
{
var backOfficePath = globalSettings.GetBackOfficePath(hostingEnvironment);
if (url.AbsolutePath.InvariantEquals(backOfficePath.TrimEnd("/"))
|| url.AbsolutePath.InvariantEquals(backOfficePath.EnsureEndsWith('/'))
|| url.AbsolutePath.InvariantEquals(backOfficePath.EnsureEndsWith('/') + "Default")
|| url.AbsolutePath.InvariantEquals(backOfficePath.EnsureEndsWith('/') + "Default/"))
{
return true;
}
return false;
}
/// <summary>
/// This is a performance tweak to check if this not an ASP.Net server file
/// .Net will pass these requests through to the module when in integrated mode.
/// We want to ignore all of these requests immediately.
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static bool IsClientSideRequest(this Uri url)
{
try
{
var ext = Path.GetExtension(url.LocalPath);
if (ext.IsNullOrWhiteSpace()) return false;
var toInclude = new[] {".aspx", ".ashx", ".asmx", ".axd", ".svc"};
return toInclude.Any(ext.InvariantEquals) == false;
}
catch (ArgumentException)
{
StaticApplicationLogging.Logger.LogDebug("Failed to determine if request was client side (invalid chars in path \"{Path}\"?)", url.LocalPath);
return false;
}
}
/// <summary>
/// Rewrites the path of uri.
/// </summary>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
@@ -11,6 +11,7 @@ using Umbraco.ModelsBuilder.Embedded.Building;
using Umbraco.Web.Cache;
using Umbraco.Core.Configuration.Models;
using Microsoft.Extensions.Options;
using Umbraco.Extensions;
namespace Umbraco.ModelsBuilder.Embedded
{
@@ -115,12 +116,16 @@ namespace Umbraco.ModelsBuilder.Embedded
public void AppEndRequest(HttpContext context)
{
var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute);
if (requestUri.IsClientSideRequest())
if (context.Request.IsClientSideRequest())
{
return;
}
if (!IsEnabled)
{
return;
}
if (!IsEnabled) return;
GenerateModelsIfRequested();
}
}

View File

@@ -6,6 +6,7 @@ using Microsoft.Extensions.Options;
using Moq;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Routing;
using Umbraco.Core.Security;
using Umbraco.Tests.Common;
using Umbraco.Web;
@@ -63,7 +64,7 @@ namespace Umbraco.Tests.UnitTests.TestHelpers.Objects
snapshotService.Object,
new TestVariationContextAccessor(),
new TestDefaultCultureAccessor(),
Options.Create<GlobalSettings>(globalSettings),
new UmbracoRequestPaths(Options.Create(globalSettings), hostingEnvironment),
hostingEnvironment,
new UriUtility(hostingEnvironment),
new AspNetCoreCookieManager(httpContextAccessor),

View File

@@ -1,4 +1,4 @@
// Copyright (c) Umbraco.
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
@@ -25,49 +25,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Extensions
private IWebHostEnvironment _hostEnvironment;
private GlobalSettings _globalSettings;
[TestCase("http://www.domain.com/umbraco/preview/frame?id=1234", "", true)]
[TestCase("http://www.domain.com/umbraco", "", true)]
[TestCase("http://www.domain.com/Umbraco/", "", true)]
[TestCase("http://www.domain.com/umbraco/default.aspx", "", true)]
[TestCase("http://www.domain.com/umbraco/test/test", "", false)]
[TestCase("http://www.domain.com/umbraco/test/test/test", "", false)]
[TestCase("http://www.domain.com/Umbraco/test/test.aspx", "", true)]
[TestCase("http://www.domain.com/umbraco/test/test.js", "", true)]
[TestCase("http://www.domain.com/umbrac", "", false)]
[TestCase("http://www.domain.com/test", "", false)]
[TestCase("http://www.domain.com/test/umbraco", "", false)]
[TestCase("http://www.domain.com/Umbraco/Backoffice/blah", "", true)]
[TestCase("http://www.domain.com/Umbraco/anything", "", true)]
[TestCase("http://www.domain.com/Umbraco/anything/", "", true)]
[TestCase("http://www.domain.com/Umbraco/surface/blah", "", false)]
[TestCase("http://www.domain.com/umbraco/api/blah", "", false)]
[TestCase("http://www.domain.com/myvdir/umbraco/api/blah", "myvdir", false)]
[TestCase("http://www.domain.com/MyVdir/umbraco/api/blah", "/myvdir", false)]
[TestCase("http://www.domain.com/MyVdir/Umbraco/", "myvdir", true)]
[TestCase("http://www.domain.com/umbraco/test/legacyAjaxCalls.ashx?some=query&blah=js", "", true)]
public void Is_Back_Office_Request(string input, string virtualPath, bool expected)
{
var source = new Uri(input);
var hostingEnvironment = CreateHostingEnvironment(virtualPath);
Assert.AreEqual(expected, source.IsBackOfficeRequest(_globalSettings, hostingEnvironment));
}
[TestCase("http://www.domain.com/install", true)]
[TestCase("http://www.domain.com/Install/", true)]
[TestCase("http://www.domain.com/install/default.aspx", true)]
[TestCase("http://www.domain.com/install/test/test", true)]
[TestCase("http://www.domain.com/Install/test/test.aspx", true)]
[TestCase("http://www.domain.com/install/test/test.js", true)]
[TestCase("http://www.domain.com/instal", false)]
[TestCase("http://www.domain.com/umbraco", false)]
[TestCase("http://www.domain.com/umbraco/umbraco", false)]
public void Is_Installer_Request(string input, bool expected)
{
var source = new Uri(input);
var hostingEnvironment = CreateHostingEnvironment();
Assert.AreEqual(expected, source.IsInstallerRequest(hostingEnvironment));
}
private AspNetCoreHostingEnvironment CreateHostingEnvironment(string virtualPath = "")
{
var hostingSettings = new HostingSettings { ApplicationVirtualPath = virtualPath };

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Routing;
using Umbraco.Web.Common.AspNetCore;
namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class UmbracoRequestPathsTests
{
private IWebHostEnvironment _hostEnvironment;
private GlobalSettings _globalSettings;
[OneTimeSetUp]
public void Setup()
{
_hostEnvironment = Mock.Of<IWebHostEnvironment>();
_globalSettings = new GlobalSettings();
}
private AspNetCoreHostingEnvironment CreateHostingEnvironment(string virtualPath = "")
{
var hostingSettings = new HostingSettings { ApplicationVirtualPath = virtualPath };
var mockedOptionsMonitorOfHostingSettings = Mock.Of<IOptionsMonitor<HostingSettings>>(x => x.CurrentValue == hostingSettings);
return new AspNetCoreHostingEnvironment(mockedOptionsMonitorOfHostingSettings, _hostEnvironment);
}
[TestCase("/favicon.ico", true)]
[TestCase("/umbraco_client/Tree/treeIcons.css", true)]
[TestCase("/umbraco_client/Tree/Themes/umbraco/style.css?cdv=37", true)]
[TestCase("/base/somebasehandler", false)]
[TestCase("/", false)]
[TestCase("/home.aspx", false)]
public void Is_Client_Side_Request(string url, bool assert)
{
var umbracoRequestPaths = new UmbracoRequestPaths(null, null);
var uri = new Uri("http://test.com" + url);
var result = umbracoRequestPaths.IsClientSideRequest(uri.AbsolutePath);
Assert.AreEqual(assert, result);
}
[Test]
public void Is_Client_Side_Request_InvalidPath_ReturnFalse()
{
var umbracoRequestPaths = new UmbracoRequestPaths(null, null);
// This URL is invalid. Default to false when the extension cannot be determined
var uri = new Uri("http://test.com/installing-modules+foobar+\"yipee\"");
var result = umbracoRequestPaths.IsClientSideRequest(uri.AbsolutePath);
Assert.AreEqual(false, result);
}
[TestCase("http://www.domain.com/umbraco/preview/frame?id=1234", "", true)]
[TestCase("http://www.domain.com/umbraco", "", true)]
[TestCase("http://www.domain.com/Umbraco/", "", true)]
[TestCase("http://www.domain.com/umbraco/default.aspx", "", true)]
[TestCase("http://www.domain.com/umbraco/test/test", "", false)]
[TestCase("http://www.domain.com/umbraco/test/test/test", "", false)]
[TestCase("http://www.domain.com/Umbraco/test/test.aspx", "", true)]
[TestCase("http://www.domain.com/umbraco/test/test.js", "", true)]
[TestCase("http://www.domain.com/umbrac", "", false)]
[TestCase("http://www.domain.com/test", "", false)]
[TestCase("http://www.domain.com/test/umbraco", "", false)]
[TestCase("http://www.domain.com/Umbraco/Backoffice/blah", "", true)]
[TestCase("http://www.domain.com/Umbraco/anything", "", true)]
[TestCase("http://www.domain.com/Umbraco/anything/", "", true)]
[TestCase("http://www.domain.com/Umbraco/surface/blah", "", false)]
[TestCase("http://www.domain.com/umbraco/api/blah", "", false)]
[TestCase("http://www.domain.com/myvdir/umbraco/api/blah", "myvdir", false)]
[TestCase("http://www.domain.com/MyVdir/umbraco/api/blah", "/myvdir", false)]
[TestCase("http://www.domain.com/MyVdir/Umbraco/", "myvdir", true)]
[TestCase("http://www.domain.com/umbraco/test/legacyAjaxCalls.ashx?some=query&blah=js", "", true)]
public void Is_Back_Office_Request(string input, string virtualPath, bool expected)
{
var source = new Uri(input);
var hostingEnvironment = CreateHostingEnvironment(virtualPath);
var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment);
Assert.AreEqual(expected, umbracoRequestPaths.IsBackOfficeRequest(source.AbsolutePath));
}
[TestCase("http://www.domain.com/install", true)]
[TestCase("http://www.domain.com/Install/", true)]
[TestCase("http://www.domain.com/install/default.aspx", true)]
[TestCase("http://www.domain.com/install/test/test", true)]
[TestCase("http://www.domain.com/Install/test/test.aspx", true)]
[TestCase("http://www.domain.com/install/test/test.js", true)]
[TestCase("http://www.domain.com/instal", false)]
[TestCase("http://www.domain.com/umbraco", false)]
[TestCase("http://www.domain.com/umbraco/umbraco", false)]
public void Is_Installer_Request(string input, bool expected)
{
var source = new Uri(input);
var hostingEnvironment = CreateHostingEnvironment();
var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment);
Assert.AreEqual(expected, umbracoRequestPaths.IsInstallerRequest(source.AbsolutePath));
}
}
}

View File

@@ -2,11 +2,13 @@
// See LICENSE for more details.
using System;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Routing;
using Umbraco.Extensions;
using Umbraco.Web;
using Umbraco.Web.BackOffice.Controllers;
@@ -26,10 +28,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security
var mgr = new BackOfficeCookieManager(
Mock.Of<IUmbracoContextAccessor>(),
runtime,
Mock.Of<IHostingEnvironment>(),
globalSettings);
new UmbracoRequestPaths(Options.Create(globalSettings), Mock.Of<IHostingEnvironment>()));
var result = mgr.ShouldAuthenticateRequest(new Uri("http://localhost/umbraco"));
var result = mgr.ShouldAuthenticateRequest("/umbraco");
Assert.IsFalse(result);
}
@@ -43,10 +44,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security
var mgr = new BackOfficeCookieManager(
Mock.Of<IUmbracoContextAccessor>(),
runtime,
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco"),
globalSettings);
new UmbracoRequestPaths(
Options.Create(globalSettings),
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco")));
var result = mgr.ShouldAuthenticateRequest(new Uri("http://localhost/umbraco"));
var result = mgr.ShouldAuthenticateRequest("/umbraco");
Assert.IsTrue(result);
}
@@ -63,13 +65,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security
var mgr = new BackOfficeCookieManager(
Mock.Of<IUmbracoContextAccessor>(),
runtime,
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install"),
globalSettings);
new UmbracoRequestPaths(
Options.Create(globalSettings),
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")));
var result = mgr.ShouldAuthenticateRequest(new Uri($"http://localhost{remainingTimeoutSecondsPath}"));
var result = mgr.ShouldAuthenticateRequest(remainingTimeoutSecondsPath);
Assert.IsTrue(result);
result = mgr.ShouldAuthenticateRequest(new Uri($"http://localhost{isAuthPath}"));
result = mgr.ShouldAuthenticateRequest(isAuthPath);
Assert.IsTrue(result);
}
@@ -83,14 +86,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security
var mgr = new BackOfficeCookieManager(
Mock.Of<IUmbracoContextAccessor>(),
runtime,
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install"),
globalSettings);
new UmbracoRequestPaths(
Options.Create(globalSettings),
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")));
var result = mgr.ShouldAuthenticateRequest(new Uri($"http://localhost/notbackoffice"));
var result = mgr.ShouldAuthenticateRequest("/notbackoffice");
Assert.IsFalse(result);
result = mgr.ShouldAuthenticateRequest(new Uri($"http://localhost/umbraco/api/notbackoffice"));
result = mgr.ShouldAuthenticateRequest("/umbraco/api/notbackoffice");
Assert.IsFalse(result);
result = mgr.ShouldAuthenticateRequest(new Uri($"http://localhost/umbraco/surface/notbackoffice"));
result = mgr.ShouldAuthenticateRequest("/umbraco/surface/notbackoffice");
Assert.IsFalse(result);
}

View File

@@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Routing;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Extensions;
using Umbraco.Web.Common.Routing;
using Umbraco.Web.Common.Extensions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing

View File

@@ -76,13 +76,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing
RouteEndpoint endpoint1 = CreateEndpoint(
"Umbraco/RenderMvc/{action?}/{id?}",
new { controller = "RenderMvc" },
"Umbraco_default",
0);
RouteEndpoint endpoint2 = CreateEndpoint(
"api/{controller?}/{id?}",
new { action = "Index" },
"WebAPI",
1);
var endpointDataSource = new DefaultEndpointDataSource(endpoint1, endpoint2);
@@ -97,16 +95,42 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing
routableDocFilter.IsDocumentRequest(url));
}
[TestCase("/umbraco", true)]
[TestCase("/umbraco/", true)]
[TestCase("/umbraco/Default", true)]
[TestCase("/umbraco/default/", true)]
[TestCase("/umbraco/default/123", true)]
[TestCase("/umbraco/default/blah/123", false)]
public void Is_Reserved_By_Default_Back_Office_Route(string url, bool isReserved)
{
var globalSettings = new GlobalSettings { ReservedPaths = string.Empty, ReservedUrls = string.Empty };
RouteEndpoint endpoint1 = CreateEndpoint(
"umbraco/{action}/{id?}",
new { controller = "BackOffice", action = "Default" },
0);
var endpointDataSource = new DefaultEndpointDataSource(endpoint1);
var routableDocFilter = new RoutableDocumentFilter(
globalSettings,
GetHostingEnvironment(),
endpointDataSource);
Assert.AreEqual(
!isReserved, // not reserved if it's a document request
routableDocFilter.IsDocumentRequest(url));
}
// borrowed from https://github.com/dotnet/aspnetcore/blob/19559e73da2b6d335b864ed2855dd8a0c7a207a0/src/Mvc/Mvc.Core/test/Routing/ControllerLinkGeneratorExtensionsTest.cs#L171
private RouteEndpoint CreateEndpoint(
string template,
object defaults = null,
string name = null,
int order = 0) => new RouteEndpoint(
(httpContext) => Task.CompletedTask,
RoutePatternFactory.Parse(template, defaults, null),
order,
new EndpointMetadataCollection(Array.Empty<object>()),
name);
null);
}
}

View File

@@ -12,6 +12,7 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Routing;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Tests.Common;
@@ -49,7 +50,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers
Mock.Of<IPublishedSnapshotService>(),
new TestVariationContextAccessor(),
new TestDefaultCultureAccessor(),
Options.Create(globalSettings),
new UmbracoRequestPaths(Options.Create(globalSettings), hostingEnvironment),
hostingEnvironment,
new UriUtility(hostingEnvironment),
Mock.Of<ICookieManager>(),
@@ -80,7 +81,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers
Mock.Of<IPublishedSnapshotService>(),
new TestVariationContextAccessor(),
new TestDefaultCultureAccessor(),
Options.Create(globalSettings),
new UmbracoRequestPaths(Options.Create(globalSettings), hostingEnvironment),
hostingEnvironment,
new UriUtility(hostingEnvironment),
Mock.Of<ICookieManager>(),
@@ -115,7 +116,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers
publishedSnapshotService.Object,
new TestVariationContextAccessor(),
new TestDefaultCultureAccessor(),
Options.Create(globalSettings),
new UmbracoRequestPaths(Options.Create(globalSettings), hostingEnvironment),
hostingEnvironment,
new UriUtility(hostingEnvironment),
Mock.Of<ICookieManager>(),
@@ -149,7 +150,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers
Mock.Of<IPublishedSnapshotService>(),
new TestVariationContextAccessor(),
new TestDefaultCultureAccessor(),
Options.Create(globalSettings),
new UmbracoRequestPaths(Options.Create(globalSettings), hostingEnvironment),
hostingEnvironment,
new UriUtility(hostingEnvironment),
Mock.Of<ICookieManager>(),

View File

@@ -32,7 +32,6 @@ namespace Umbraco.Tests.Routing
(
runtime,
logger,
null, // FIXME: PublishedRouter complexities...
Mock.Of<IUmbracoContextFactory>(),
globalSettings,
HostingEnvironment
@@ -77,28 +76,6 @@ namespace Umbraco.Tests.Routing
Assert.AreEqual(assert, result.Success);
}
[TestCase("/favicon.ico", true)]
[TestCase("/umbraco_client/Tree/treeIcons.css", true)]
[TestCase("/umbraco_client/Tree/Themes/umbraco/style.css?cdv=37", true)]
[TestCase("/base/somebasehandler", false)]
[TestCase("/", false)]
[TestCase("/home.aspx", false)]
public void Is_Client_Side_Request(string url, bool assert)
{
var uri = new Uri("http://test.com" + url);
var result = uri.IsClientSideRequest();
Assert.AreEqual(assert, result);
}
[Test]
public void Is_Client_Side_Request_InvalidPath_ReturnFalse()
{
//This URL is invalid. Default to false when the extension cannot be determined
var uri = new Uri("http://test.com/installing-modules+foobar+\"yipee\"");
var result = uri.IsClientSideRequest();
Assert.AreEqual(false, result);
}
//NOTE: This test shows how we can test most of the HttpModule, it however is testing a method that no longer exists and is testing too much,
// we need to write unit tests for each of the components: NiceUrlProvider, all of the Lookup classes, etc...
// to ensure that each one is individually tested.

View File

@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Logging;
using Umbraco.Core;
using Umbraco.Extensions;
namespace Umbraco.Web.BackOffice.Filters
{
@@ -21,9 +22,8 @@ namespace Umbraco.Web.BackOffice.Filters
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute);
// If it's a client side request just call next and don't try to log anything
if (requestUri.IsClientSideRequest())
if (context.Request.IsClientSideRequest())
{
await next(context);
}
@@ -36,7 +36,7 @@ namespace Umbraco.Web.BackOffice.Filters
}
catch (Exception e)
{
_logger.LogError(e, "Unhandled controller exception occurred for request '{RequestUrl}'", requestUri.AbsoluteUri);
_logger.LogError(e, "Unhandled controller exception occurred for request '{RequestUrl}'", context.Request.GetEncodedPathAndQuery());
// Throw the error again, just in case it gets handled
throw;
}

View File

@@ -1,13 +1,10 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Extensions;
namespace Umbraco.Web.BackOffice.Middleware
@@ -17,17 +14,7 @@ namespace Umbraco.Web.BackOffice.Middleware
/// </summary>
public class PreviewAuthenticationMiddleware : IMiddleware
{
private readonly GlobalSettings _globalSettings;
private readonly IHostingEnvironment _hostingEnvironment;
public PreviewAuthenticationMiddleware(
IOptions<GlobalSettings> globalSettings,
IHostingEnvironment hostingEnvironment)
{
_globalSettings = globalSettings.Value;
_hostingEnvironment = hostingEnvironment;
}
/// <inheritdoc/>
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var request = context.Request;
@@ -35,7 +22,7 @@ namespace Umbraco.Web.BackOffice.Middleware
{
var isPreview = request.HasPreviewCookie()
&& context.User != null
&& !request.IsBackOfficeRequest(_globalSettings, _hostingEnvironment);
&& !request.IsBackOfficeRequest();
if (isPreview)
{
@@ -43,7 +30,9 @@ namespace Umbraco.Web.BackOffice.Middleware
.Get(Constants.Security.BackOfficeAuthenticationType);
if (cookieOptions == null)
{
throw new InvalidOperationException("No cookie options found with name " + Constants.Security.BackOfficeAuthenticationType);
}
// If we've gotten this far it means a preview cookie has been set and a front-end umbraco document request is executing.
// In this case, authentication will not have occurred for an Umbraco back office User, however we need to perform the authentication
@@ -55,11 +44,12 @@ namespace Umbraco.Web.BackOffice.Middleware
{
var backOfficeIdentity = unprotected.Principal.GetUmbracoIdentity();
if (backOfficeIdentity != null)
{
// Ok, we've got a real ticket, now we can add this ticket's identity to the current
// Principal, this means we'll have 2 identities assigned to the principal which we can
// use to authorize the preview and allow for a back office User.
context.User.AddIdentity(backOfficeIdentity);
}
}
}

View File

@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -6,6 +6,7 @@ using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Web.BackOffice.Controllers;
using Umbraco.Web.Common.Controllers;
using Umbraco.Web.Common.Extensions;
using Umbraco.Web.Common.Routing;
using Umbraco.Web.WebApi;
@@ -61,14 +62,16 @@ namespace Umbraco.Web.BackOffice.Routing
/// <summary>
/// Map the minimal routes required to load the back office login and auth
/// </summary>
/// <param name="endpoints"></param>
private void MapMinimalBackOffice(IEndpointRouteBuilder endpoints)
{
endpoints.MapUmbracoRoute<BackOfficeController>(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea,
endpoints.MapUmbracoRoute<BackOfficeController>(
_umbracoPathSegment,
Constants.Web.Mvc.BackOfficeArea,
string.Empty,
"Default",
includeControllerNameInRoute: false,
constraints:
// Limit the action/id to only allow characters - this is so this route doesn't hog all other
// routes like: /umbraco/channels/word.aspx, etc...
// (Not that we have to worry about too many of those these days, there still might be a need for these constraints).

View File

@@ -7,6 +7,7 @@ using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Web.BackOffice.Controllers;
using Umbraco.Web.BackOffice.SignalR;
using Umbraco.Web.Common.Extensions;
using Umbraco.Web.Common.Routing;
namespace Umbraco.Web.BackOffice.Routing

View File

@@ -1,14 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Extensions;
using Umbraco.Core.Routing;
namespace Umbraco.Web.BackOffice.Security
{
@@ -23,9 +18,8 @@ namespace Umbraco.Web.BackOffice.Security
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IRuntimeState _runtime;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly GlobalSettings _globalSettings;
private readonly string[] _explicitPaths;
private readonly UmbracoRequestPaths _umbracoRequestPaths;
/// <summary>
/// Initializes a new instance of the <see cref="BackOfficeCookieManager"/> class.
@@ -33,10 +27,10 @@ namespace Umbraco.Web.BackOffice.Security
public BackOfficeCookieManager(
IUmbracoContextAccessor umbracoContextAccessor,
IRuntimeState runtime,
IHostingEnvironment hostingEnvironment,
GlobalSettings globalSettings)
: this(umbracoContextAccessor, runtime, hostingEnvironment, globalSettings, null)
{ }
UmbracoRequestPaths umbracoRequestPaths)
: this(umbracoContextAccessor, runtime, null, umbracoRequestPaths)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BackOfficeCookieManager"/> class.
@@ -44,21 +38,18 @@ namespace Umbraco.Web.BackOffice.Security
public BackOfficeCookieManager(
IUmbracoContextAccessor umbracoContextAccessor,
IRuntimeState runtime,
IHostingEnvironment hostingEnvironment,
GlobalSettings globalSettings,
IEnumerable<string> explicitPaths)
IEnumerable<string> explicitPaths,
UmbracoRequestPaths umbracoRequestPaths)
{
_umbracoContextAccessor = umbracoContextAccessor;
_runtime = runtime;
_hostingEnvironment = hostingEnvironment;
_globalSettings = globalSettings;
_explicitPaths = explicitPaths?.ToArray();
_umbracoRequestPaths = umbracoRequestPaths;
}
/// <summary>
/// Determines if we should authenticate the request
/// </summary>
/// <param name="requestUri">The <see cref="Uri"/> to check</param>
/// <returns>true if the request should be authenticated</returns>
/// <remarks>
/// We auth the request when:
@@ -66,7 +57,7 @@ namespace Umbraco.Web.BackOffice.Security
/// * it is an installer request
/// * it is a preview request
/// </remarks>
public bool ShouldAuthenticateRequest(Uri requestUri)
public bool ShouldAuthenticateRequest(string absPath)
{
// Do not authenticate the request if we are not running (don't have a db, are not configured) - since we will never need
// to know a current user in this scenario - we treat it as a new install. Without this we can have some issues
@@ -82,14 +73,14 @@ namespace Umbraco.Web.BackOffice.Security
// check the explicit paths
if (_explicitPaths != null)
{
return _explicitPaths.Any(x => x.InvariantEquals(requestUri.AbsolutePath));
return _explicitPaths.Any(x => x.InvariantEquals(absPath));
}
if (// check back office
requestUri.IsBackOfficeRequest(_globalSettings, _hostingEnvironment)
_umbracoRequestPaths.IsBackOfficeRequest(absPath)
// check installer
|| requestUri.IsInstallerRequest(_hostingEnvironment))
|| _umbracoRequestPaths.IsInstallerRequest(absPath))
{
return true;
}
@@ -103,16 +94,18 @@ namespace Umbraco.Web.BackOffice.Security
/// <inheritdoc/>
string Microsoft.AspNetCore.Authentication.Cookies.ICookieManager.GetRequestCookie(HttpContext context, string key)
{
var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute);
var absPath = context.Request.Path;
if (_umbracoContextAccessor.UmbracoContext == null || requestUri.IsClientSideRequest())
if (_umbracoContextAccessor.UmbracoContext == null || _umbracoRequestPaths.IsClientSideRequest(absPath))
{
return null;
}
return ShouldAuthenticateRequest(requestUri) == false
return ShouldAuthenticateRequest(absPath) == false
// Don't auth request, don't return a cookie
? null
// Return the default implementation
: GetRequestCookie(context, key);
}

View File

@@ -8,13 +8,14 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Umbraco.Core;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Security;
using Umbraco.Extensions;
namespace Umbraco.Web.BackOffice.Security
{
#pragma warning disable IDE0065 // Misplaced using directive
using ICookieManager = Microsoft.AspNetCore.Authentication.Cookies.ICookieManager;
#pragma warning restore IDE0065 // Misplaced using directive
/// <summary>
/// Used to validate a cookie against a user's session id
@@ -36,21 +37,24 @@ namespace Umbraco.Web.BackOffice.Security
public const string CookieName = "UMB_UCONTEXT_C";
private readonly ISystemClock _systemClock;
private readonly GlobalSettings _globalSettings;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IBackOfficeUserManager _userManager;
public BackOfficeSessionIdValidator(ISystemClock systemClock, IOptions<GlobalSettings> globalSettings, IHostingEnvironment hostingEnvironment, IBackOfficeUserManager userManager)
/// <summary>
/// Initializes a new instance of the <see cref="BackOfficeSessionIdValidator"/> class.
/// </summary>
public BackOfficeSessionIdValidator(ISystemClock systemClock, IOptions<GlobalSettings> globalSettings, IBackOfficeUserManager userManager)
{
_systemClock = systemClock;
_globalSettings = globalSettings.Value;
_hostingEnvironment = hostingEnvironment;
_userManager = userManager;
}
public async Task ValidateSessionAsync(TimeSpan validateInterval, CookieValidatePrincipalContext context)
{
if (!context.Request.IsBackOfficeRequest(_globalSettings, _hostingEnvironment))
if (!context.Request.IsBackOfficeRequest())
{
return;
}
var valid = await ValidateSessionAsync(validateInterval, context.HttpContext, context.Options.CookieManager, _systemClock, context.Properties.IssuedUtc, context.Principal.Identity as ClaimsIdentity);
@@ -81,7 +85,7 @@ namespace Umbraco.Web.BackOffice.Security
DateTimeOffset? issuedUtc = null;
var currentUtc = systemClock.UtcNow;
//read the last checked time from a custom cookie
// read the last checked time from a custom cookie
var lastCheckedCookie = cookieManager.GetRequestCookie(httpContext, CookieName);
if (lastCheckedCookie.IsNullOrWhiteSpace() == false)
@@ -92,7 +96,7 @@ namespace Umbraco.Web.BackOffice.Security
}
}
//no cookie, use the issue time of the auth ticket
// no cookie, use the issue time of the auth ticket
if (issuedUtc.HasValue == false)
{
issuedUtc = authTicketIssueDate;
@@ -107,18 +111,24 @@ namespace Umbraco.Web.BackOffice.Security
}
if (validate == false)
{
return true;
}
var userId = currentIdentity.GetUserId();
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return false;
}
var sessionId = currentIdentity.FindFirstValue(Constants.Security.SessionIdClaimType);
if (await _userManager.ValidateSessionIdAsync(userId, sessionId) == false)
{
return false;
}
//we will re-issue the cookie last checked cookie
// we will re-issue the cookie last checked cookie
cookieManager.AppendResponseCookie(
httpContext,
CookieName,

View File

@@ -13,6 +13,7 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Routing;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Extensions;
@@ -36,6 +37,7 @@ namespace Umbraco.Web.BackOffice.Security
private readonly IUserService _userService;
private readonly IIpResolver _ipResolver;
private readonly ISystemClock _systemClock;
private readonly UmbracoRequestPaths _umbracoRequestPaths;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureBackOfficeCookieOptions"/> class.
@@ -60,7 +62,8 @@ namespace Umbraco.Web.BackOffice.Security
IDataProtectionProvider dataProtection,
IUserService userService,
IIpResolver ipResolver,
ISystemClock systemClock)
ISystemClock systemClock,
UmbracoRequestPaths umbracoRequestPaths)
{
_serviceProvider = serviceProvider;
_umbracoContextAccessor = umbracoContextAccessor;
@@ -72,6 +75,7 @@ namespace Umbraco.Web.BackOffice.Security
_userService = userService;
_ipResolver = ipResolver;
_systemClock = systemClock;
_umbracoRequestPaths = umbracoRequestPaths;
}
/// <inheritdoc />
@@ -115,8 +119,7 @@ namespace Umbraco.Web.BackOffice.Security
options.CookieManager = new BackOfficeCookieManager(
_umbracoContextAccessor,
_runtimeState,
_hostingEnvironment,
_globalSettings); // _explicitPaths); TODO: Implement this once we do OAuth somehow
_umbracoRequestPaths);
options.Events = new CookieAuthenticationEvents
{

View File

@@ -1,26 +1,18 @@
using Microsoft.AspNetCore.Builder;
using System;
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using NUglify.Helpers;
using System;
using System.Text;
using Umbraco.Extensions;
namespace Umbraco.Web.Common.Routing
namespace Umbraco.Web.Common.Extensions
{
public static class EndpointRouteBuilderExtensions
{
/// <summary>
/// Used to map Umbraco controllers consistently
/// </summary>
/// <param name="endpoints"></param>
/// <param name="controllerType"></param>
/// <param name="rootSegment"></param>
/// <param name="areaName"></param>
/// <param name="prefixPathSegment"></param>
/// <param name="defaultAction"></param>
/// <param name="includeControllerNameInRoute"></param>
/// <param name="constraints"></param>
public static void MapUmbracoRoute(
this IEndpointRouteBuilder endpoints,
Type controllerType,
@@ -36,19 +28,26 @@ namespace Umbraco.Web.Common.Routing
// build the route pattern
var pattern = new StringBuilder(rootSegment);
if (!prefixPathSegment.IsNullOrWhiteSpace())
{
pattern.Append("/").Append(prefixPathSegment);
}
if (includeControllerNameInRoute)
{
pattern.Append("/").Append(controllerName);
}
pattern.Append("/").Append("{action}/{id?}");
var defaults = defaultAction.IsNullOrWhiteSpace()
? (object) new { controller = controllerName }
? (object)new { controller = controllerName }
: new { controller = controllerName, action = defaultAction };
if (areaName.IsNullOrWhiteSpace())
{
endpoints.MapControllerRoute(
// named consistently
$"umbraco-{areaName}-{controllerName}".ToLowerInvariant(),
pattern.ToString().ToLowerInvariant(),
@@ -58,6 +57,7 @@ namespace Umbraco.Web.Common.Routing
else
{
endpoints.MapAreaControllerRoute(
// named consistently
$"umbraco-{areaName}-{controllerName}".ToLowerInvariant(),
areaName,
@@ -65,19 +65,11 @@ namespace Umbraco.Web.Common.Routing
defaults,
constraints);
}
}
/// <summary>
/// Used to map Umbraco controllers consistently
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="endpoints"></param>
/// <param name="rootSegment"></param>
/// <param name="areaName"></param>
/// <param name="prefixPathSegment"></param>
/// <param name="defaultAction"></param>
/// <param name="constraints"></param>
public static void MapUmbracoRoute<T>(
this IEndpointRouteBuilder endpoints,
string rootSegment,
@@ -92,12 +84,6 @@ namespace Umbraco.Web.Common.Routing
/// <summary>
/// Used to map Umbraco api controllers consistently
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="endpoints"></param>
/// <param name="rootSegment"></param>
/// <param name="areaName"></param>
/// <param name="isBackOffice">If the route is a back office route</param>
/// <param name="constraints"></param>
public static void MapUmbracoApiRoute<T>(
this IEndpointRouteBuilder endpoints,
string rootSegment,
@@ -111,13 +97,6 @@ namespace Umbraco.Web.Common.Routing
/// <summary>
/// Used to map Umbraco api controllers consistently
/// </summary>
/// <param name="endpoints"></param>
/// <param name="controllerType"></param>
/// <param name="rootSegment"></param>
/// <param name="areaName"></param>
/// <param name="isBackOffice">If the route is a back office route</param>
/// <param name="defaultAction"></param>
/// <param name="constraints"></param>
public static void MapUmbracoApiRoute(
this IEndpointRouteBuilder endpoints,
Type controllerType,
@@ -126,10 +105,23 @@ namespace Umbraco.Web.Common.Routing
bool isBackOffice,
string defaultAction = "Index",
object constraints = null)
=> endpoints.MapUmbracoRoute(controllerType, rootSegment, areaName,
isBackOffice
? (areaName.IsNullOrWhiteSpace() ? $"{Core.Constants.Web.Mvc.BackOfficePathSegment}/Api" : $"{Core.Constants.Web.Mvc.BackOfficePathSegment}/{areaName}")
: (areaName.IsNullOrWhiteSpace() ? "Api" : areaName),
defaultAction, true, constraints);
{
string prefixPathSegment = isBackOffice
? areaName.IsNullOrWhiteSpace()
? $"{Core.Constants.Web.Mvc.BackOfficePathSegment}/Api"
: $"{Core.Constants.Web.Mvc.BackOfficePathSegment}/{areaName}"
: areaName.IsNullOrWhiteSpace()
? "Api"
: areaName;
endpoints.MapUmbracoRoute(
controllerType,
rootSegment,
areaName,
prefixPathSegment,
defaultAction,
true,
constraints);
}
}
}

View File

@@ -1,34 +1,44 @@
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Routing;
namespace Umbraco.Extensions
{
/// <summary>
/// Extension methods for <see cref="HttpRequest"/>
/// </summary>
public static class HttpRequestExtensions
{
/// <summary>
/// Check if a preview cookie exist
/// </summary>
public static bool HasPreviewCookie(this HttpRequest request)
=> request.Cookies.TryGetValue(Constants.Web.PreviewCookieName, out var cookieVal) && !cookieVal.IsNullOrWhiteSpace();
public static bool IsBackOfficeRequest(this HttpRequest request, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment)
=> new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsBackOfficeRequest(globalSettings, hostingEnvironment);
/// <summary>
/// Returns true if the request is a back office request
/// </summary>
public static bool IsBackOfficeRequest(this HttpRequest request)
{
PathString absPath = request.Path;
UmbracoRequestPaths umbReqPaths = request.HttpContext.RequestServices.GetService<UmbracoRequestPaths>();
return umbReqPaths.IsBackOfficeRequest(absPath);
}
/// <summary>
/// Returns true if the request is for a client side extension
/// </summary>
public static bool IsClientSideRequest(this HttpRequest request)
=> new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest();
public static bool IsDefaultBackOfficeRequest(this HttpRequest request, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment)
=> new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsDefaultBackOfficeRequest(globalSettings, hostingEnvironment);
{
PathString absPath = request.Path;
UmbracoRequestPaths umbReqPaths = request.HttpContext.RequestServices.GetService<UmbracoRequestPaths>();
return umbReqPaths.IsClientSideRequest(absPath);
}
public static string ClientCulture(this HttpRequest request)
=> request.Headers.TryGetValue("X-UMB-CULTURE", out var values) ? values[0] : null;

View File

@@ -7,6 +7,7 @@ using Umbraco.Core;
using Umbraco.Core.Hosting;
using Umbraco.Core.Logging;
using Umbraco.Extensions;
using Umbraco.Web.Common.Extensions;
using Umbraco.Web.Common.Routing;
namespace Umbraco.Web.Common.Install

View File

@@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Extensions;
using Umbraco.Web.Common.Lifetime;
using Umbraco.Web.PublishedCache.NuCache;
@@ -59,10 +60,8 @@ namespace Umbraco.Web.Common.Middleware
/// <inheritdoc/>
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute);
// do not process if client-side request
if (requestUri.IsClientSideRequest())
if (context.Request.IsClientSideRequest())
{
await next(context);
return;
@@ -75,12 +74,14 @@ namespace Umbraco.Web.Common.Middleware
bool isFrontEndRequest = umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest();
var pathAndQuery = context.Request.GetEncodedPathAndQuery();
try
{
if (isFrontEndRequest)
{
LogHttpRequest.TryGetCurrentHttpRequestId(out Guid httpRequestId, _requestCache);
_logger.LogTrace("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, requestUri);
_logger.LogTrace("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, pathAndQuery);
}
try
@@ -109,12 +110,12 @@ namespace Umbraco.Web.Common.Middleware
if (isFrontEndRequest)
{
LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache);
_logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, requestUri, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds);
_logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, pathAndQuery, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds);
}
try
{
DisposeRequestCacheItems(_logger, _requestCache, requestUri);
DisposeRequestCacheItems(_logger, _requestCache, context.Request);
}
finally
{
@@ -126,10 +127,10 @@ namespace Umbraco.Web.Common.Middleware
/// <summary>
/// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request
/// </summary>
private static void DisposeRequestCacheItems(ILogger<UmbracoRequestMiddleware> logger, IRequestCache requestCache, Uri requestUri)
private static void DisposeRequestCacheItems(ILogger<UmbracoRequestMiddleware> logger, IRequestCache requestCache, HttpRequest request)
{
// do not process if client-side request
if (requestUri.IsClientSideRequest())
if (request.IsClientSideRequest())
{
return;
}
@@ -143,6 +144,7 @@ namespace Umbraco.Web.Common.Middleware
keys.Add(i.Key);
}
}
// dispose each item and key that was found as disposable.
foreach (var k in keys)
{
@@ -154,6 +156,7 @@ namespace Umbraco.Web.Common.Middleware
{
logger.LogError("Could not dispose item with key " + k, ex);
}
try
{
k.DisposeIfDisposable();

View File

@@ -7,10 +7,9 @@ using System.Threading;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Template;
using Umbraco.Core;
using Umbraco.Core.Collections;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
namespace Umbraco.Web.Common.Routing
{
@@ -27,12 +26,10 @@ namespace Umbraco.Web.Common.Routing
private readonly IHostingEnvironment _hostingEnvironment;
private readonly EndpointDataSource _endpointDataSource;
private readonly object _routeLocker = new object();
#pragma warning disable IDE0044 // Add readonly modifier
private readonly List<string> _backOfficePaths;
private object _initLocker = new object();
private bool _isInit = false;
private HashSet<string> _reservedList;
#pragma warning restore IDE0044 // Add readonly modifier
/// <summary>
/// Initializes a new instance of the <see cref="RoutableDocumentFilter"/> class.

View File

@@ -3,6 +3,7 @@ using Umbraco.Core;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Routing;
using Umbraco.Core.Security;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
@@ -14,7 +15,6 @@ namespace Umbraco.Web
/// </summary>
public class UmbracoContext : DisposableObjectSlim, IDisposeOnRequestEnd, IUmbracoContext
{
private readonly GlobalSettings _globalSettings;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ICookieManager _cookieManager;
private readonly IRequestAccessor _requestAccessor;
@@ -22,6 +22,7 @@ namespace Umbraco.Web
private string _previewToken;
private bool? _previewing;
private readonly IBackOfficeSecurity _backofficeSecurity;
private readonly UmbracoRequestPaths _umbracoRequestPaths;
// initializes a new instance of the UmbracoContext class
// internal for unit tests
@@ -30,7 +31,7 @@ namespace Umbraco.Web
internal UmbracoContext(
IPublishedSnapshotService publishedSnapshotService,
IBackOfficeSecurity backofficeSecurity,
GlobalSettings globalSettings,
UmbracoRequestPaths umbracoRequestPaths,
IHostingEnvironment hostingEnvironment,
IVariationContextAccessor variationContextAccessor,
UriUtility uriUtility,
@@ -43,7 +44,6 @@ namespace Umbraco.Web
}
VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
_hostingEnvironment = hostingEnvironment;
_cookieManager = cookieManager;
@@ -52,6 +52,7 @@ namespace Umbraco.Web
ObjectCreated = DateTime.Now;
UmbracoRequestId = Guid.NewGuid();
_backofficeSecurity = backofficeSecurity ?? throw new ArgumentNullException(nameof(backofficeSecurity));
_umbracoRequestPaths = umbracoRequestPaths;
// beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing
_publishedSnapshot = new Lazy<IPublishedSnapshot>(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken));
@@ -140,7 +141,7 @@ namespace Umbraco.Web
{
Uri requestUrl = _requestAccessor.GetRequestUrl();
if (requestUrl != null
&& requestUrl.IsBackOfficeRequest(_globalSettings, _hostingEnvironment) == false
&& _umbracoRequestPaths.IsBackOfficeRequest(requestUrl.AbsolutePath) == false
&& _backofficeSecurity.CurrentUser != null)
{
var previewToken = _cookieManager.GetCookieValue(Constants.Web.PreviewCookieName); // may be null or empty

View File

@@ -3,6 +3,7 @@ using Microsoft.Extensions.Options;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Routing;
using Umbraco.Core.Security;
using Umbraco.Web.PublishedCache;
@@ -18,7 +19,7 @@ namespace Umbraco.Web
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IDefaultCultureAccessor _defaultCultureAccessor;
private readonly GlobalSettings _globalSettings;
private readonly UmbracoRequestPaths _umbracoRequestPaths;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ICookieManager _cookieManager;
private readonly IRequestAccessor _requestAccessor;
@@ -33,7 +34,7 @@ namespace Umbraco.Web
IPublishedSnapshotService publishedSnapshotService,
IVariationContextAccessor variationContextAccessor,
IDefaultCultureAccessor defaultCultureAccessor,
IOptions<GlobalSettings> globalSettings,
UmbracoRequestPaths umbracoRequestPaths,
IHostingEnvironment hostingEnvironment,
UriUtility uriUtility,
ICookieManager cookieManager,
@@ -44,7 +45,7 @@ namespace Umbraco.Web
_publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService));
_variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
_defaultCultureAccessor = defaultCultureAccessor ?? throw new ArgumentNullException(nameof(defaultCultureAccessor));
_globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings));
_umbracoRequestPaths = umbracoRequestPaths ?? throw new ArgumentNullException(nameof(umbracoRequestPaths));
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
_uriUtility = uriUtility ?? throw new ArgumentNullException(nameof(uriUtility));
_cookieManager = cookieManager ?? throw new ArgumentNullException(nameof(cookieManager));
@@ -75,7 +76,7 @@ namespace Umbraco.Web
return new UmbracoContext(
_publishedSnapshotService,
_backofficeSecurityAccessor.BackOfficeSecurity,
_globalSettings,
_umbracoRequestPaths,
_hostingEnvironment,
_variationContextAccessor,
_uriUtility,

View File

@@ -71,14 +71,6 @@ namespace Umbraco.Web.Website.Routing
return values;
}
// Check for back office request
// TODO: This is how the module was doing it before but could just as easily be part of the RoutableDocumentFilter
// which still needs to be migrated.
if (httpContext.Request.IsDefaultBackOfficeRequest(_globalSettings, _hostingEnvironment))
{
return values;
}
// Check if there is no existing content and return the no content controller
if (!_umbracoContextAccessor.UmbracoContext.Content.HasContent())
{

View File

@@ -12,18 +12,12 @@ using Umbraco.Web.Security;
namespace Umbraco.Web
{
/// <summary>
/// Class that encapsulates Umbraco information of a specific HTTP request
/// </summary>
// NOTE: has all been ported to netcore but exists here just to keep the build working for tests
public class UmbracoContext : DisposableObjectSlim, IDisposeOnRequestEnd, IUmbracoContext
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly GlobalSettings _globalSettings;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ICookieManager _cookieManager;
private readonly Lazy<IPublishedSnapshot> _publishedSnapshot;
private string _previewToken;
private bool? _previewing;
// initializes a new instance of the UmbracoContext class
// internal for unit tests
@@ -44,9 +38,6 @@ namespace Umbraco.Web
if (backofficeSecurity == null) throw new ArgumentNullException(nameof(backofficeSecurity));
VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
_httpContextAccessor = httpContextAccessor;
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
_hostingEnvironment = hostingEnvironment;
_cookieManager = cookieManager;
// ensure that this instance is disposed when the request terminates, though we *also* ensure
// this happens in the Umbraco module since the UmbracoCOntext is added to the HttpContext items.
@@ -134,68 +125,17 @@ namespace Umbraco.Web
/// </summary>
public IVariationContextAccessor VariationContextAccessor { get; }
/// <summary>
/// Gets a value indicating whether the request has debugging enabled
/// </summary>
/// <value><c>true</c> if this instance is debug; otherwise, <c>false</c>.</value>
public bool IsDebug
{
get
{
var request = GetRequestFromContext();
//NOTE: the request can be null during app startup!
return Current.HostingEnvironment.IsDebugMode
&& request != null
&& (string.IsNullOrEmpty(request["umbdebugshowtrace"]) == false
|| string.IsNullOrEmpty(request["umbdebug"]) == false
|| string.IsNullOrEmpty(request.Cookies["UMB-DEBUG"]?.Value) == false);
}
}
// NOTE: has been ported to netcore
public bool IsDebug => false;
/// <summary>
/// Determines whether the current user is in a preview mode and browsing the site (ie. not in the admin UI)
/// </summary>
public bool InPreviewMode
{
get
{
if (_previewing.HasValue == false) DetectPreviewMode();
return _previewing ?? false;
}
private set => _previewing = value;
}
// NOTE: has been ported to netcore
public bool InPreviewMode => false;
public string PreviewToken
{
get
{
if (_previewing.HasValue == false) DetectPreviewMode();
return _previewToken;
}
}
// NOTE: has been ported to netcore
public string PreviewToken => null;
private void DetectPreviewMode()
{
var request = GetRequestFromContext();
if (request?.Url != null
&& request.Url.IsBackOfficeRequest(_globalSettings, _hostingEnvironment) == false
&& Security.CurrentUser != null)
{
var previewToken = _cookieManager.GetPreviewCookieValue(); // may be null or empty
_previewToken = previewToken.IsNullOrWhiteSpace() ? null : previewToken;
}
_previewing = _previewToken.IsNullOrWhiteSpace() == false;
}
// say we render a macro or RTE in a give 'preview' mode that might not be the 'current' one,
// then due to the way it all works at the moment, the 'current' published snapshot need to be in the proper
// default 'preview' mode - somehow we have to force it. and that could be recursive.
public IDisposable ForcedPreview(bool preview)
{
InPreviewMode = preview;
return PublishedSnapshot.ForcedPreview(preview, orig => InPreviewMode = orig);
}
// NOTE: has been ported to netcore
public IDisposable ForcedPreview(bool preview) => null;
private HttpRequestBase GetRequestFromContext()
{
@@ -209,17 +149,7 @@ namespace Umbraco.Web
}
}
protected override void DisposeResources()
{
// DisposableObject ensures that this runs only once
Security.DisposeIfDisposable();
// help caches release resources
// (but don't create caches just to dispose them)
// context is not multi-threaded
if (_publishedSnapshot.IsValueCreated)
_publishedSnapshot.Value.Dispose();
}
// NOTE: has been ported to netcore
protected override void DisposeResources() { }
}
}

View File

@@ -3,7 +3,6 @@ using System.Web;
using System.Web.Routing;
using Microsoft.Extensions.Logging;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Exceptions;
@@ -11,7 +10,6 @@ using Umbraco.Core.Hosting;
using Umbraco.Core.Security;
using Umbraco.Web.Composing;
using Umbraco.Web.Routing;
using RouteDirection = Umbraco.Web.Routing.RouteDirection;
namespace Umbraco.Web
{
@@ -34,7 +32,6 @@ namespace Umbraco.Web
{
private readonly IRuntimeState _runtime;
private readonly ILogger _logger;
private readonly IPublishedRouter _publishedRouter;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly GlobalSettings _globalSettings;
private readonly IHostingEnvironment _hostingEnvironment;
@@ -42,31 +39,22 @@ namespace Umbraco.Web
public UmbracoInjectedModule(
IRuntimeState runtime,
ILogger logger,
IPublishedRouter publishedRouter,
IUmbracoContextFactory umbracoContextFactory,
GlobalSettings globalSettings,
IHostingEnvironment hostingEnvironment)
{
_runtime = runtime;
_logger = logger;
_publishedRouter = publishedRouter;
_umbracoContextFactory = umbracoContextFactory;
_globalSettings = globalSettings;
_hostingEnvironment = hostingEnvironment;
}
#region HttpModule event handlers
/// <summary>
/// Begins to process a request.
/// </summary>
/// <param name="httpContext"></param>
private void BeginRequest(HttpContextBase httpContext)
{
// do not process if client-side request
if (httpContext.Request.Url.IsClientSideRequest())
return;
// write the trace output for diagnostics at the end of the request
httpContext.Trace.Write("UmbracoModule", "Umbraco request begins");
@@ -82,69 +70,25 @@ namespace Umbraco.Web
/// <summary>
/// Processes the Umbraco Request
/// </summary>
/// <param name="httpContext"></param>
/// <remarks>
///
/// This will check if we are trying to route to the default back office page (i.e. ~/Umbraco/ or ~/Umbraco or ~/Umbraco/Default )
/// and ensure that the MVC handler executes for that. This is required because the route for /Umbraco will never execute because
/// files/folders exist there and we cannot set the RouteCollection.RouteExistingFiles = true since that will muck a lot of other things up.
/// So we handle it here and explicitly execute the MVC controller.
///
/// </remarks>
void ProcessRequest(HttpContextBase httpContext)
{
// do not process if client-side request
if (httpContext.Request.Url.IsClientSideRequest())
return;
if (Current.UmbracoContext == null)
throw new InvalidOperationException("The Current.UmbracoContext is null, ProcessRequest cannot proceed unless there is a current UmbracoContext");
var umbracoContext = Current.UmbracoContext;
// re-write for the default back office path
if (httpContext.Request.Url.IsDefaultBackOfficeRequest(_globalSettings, _hostingEnvironment))
{
if (EnsureRuntime(httpContext, umbracoContext.OriginalRequestUrl))
RewriteToBackOfficeHandler(httpContext);
return;
}
// do not process if this request is not a front-end routable page
var isRoutableAttempt = EnsureUmbracoRoutablePage(umbracoContext, httpContext);
// raise event here
UmbracoModule.OnRouteAttempt(this, new RoutableAttemptEventArgs(isRoutableAttempt.Result, umbracoContext));
if (isRoutableAttempt.Success == false) return;
httpContext.Trace.Write("UmbracoModule", "Umbraco request confirmed");
// ok, process
// note: requestModule.UmbracoRewrite also did some stripping of &umbPage
// from the querystring... that was in v3.x to fix some issues with pre-forms
// auth. Paul Sterling confirmed in Jan. 2013 that we can get rid of it.
// instantiate, prepare and process the published content request
// important to use CleanedUmbracoUrl - lowercase path-only version of the current URL
var requestBuilder = _publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl).Result;
var request = umbracoContext.PublishedRequest = _publishedRouter.RouteRequestAsync(requestBuilder, new RouteRequestOptions(RouteDirection.Inbound)).Result;
// NOTE: This has been ported to netcore
// HandleHttpResponseStatus returns a value indicating that the request should
// not be processed any further, eg because it has been redirect. then, exit.
//if (UmbracoModule.HandleHttpResponseStatus(httpContext, request, _logger))
// return;
//if (request.HasPublishedContent() == false)
// httpContext.RemapHandler(new PublishedContentNotFoundHandler());
//else
// RewriteToUmbracoHandler(httpContext, request);
}
#endregion
#region Methods
/// <summary>
/// Checks the current request and ensures that it is routable based on the structure of the request and URI
/// </summary>
@@ -251,7 +195,6 @@ namespace Umbraco.Web
}
#endregion
#region IHttpModule