./ paths relative on page.
This commit is contained in:
parent
2d2ed571df
commit
42b988ad88
|
|
@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Internal
|
||||||
{
|
{
|
||||||
public static class ViewEnginePath
|
public static class ViewEnginePath
|
||||||
{
|
{
|
||||||
|
private const string CurrentDirectoryToken = ".";
|
||||||
private const string ParentDirectoryToken = "..";
|
private const string ParentDirectoryToken = "..";
|
||||||
private static readonly char[] _pathSeparators = new[] { '/', '\\' };
|
private static readonly char[] _pathSeparators = new[] { '/', '\\' };
|
||||||
|
|
||||||
|
|
@ -70,6 +71,11 @@ namespace Microsoft.AspNetCore.Mvc.Core.Internal
|
||||||
}
|
}
|
||||||
pathSegments.RemoveAt(pathSegments.Count - 1);
|
pathSegments.RemoveAt(pathSegments.Count - 1);
|
||||||
}
|
}
|
||||||
|
else if (segment.Equals(CurrentDirectoryToken, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
// We already have the current directory
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pathSegments.Add(segment);
|
pathSegments.Add(segment);
|
||||||
|
|
@ -89,7 +95,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Internal
|
||||||
|
|
||||||
private static bool RequiresPathResolution(string path)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,6 @@
|
||||||
<value>No page named '{0}' matches the supplied values.</value>
|
<value>No page named '{0}' matches the supplied values.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UrlHelper_RelativePagePathIsNotSupported" xml:space="preserve">
|
<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>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -77,6 +77,63 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
httpResponse.Verify(r => r.Redirect(expectedUrl, permanentRedirect), Times.Exactly(1));
|
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]
|
[Fact]
|
||||||
public async Task ExecuteResultAsync_WithAllParameters()
|
public async Task ExecuteResultAsync_WithAllParameters()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1518,7 +1518,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var ex = Assert.Throws<InvalidOperationException>(() => urlHelper.Object.Page(expected));
|
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);
|
"Specify a root relative path with a leading '/' to generate a URL outside of a Razor Page.", ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -924,6 +924,20 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore._InjectedP
|
||||||
Assert.Equal(expected, response.Headers.Location.ToString());
|
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]
|
[Fact]
|
||||||
public async Task RedirectToSibling_RedirectsToParentDirectory()
|
public async Task RedirectToSibling_RedirectsToParentDirectory()
|
||||||
{
|
{
|
||||||
|
|
@ -940,8 +954,8 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore._InjectedP
|
||||||
public async Task TagHelpers_SupportSiblingRoutes()
|
public async Task TagHelpers_SupportSiblingRoutes()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected =
|
var expected =
|
||||||
@"<form method=""post"" action=""/Pages/TagHelper/CrossPost""></form>
|
@"<form method=""post"" action=""/Pages/TagHelper/CrossPost""></form>
|
||||||
<a href=""/Pages/TagHelper/SelfPost/12"" />
|
<a href=""/Pages/TagHelper/SelfPost/12"" />
|
||||||
<input type=""image"" formaction=""/Pages/TagHelper/CrossPost#my-fragment"" />";
|
<input type=""image"" formaction=""/Pages/TagHelper/CrossPost#my-fragment"" />";
|
||||||
|
|
||||||
|
|
@ -956,8 +970,8 @@ var expected =
|
||||||
public async Task TagHelpers_SupportSubDirectoryRoutes()
|
public async Task TagHelpers_SupportSubDirectoryRoutes()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected =
|
var expected =
|
||||||
@"<form method=""post"" action=""/Pages/TagHelper/SubDir/SubDirPage""></form>
|
@"<form method=""post"" action=""/Pages/TagHelper/SubDir/SubDirPage""></form>
|
||||||
<a href=""/Pages/TagHelper/SubDir/SubDirPage/12"" />
|
<a href=""/Pages/TagHelper/SubDir/SubDirPage/12"" />
|
||||||
<input type=""image"" formaction=""/Pages/TagHelper/SubDir/SubDirPage#my-fragment"" />";
|
<input type=""image"" formaction=""/Pages/TagHelper/SubDir/SubDirPage#my-fragment"" />";
|
||||||
|
|
||||||
|
|
@ -972,8 +986,8 @@ var expected =
|
||||||
public async Task TagHelpers_SupportsPathNavigation()
|
public async Task TagHelpers_SupportsPathNavigation()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected =
|
var expected =
|
||||||
@"<form method=""post"" action=""/HelloWorld""></form>
|
@"<form method=""post"" action=""/HelloWorld""></form>
|
||||||
<a href=""/Pages/Redirects/RedirectToIndex"" />
|
<a href=""/Pages/Redirects/RedirectToIndex"" />
|
||||||
<input type=""image"" formaction=""/Pages/Admin#my-fragment"" />";
|
<input type=""image"" formaction=""/Pages/Admin#my-fragment"" />";
|
||||||
|
|
||||||
|
|
@ -981,7 +995,20 @@ var expected =
|
||||||
var response = await Client.GetStringAsync("/Pages/TagHelper/PathTraversalLinks");
|
var response = await Client.GetStringAsync("/Pages/TagHelper/PathTraversalLinks");
|
||||||
|
|
||||||
// Assert
|
// 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)
|
private async Task AddAntiforgeryHeaders(HttpRequestMessage request)
|
||||||
|
|
|
||||||
|
|
@ -1472,6 +1472,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Test
|
||||||
[InlineData("/Views/Home/Index.cshtml", "..\\Shared\\_Partial.cshtml")]
|
[InlineData("/Views/Home/Index.cshtml", "..\\Shared\\_Partial.cshtml")]
|
||||||
[InlineData("/Areas/MyArea/Views/Home/Index.cshtml", "../../../../Views/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", "../Test/../Shared/_Partial.cshtml")]
|
||||||
|
[InlineData("Views/Accounts/Users.cshtml", "./../Shared/./_Partial.cshtml")]
|
||||||
public void GetAbsolutePath_ResolvesPathTraversals(string executingFilePath, string pagePath)
|
public void GetAbsolutePath_ResolvesPathTraversals(string executingFilePath, string pagePath)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,6 @@
|
||||||
public IActionResult OnGetRedirectToSubDir() => RedirectToPage("SubDir/SubDirPage");
|
public IActionResult OnGetRedirectToSubDir() => RedirectToPage("SubDir/SubDirPage");
|
||||||
|
|
||||||
public IActionResult OnGetRedirectToParent() => RedirectToPage("../Conventions/AuthFolder/Index");
|
public IActionResult OnGetRedirectToParent() => RedirectToPage("../Conventions/AuthFolder/Index");
|
||||||
|
|
||||||
|
public IActionResult OnGetRedirectToDotSlash() => RedirectToPage("./SubDir/SubDirPage");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
@page
|
@page
|
||||||
|
|
||||||
|
<form method="post" asp-page="./SubDirectoryLinks" asp-antiforgery="false"></form>
|
||||||
<form method="post" asp-page="../../HelloWorld" asp-antiforgery="false"></form>
|
<form method="post" asp-page="../../HelloWorld" asp-antiforgery="false"></form>
|
||||||
<a asp-page="../Redirects/Index" asp-route-handler="RedirectToIndex" />
|
<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" />
|
||||||
Loading…
Reference in New Issue