diff --git a/src/Microsoft.AspNet.Mvc.Core/IUrlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/IUrlHelper.cs
index 423adf99f9..9c466cdfbe 100644
--- a/src/Microsoft.AspNet.Mvc.Core/IUrlHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/IUrlHelper.cs
@@ -33,10 +33,24 @@ namespace Microsoft.AspNet.Mvc
string Content(string contentPath);
///
- /// Returns a value that indicates whether the URL is local.
+ /// Returns a value that indicates whether the URL is local. An URL with an absolute path is considered local
+ /// if it does not have a host/authority part. URLs using the virtual paths ('~/') are also local.
///
/// The URL.
- /// true if the URL is local; otherwise, false.
+ /// true if the URL is local; otherwise, false.
+ ///
+ ///
+ /// For example, the following URLs are considered local:
+ /// /Views/Default/Index.html
+ /// ~/Index.html
+ ///
+ ///
+ /// The following URLs are non-local:
+ /// ../Index.html
+ /// http://www.contoso.com/
+ /// http://localhost/Index.html
+ ///
+ ///
bool IsLocalUrl(string url);
///
diff --git a/src/Microsoft.AspNet.Mvc.Core/Internal/UrlUtility.cs b/src/Microsoft.AspNet.Mvc.Core/Internal/UrlUtility.cs
new file mode 100644
index 0000000000..ba5ccadf36
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/Internal/UrlUtility.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNet.Mvc.Internal
+{
+ public static class UrlUtility
+ {
+ ///
+ /// Returns a value that indicates whether the URL is local. An URL with an absolute path is considered local
+ /// if it does not have a host/authority part. URLs using the virtual paths ('~/') are also local.
+ ///
+ /// The URL.
+ /// true if the URL is local; otherwise, false.
+ ///
+ ///
+ /// For example, the following URLs are considered local:
+ /// /Views/Default/Index.html
+ /// ~/Index.html
+ ///
+ ///
+ /// The following URLs are non-local:
+ /// ../Index.html
+ /// http://www.contoso.com/
+ /// http://localhost/Index.html
+ ///
+ ///
+ public static bool IsLocalUrl(string url)
+ {
+ return
+ !string.IsNullOrEmpty(url) &&
+
+ // Allows "/" or "/foo" but not "//" or "/\".
+ ((url[0] == '/' && (url.Length == 1 || (url[1] != '/' && url[1] != '\\'))) ||
+
+ // Allows "~/" or "~/foo".
+ (url.Length > 1 && url[0] == '~' && url[1] == '/'));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs
index f9fda02176..e463fcea99 100644
--- a/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
@@ -71,14 +72,7 @@ namespace Microsoft.AspNet.Mvc
///
public bool IsLocalUrl(string url)
{
- return
- !string.IsNullOrEmpty(url) &&
-
- // Allows "/" or "/foo" but not "//" or "/\".
- ((url[0] == '/' && (url.Length == 1 || (url[1] != '/' && url[1] != '\\'))) ||
-
- // Allows "~/" or "~/foo".
- (url.Length > 1 && url[0] == '~' && url[1] == '/'));
+ return UrlUtility.IsLocalUrl(url);
}
///
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs
index cc2afb46c9..fc7228709a 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
@@ -58,9 +59,13 @@ namespace Microsoft.AspNet.Mvc.Core.Test
Assert.Equal(expectedPath, path);
}
+ // UrlHelper.IsLocalUrl depends on the UrlUtility.IsLocalUrl method.
+ // To avoid duplicate tests, all the tests exercising IsLocalUrl verify
+ // both of UrlHelper.IsLocalUrl and UrlUtility.IsLocalUrl
[Theory]
[InlineData(null)]
[InlineData("")]
+ [InlineData(" ")]
public void IsLocalUrl_ReturnsFalseOnEmpty(string url)
{
// Arrange
@@ -71,6 +76,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -87,6 +98,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.True(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.True(result);
}
[Theory]
@@ -102,6 +119,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.True(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.True(result);
}
[Theory]
@@ -118,6 +141,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -135,6 +164,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -150,6 +185,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -165,6 +206,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -179,6 +226,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -196,6 +249,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -214,6 +273,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -233,6 +298,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Theory]
@@ -250,6 +321,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test
// Assert
Assert.False(result);
+
+ // Arrange & Act
+ result = UrlUtility.IsLocalUrl(url);
+
+ // Assert
+ Assert.False(result);
}
[Fact]