Fix absolute path handling.
- Normalize paths to be absolute and to also use forward slashes. - Updated our `EnsureValidPath` method to be `NormalizeAndEnsureValidPath`. - Added tests to validate new `NormalizeAndEnsureValidPath`. - Updated existing tests to react to `NormalizeAndEnsureValidPath` correctly. #1106
This commit is contained in:
parent
72febdac64
commit
c07759996f
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
|
@ -25,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(root));
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
Root = root.TrimEnd('/', '\\');
|
Root = root.Replace('\\', '/').TrimEnd('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -36,10 +35,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override IEnumerable<RazorProjectItem> EnumerateItems(string basePath)
|
public override IEnumerable<RazorProjectItem> EnumerateItems(string basePath)
|
||||||
{
|
{
|
||||||
EnsureValidPath(basePath);
|
var absoluteBasePath = NormalizeAndEnsureValidPath(basePath);
|
||||||
|
|
||||||
Debug.Assert(basePath.StartsWith("/"));
|
|
||||||
var absoluteBasePath = Path.Combine(Root, basePath.Substring(1));
|
|
||||||
|
|
||||||
var directory = new DirectoryInfo(absoluteBasePath);
|
var directory = new DirectoryInfo(absoluteBasePath);
|
||||||
if (!directory.Exists)
|
if (!directory.Exists)
|
||||||
|
|
@ -53,17 +49,38 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
{
|
{
|
||||||
var relativePath = file.FullName.Substring(absoluteBasePath.Length).Replace(Path.DirectorySeparatorChar, '/');
|
var relativePath = file.FullName.Substring(absoluteBasePath.Length).Replace(Path.DirectorySeparatorChar, '/');
|
||||||
return new FileSystemRazorProjectItem(basePath, relativePath, file);
|
return new FileSystemRazorProjectItem(basePath, relativePath, file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override RazorProjectItem GetItem(string path)
|
public override RazorProjectItem GetItem(string path)
|
||||||
{
|
{
|
||||||
EnsureValidPath(path);
|
var absolutePath = NormalizeAndEnsureValidPath(path);
|
||||||
|
|
||||||
Debug.Assert(path.StartsWith("/"));
|
|
||||||
var absolutePath = Path.Combine(Root, path.Substring(1));
|
|
||||||
return new FileSystemRazorProjectItem("/", path, new FileInfo(absolutePath));
|
return new FileSystemRazorProjectItem("/", path, new FileInfo(absolutePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override string NormalizeAndEnsureValidPath(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
var absolutePath = path;
|
||||||
|
if (!absolutePath.StartsWith(Root, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (path[0] == '/' || path[0] == '\\')
|
||||||
|
{
|
||||||
|
path = path.Substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
absolutePath = Path.Combine(Root, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
absolutePath = absolutePath.Replace('\\', '/');
|
||||||
|
|
||||||
|
return absolutePath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual IEnumerable<RazorProjectItem> FindHierarchicalItems(string basePath, string path, string fileName)
|
public virtual IEnumerable<RazorProjectItem> FindHierarchicalItems(string basePath, string path, string fileName)
|
||||||
{
|
{
|
||||||
EnsureValidPath(basePath);
|
basePath = NormalizeAndEnsureValidPath(basePath);
|
||||||
EnsureValidPath(path);
|
path = NormalizeAndEnsureValidPath(path);
|
||||||
if (string.IsNullOrEmpty(fileName))
|
if (string.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(fileName));
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(fileName));
|
||||||
|
|
@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
/// Performs validation for paths passed to methods of <see cref="RazorProject"/>.
|
/// Performs validation for paths passed to methods of <see cref="RazorProject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path to validate.</param>
|
/// <param name="path">The path to validate.</param>
|
||||||
protected virtual void EnsureValidPath(string path)
|
protected virtual string NormalizeAndEnsureValidPath(string path)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
|
|
@ -120,6 +120,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
{
|
{
|
||||||
throw new ArgumentException(Resources.RazorProject_PathMustStartWithForwardSlash, nameof(path));
|
throw new ArgumentException(Resources.RazorProject_PathMustStartWithForwardSlash, nameof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
|
|
@ -12,6 +13,57 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
private static string TestFolder { get; } =
|
private static string TestFolder { get; } =
|
||||||
Path.Combine(TestProject.GetProjectDirectory(), "TestFiles", "FileSystemRazorProject");
|
Path.Combine(TestProject.GetProjectDirectory(), "TestFiles", "FileSystemRazorProject");
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(null)]
|
||||||
|
[InlineData("")]
|
||||||
|
public void NormalizeAndEnsureValidPath_ThrowsIfPathIsNullOrEmpty(string path)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var project = new TestFileSystemRazorProject("C:/some/test/path/root");
|
||||||
|
|
||||||
|
// Act and Assert
|
||||||
|
ExceptionAssert.ThrowsArgumentNullOrEmptyString(() => project.NormalizeAndEnsureValidPath(path), "path");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NormalizeAndEnsureValidPath_NormalizesToAbsolutePath()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var project = new TestFileSystemRazorProject("C:/some/test/path/root");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var absolutePath = project.NormalizeAndEnsureValidPath("file.cshtml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("C:/some/test/path/root/file.cshtml", absolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NormalizeAndEnsureValidPath_NormalizesToAbsolutePathWithoutForwardSlash()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var project = new TestFileSystemRazorProject("C:/some/test/path/root");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var absolutePath = project.NormalizeAndEnsureValidPath("/file.cshtml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("C:/some/test/path/root/file.cshtml", absolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NormalizeAndEnsureValidPath_NormalizesToForwardSlashes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var project = new TestFileSystemRazorProject(@"C:\some\test\path\root");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var absolutePath = project.NormalizeAndEnsureValidPath(@"something\file.cshtml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("C:/some/test/path/root/something/file.cshtml", absolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void EnumerateItems_DiscoversAllCshtmlFiles()
|
public void EnumerateItems_DiscoversAllCshtmlFiles()
|
||||||
{
|
{
|
||||||
|
|
@ -104,5 +156,14 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
// Assert
|
// Assert
|
||||||
Assert.False(file.Exists);
|
Assert.False(file.Exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestFileSystemRazorProject : FileSystemRazorProject
|
||||||
|
{
|
||||||
|
public TestFileSystemRazorProject(string root) : base(root)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public new string NormalizeAndEnsureValidPath(string path) => base.NormalizeAndEnsureValidPath(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,30 +11,43 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
{
|
{
|
||||||
public class RazorProjectTest
|
public class RazorProjectTest
|
||||||
{
|
{
|
||||||
|
[Fact]
|
||||||
|
public void NormalizeAndEnsureValidPath_DoesNotModifyPath()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var project = new TestRazorProject(new Dictionary<string, RazorProjectItem>());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var path = project.NormalizeAndEnsureValidPath("/Views/Home/Index.cshtml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/Views/Home/Index.cshtml", path);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null)]
|
[InlineData(null)]
|
||||||
[InlineData("")]
|
[InlineData("")]
|
||||||
public void EnsureValidPath_ThrowsIfPathIsNullOrEmpty(string path)
|
public void NormalizeAndEnsureValidPath_ThrowsIfPathIsNullOrEmpty(string path)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var project = new TestRazorProject(new Dictionary<string, RazorProjectItem>());
|
var project = new TestRazorProject(new Dictionary<string, RazorProjectItem>());
|
||||||
|
|
||||||
// Act and Assert
|
// Act and Assert
|
||||||
ExceptionAssert.ThrowsArgumentNullOrEmptyString(() => project.EnsureValidPath(path), "path");
|
ExceptionAssert.ThrowsArgumentNullOrEmptyString(() => project.NormalizeAndEnsureValidPath(path), "path");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("foo")]
|
[InlineData("foo")]
|
||||||
[InlineData("~/foo")]
|
[InlineData("~/foo")]
|
||||||
[InlineData("\\foo")]
|
[InlineData("\\foo")]
|
||||||
public void EnsureValidPath_ThrowsIfPathDoesNotStartWithForwardSlash(string path)
|
public void NormalizeAndEnsureValidPath_ThrowsIfPathDoesNotStartWithForwardSlash(string path)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var project = new TestRazorProject(new Dictionary<string, RazorProjectItem>());
|
var project = new TestRazorProject(new Dictionary<string, RazorProjectItem>());
|
||||||
|
|
||||||
// Act and Assert
|
// Act and Assert
|
||||||
ExceptionAssert.ThrowsArgument(
|
ExceptionAssert.ThrowsArgument(
|
||||||
() => project.EnsureValidPath(path),
|
() => project.NormalizeAndEnsureValidPath(path),
|
||||||
"path",
|
"path",
|
||||||
"Path must begin with a forward slash '/'.");
|
"Path must begin with a forward slash '/'.");
|
||||||
}
|
}
|
||||||
|
|
@ -338,7 +351,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public new void EnsureValidPath(string path) => base.EnsureValidPath(path);
|
public new string NormalizeAndEnsureValidPath(string path) => base.NormalizeAndEnsureValidPath(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue