./ paths relative on page.

This commit is contained in:
Ryan Brandenburg 2017-04-24 15:36:25 -07:00
parent 2d2ed571df
commit 42b988ad88
8 changed files with 106 additions and 11 deletions

View File

@ -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;
}
}
}

View File

@ -404,6 +404,6 @@
<value>No page named '{0}' matches the supplied values.</value>
</data>
<data name="UrlHelper_RelativePagePathIsNotSupported" xml:space="preserve">
<value>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.</value>
<value>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.</value>
</data>
</root>

View File

@ -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<IUrlHelper>();
urlHelper.SetupGet(h => h.ActionContext).Returns(pageContext);
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.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<RouteValueDictionary>(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()
{

View File

@ -1518,7 +1518,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => 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);
}

View File

@ -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 =
@"<form method=""post"" action=""/Pages/TagHelper/CrossPost""></form>
var expected =
@"<form method=""post"" action=""/Pages/TagHelper/CrossPost""></form>
<a href=""/Pages/TagHelper/SelfPost/12"" />
<input type=""image"" formaction=""/Pages/TagHelper/CrossPost#my-fragment"" />";
@ -956,8 +970,8 @@ var expected =
public async Task TagHelpers_SupportSubDirectoryRoutes()
{
// Arrange
var expected =
@"<form method=""post"" action=""/Pages/TagHelper/SubDir/SubDirPage""></form>
var expected =
@"<form method=""post"" action=""/Pages/TagHelper/SubDir/SubDirPage""></form>
<a href=""/Pages/TagHelper/SubDir/SubDirPage/12"" />
<input type=""image"" formaction=""/Pages/TagHelper/SubDir/SubDirPage#my-fragment"" />";
@ -972,8 +986,8 @@ var expected =
public async Task TagHelpers_SupportsPathNavigation()
{
// Arrange
var expected =
@"<form method=""post"" action=""/HelloWorld""></form>
var expected =
@"<form method=""post"" action=""/HelloWorld""></form>
<a href=""/Pages/Redirects/RedirectToIndex"" />
<input type=""image"" formaction=""/Pages/Admin#my-fragment"" />";
@ -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 = @"<form method=""post"" action=""/Pages/TagHelper/SubDirectoryLinks""></form>";
// Act
var response = await Client.GetStringAsync("/Pages/TagHelper/PathTraversalLinks");
// Assert
Assert.StartsWith(expected, response.Trim());
}
private async Task AddAntiforgeryHeaders(HttpRequestMessage request)

View File

@ -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

View File

@ -8,4 +8,6 @@
public IActionResult OnGetRedirectToSubDir() => RedirectToPage("SubDir/SubDirPage");
public IActionResult OnGetRedirectToParent() => RedirectToPage("../Conventions/AuthFolder/Index");
public IActionResult OnGetRedirectToDotSlash() => RedirectToPage("./SubDir/SubDirPage");
}

View File

@ -1,5 +1,6 @@
@page
<form method="post" asp-page="./SubDirectoryLinks" asp-antiforgery="false"></form>
<form method="post" asp-page="../../HelloWorld" asp-antiforgery="false"></form>
<a asp-page="../Redirects/Index" asp-route-handler="RedirectToIndex" />
<input type="image" asp-page="../Admin/Index" asp-fragment="my-fragment" />
<input type="image" asp-page="../Admin/Index" asp-fragment="my-fragment" />