From 889709239fec7e3a3e81e30e055913b93a96256a Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 5 Oct 2012 15:05:12 -0700 Subject: [PATCH] #19071: Replacing UrlHelper.IsLocalUrl by custom implementation Work Item: 19071 --HG-- branch : 1.x --- .../Orchard.Framework.Tests.csproj | 1 + .../Extensions/HttpRequestExtensionsTests.cs | 78 +++++++++++++++++++ .../Contents/Controllers/AdminController.cs | 3 +- .../Mvc/Extensions/ControllerExtensions.cs | 10 +-- .../Extensions/HttpRequestExtensions.cs | 35 +++++++++ 5 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 src/Orchard.Tests/Utility/Extensions/HttpRequestExtensionsTests.cs diff --git a/src/Orchard.Tests/Orchard.Framework.Tests.csproj b/src/Orchard.Tests/Orchard.Framework.Tests.csproj index d622771af..a3121bb14 100644 --- a/src/Orchard.Tests/Orchard.Framework.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Framework.Tests.csproj @@ -309,6 +309,7 @@ + diff --git a/src/Orchard.Tests/Utility/Extensions/HttpRequestExtensionsTests.cs b/src/Orchard.Tests/Utility/Extensions/HttpRequestExtensionsTests.cs new file mode 100644 index 000000000..0e1a4dc1b --- /dev/null +++ b/src/Orchard.Tests/Utility/Extensions/HttpRequestExtensionsTests.cs @@ -0,0 +1,78 @@ +using System.Collections.Specialized; +using System.Web; +using NUnit.Framework; +using Orchard.Utility.Extensions; + +namespace Orchard.Tests.Utility.Extensions { + [TestFixture] + public class HttpRequestExtensionsTests { + + [Test] + public void IsLocalUrlShouldReturnFalseWhenUrlIsNullOrEmpty() { + var request = new StubHttpRequest(); + + Assert.That(request.IsLocalUrl(null), Is.False); + Assert.That(request.IsLocalUrl(" "), Is.False); + Assert.That(request.IsLocalUrl(""), Is.False); + } + + [Test] + public void IsLocalUrlShouldReturnFalseWhenUrlStartsWithDoubleSlash() { + var request = new StubHttpRequest(); + + Assert.That(request.IsLocalUrl("//"), Is.False); + } + + [Test] + public void IsLocalUrlShouldReturnFalseWhenUrlStartsWithForwardBackwardSlash() { + var request = new StubHttpRequest(); + + Assert.That(request.IsLocalUrl("/\\"), Is.False); + } + + [Test] + public void IsLocalUrlShouldReturnTrueWhenUrlStartsWithSlashAndAnythingElse() { + var request = new StubHttpRequest(); + + Assert.That(request.IsLocalUrl("/"), Is.True); + Assert.That(request.IsLocalUrl("/контакты"), Is.True); + Assert.That(request.IsLocalUrl("/ "), Is.True); + Assert.That(request.IsLocalUrl("/abc-def"), Is.True); + } + + [Test] + public void IsLocalUrlShouldReturnTrueWhenAuthoritiesMatch() { + var request = new StubHttpRequest(); + request.Headers.Add("Host", "localhost"); + + Assert.That(request.IsLocalUrl("http://localhost"), Is.True); + } + + [Test] + public void IsLocalUrlShouldReturnFalseWhenAuthoritiesDiffer() { + var request = new StubHttpRequest(); + request.Headers.Add("Host", "localhost"); + + Assert.That(request.IsLocalUrl("http://somedomain"), Is.False); + Assert.That(request.IsLocalUrl("http://localhost:8080"), Is.False); + } + + [Test] + public void IsLocalUrlShouldReturnFalseForEverythingElse() { + var request = new StubHttpRequest(); + request.Headers.Add("Host", "localhost"); + + Assert.That(request.IsLocalUrl("abc"), Is.False); + } + } + + class StubHttpRequest : HttpRequestBase { + private readonly NameValueCollection _headers = new NameValueCollection(); + + public override NameValueCollection Headers { + get { + return _headers; + } + } + } +} diff --git a/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs b/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs index ddd16a208..30f113376 100644 --- a/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs +++ b/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs @@ -21,6 +21,7 @@ using Orchard.Mvc.Html; using Orchard.UI.Navigation; using Orchard.UI.Notify; using Orchard.Settings; +using Orchard.Utility.Extensions; namespace Orchard.Core.Contents.Controllers { [ValidateInput(false)] @@ -299,7 +300,7 @@ namespace Orchard.Core.Contents.Controllers { string previousRoute = null; if(contentItem.Has() &&!string.IsNullOrWhiteSpace(returnUrl) - && Url.IsLocalUrl(returnUrl) + && Request.IsLocalUrl(returnUrl) // only if the original returnUrl is the content itself && String.Equals(returnUrl, Url.ItemDisplayUrl(contentItem), StringComparison.OrdinalIgnoreCase) ) { diff --git a/src/Orchard/Mvc/Extensions/ControllerExtensions.cs b/src/Orchard/Mvc/Extensions/ControllerExtensions.cs index 9ca5ff8b5..9e69584ea 100644 --- a/src/Orchard/Mvc/Extensions/ControllerExtensions.cs +++ b/src/Orchard/Mvc/Extensions/ControllerExtensions.cs @@ -1,5 +1,7 @@ using System; +using System.Web; using System.Web.Mvc; +using Orchard.Utility.Extensions; namespace Orchard.Mvc.Extensions { public static class ControllerExtensions { @@ -15,14 +17,10 @@ namespace Orchard.Mvc.Extensions { } public static ActionResult RedirectLocal(this Controller controller, string redirectUrl, string defaultUrl) { - if (!string.IsNullOrWhiteSpace(redirectUrl) - && controller.Url.IsLocalUrl(redirectUrl) - && !redirectUrl.StartsWith("//") - && !redirectUrl.StartsWith("/\\")) { - - + if (controller.Request.IsLocalUrl(redirectUrl)) { return new RedirectResult(redirectUrl); } + return new RedirectResult(defaultUrl ?? "~/"); } } diff --git a/src/Orchard/Utility/Extensions/HttpRequestExtensions.cs b/src/Orchard/Utility/Extensions/HttpRequestExtensions.cs index 511f1ba2f..a32881861 100644 --- a/src/Orchard/Utility/Extensions/HttpRequestExtensions.cs +++ b/src/Orchard/Utility/Extensions/HttpRequestExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.Web; namespace Orchard.Utility.Extensions { @@ -57,5 +58,39 @@ namespace Orchard.Utility.Extensions { public static string ToUrlString(this HttpRequest request) { return string.Format("{0}://{1}{2}", request.Url.Scheme, request.Headers["Host"], request.RawUrl); } + + + /// + /// Returns wether the specified url is local to the host or not + /// + /// + /// + /// + public static bool IsLocalUrl(this HttpRequestBase request, string url) { + + if (string.IsNullOrWhiteSpace(url)) { + return false; + } + + if (url.StartsWith("//") || url.StartsWith("/\\")) { + return false; + } + + // at this point is the url starts with "/" it is local + if (url.StartsWith("/")) { + return true; + } + + // at this point, check for an fully qualified url + try { + var uri = new Uri(url); + return uri.Authority.Equals(request.Headers["Host"], StringComparison.OrdinalIgnoreCase); + } + catch { + // mall-formed url e.g, "abcdef" + return false; + } + + } } } \ No newline at end of file