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]