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