diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ViewEnginePath.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ViewEnginePath.cs
index 514bb57719..18f69cbec6 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ViewEnginePath.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ViewEnginePath.cs
@@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Internal
{
public static class ViewEnginePath
{
+ private const string CurrentDirectoryToken = ".";
private const string ParentDirectoryToken = "..";
private static readonly char[] _pathSeparators = new[] { '/', '\\' };
@@ -70,6 +71,11 @@ namespace Microsoft.AspNetCore.Mvc.Core.Internal
}
pathSegments.RemoveAt(pathSegments.Count - 1);
}
+ else if (segment.Equals(CurrentDirectoryToken, StringComparison.Ordinal))
+ {
+ // We already have the current directory
+ continue;
+ }
else
{
pathSegments.Add(segment);
@@ -89,7 +95,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Internal
private static bool RequiresPathResolution(string path)
{
- return path.IndexOf(ParentDirectoryToken, StringComparison.Ordinal) != -1;
+ return path.IndexOf(ParentDirectoryToken, StringComparison.Ordinal) != -1 ||
+ path.IndexOf(CurrentDirectoryToken, StringComparison.Ordinal) != -1;
}
}
}
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
index 8fd48ee9ce..82da0b9f83 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
@@ -404,6 +404,6 @@
No page named '{0}' matches the supplied values.
- The relative page path '{0}' can only can only be used while executing a Razor Page. Specify a root relative path with a leading '/' to generate a URL outside of a Razor Page.
+ The relative page path '{0}' can only be used while executing a Razor Page. Specify a root relative path with a leading '/' to generate a URL outside of a Razor Page.
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/RedirectToPageResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/RedirectToPageResultTest.cs
index 27c7dba121..6b98f0086f 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/RedirectToPageResultTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/RedirectToPageResultTest.cs
@@ -77,6 +77,63 @@ namespace Microsoft.AspNetCore.Mvc
httpResponse.Verify(r => r.Redirect(expectedUrl, permanentRedirect), Times.Exactly(1));
}
+ [Fact]
+ public async Task ExecuteResultAsync_LocalRelativePaths()
+ {
+ // Arrange
+ var httpContext = new DefaultHttpContext
+ {
+ RequestServices = CreateServices(),
+ };
+
+ var pageContext = new PageContext
+ {
+ HttpContext = httpContext,
+ RouteData = new RouteData(),
+ ActionDescriptor = new CompiledPageActionDescriptor(),
+ };
+
+ pageContext.RouteData.Values.Add("page", "/A/Redirecting/Page");
+
+ UrlRouteContext context = null;
+ var urlHelper = new Mock();
+ urlHelper.SetupGet(h => h.ActionContext).Returns(pageContext);
+ urlHelper.Setup(h => h.RouteUrl(It.IsAny()))
+ .Callback((UrlRouteContext c) => context = c)
+ .Returns("some-value");
+ var values = new { test = "test-value" };
+ var result = new RedirectToPageResult("./", "page-handler", values, true, "test-fragment")
+ {
+ UrlHelper = urlHelper.Object,
+ Protocol = "ftp",
+ };
+
+ // Act
+ await result.ExecuteResultAsync(pageContext);
+
+ // Assert
+ Assert.NotNull(context);
+ Assert.Null(context.RouteName);
+ Assert.Collection(Assert.IsType(context.Values),
+ value =>
+ {
+ Assert.Equal("test", value.Key);
+ Assert.Equal("test-value", value.Value);
+ },
+ value =>
+ {
+ Assert.Equal("page", value.Key);
+ Assert.Equal("/A/Redirecting", value.Value);
+ },
+ value =>
+ {
+ Assert.Equal("handler", value.Key);
+ Assert.Equal("page-handler", value.Value);
+ });
+ Assert.Equal("ftp", context.Protocol);
+ Assert.Equal("test-fragment", context.Fragment);
+ }
+
[Fact]
public async Task ExecuteResultAsync_WithAllParameters()
{
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/UrlHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/UrlHelperTest.cs
index a1e337e607..563cfd2410 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/UrlHelperTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/UrlHelperTest.cs
@@ -1518,7 +1518,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
// Act & Assert
var ex = Assert.Throws(() => urlHelper.Object.Page(expected));
- Assert.Equal($"The relative page path '{expected}' can only can only be used while executing a Razor Page. " +
+ Assert.Equal($"The relative page path '{expected}' can only be used while executing a Razor Page. " +
"Specify a root relative path with a leading '/' to generate a URL outside of a Razor Page.", ex.Message);
}
diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs
index 5805b21e1b..8a6610eb7a 100644
--- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs
@@ -924,6 +924,20 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore._InjectedP
Assert.Equal(expected, response.Headers.Location.ToString());
}
+ [Fact]
+ public async Task RedirectToSibling_RedirectsToDotSlash()
+ {
+ // Arrange
+ var expected = "/Pages/Redirects/SubDir/SubDirPage";
+
+ // Act
+ var response = await Client.GetAsync("/Pages/Redirects/RedirectToSibling/RedirectToDotSlash");
+
+ // Assert
+ Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
+ Assert.Equal(expected, response.Headers.Location.ToString());
+ }
+
[Fact]
public async Task RedirectToSibling_RedirectsToParentDirectory()
{
@@ -940,8 +954,8 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore._InjectedP
public async Task TagHelpers_SupportSiblingRoutes()
{
// Arrange
-var expected =
-@"
+ var expected =
+ @"
";
@@ -956,8 +970,8 @@ var expected =
public async Task TagHelpers_SupportSubDirectoryRoutes()
{
// Arrange
-var expected =
-@"
+ var expected =
+ @"
";
@@ -972,8 +986,8 @@ var expected =
public async Task TagHelpers_SupportsPathNavigation()
{
// Arrange
-var expected =
-@"
+ var expected =
+ @"
";
@@ -981,7 +995,20 @@ var expected =
var response = await Client.GetStringAsync("/Pages/TagHelper/PathTraversalLinks");
// Assert
- Assert.Equal(expected, response.Trim());
+ Assert.EndsWith(expected, response.Trim());
+ }
+
+ [Fact]
+ public async Task TagHelpers_SupportsRelativeNavigation()
+ {
+ // Arrange
+ var expected = @"";
+
+ // Act
+ var response = await Client.GetStringAsync("/Pages/TagHelper/PathTraversalLinks");
+
+ // Assert
+ Assert.StartsWith(expected, response.Trim());
}
private async Task AddAntiforgeryHeaders(HttpRequestMessage request)
diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewEngineTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewEngineTest.cs
index 48e489507d..f664954c94 100644
--- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewEngineTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewEngineTest.cs
@@ -1472,6 +1472,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Test
[InlineData("/Views/Home/Index.cshtml", "..\\Shared\\_Partial.cshtml")]
[InlineData("/Areas/MyArea/Views/Home/Index.cshtml", "../../../../Views/Shared/_Partial.cshtml")]
[InlineData("/Views/Accounts/Users.cshtml", "../Test/../Shared/_Partial.cshtml")]
+ [InlineData("Views/Accounts/Users.cshtml", "./../Shared/./_Partial.cshtml")]
public void GetAbsolutePath_ResolvesPathTraversals(string executingFilePath, string pagePath)
{
// Arrange
diff --git a/test/WebSites/RazorPagesWebSite/Pages/Redirects/RedirectToSibling.cshtml b/test/WebSites/RazorPagesWebSite/Pages/Redirects/RedirectToSibling.cshtml
index acb01f4acb..f0935c53db 100644
--- a/test/WebSites/RazorPagesWebSite/Pages/Redirects/RedirectToSibling.cshtml
+++ b/test/WebSites/RazorPagesWebSite/Pages/Redirects/RedirectToSibling.cshtml
@@ -8,4 +8,6 @@
public IActionResult OnGetRedirectToSubDir() => RedirectToPage("SubDir/SubDirPage");
public IActionResult OnGetRedirectToParent() => RedirectToPage("../Conventions/AuthFolder/Index");
+
+ public IActionResult OnGetRedirectToDotSlash() => RedirectToPage("./SubDir/SubDirPage");
}
diff --git a/test/WebSites/RazorPagesWebSite/Pages/TagHelper/PathTraversalLinks.cshtml b/test/WebSites/RazorPagesWebSite/Pages/TagHelper/PathTraversalLinks.cshtml
index bfa5615ed2..456deacfaf 100644
--- a/test/WebSites/RazorPagesWebSite/Pages/TagHelper/PathTraversalLinks.cshtml
+++ b/test/WebSites/RazorPagesWebSite/Pages/TagHelper/PathTraversalLinks.cshtml
@@ -1,5 +1,6 @@
@page
+
-
\ No newline at end of file
+