Skip to content

Commit 3b2b9a0

Browse files
Normalize root paths and throw when not set
1 parent 36de016 commit 3b2b9a0

4 files changed

Lines changed: 79 additions & 47 deletions

File tree

src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,27 @@ public PhysicalFileSystemCache(
6464
/// <returns><see cref="string"/> representing the fully qualified cache root path.</returns>
6565
internal static string GetCacheRoot(PhysicalFileSystemCacheOptions cacheOptions, string webRootPath, string contentRootPath)
6666
{
67-
string cacheRoot = cacheOptions.CacheRootPath ?? webRootPath ?? "wwwroot";
67+
string cacheRootPath = cacheOptions.CacheRootPath ?? webRootPath;
68+
if (string.IsNullOrEmpty(cacheRootPath))
69+
{
70+
throw new InvalidOperationException("The cache root path can't be determined, make sure it's explicitly configured or the webroot is set.");
71+
}
72+
73+
if (!Path.IsPathFullyQualified(cacheRootPath))
74+
{
75+
// Ensure this is an absolute path (resolved to the content root path)
76+
cacheRootPath = Path.GetFullPath(cacheRootPath, contentRootPath);
77+
}
78+
79+
string cacheFolderPath = Path.Combine(cacheRootPath, cacheOptions.CacheFolder);
80+
81+
// Ensure directory exists
82+
if (!Directory.Exists(cacheFolderPath))
83+
{
84+
Directory.CreateDirectory(cacheFolderPath);
85+
}
6886

69-
return Path.IsPathFullyQualified(cacheRoot)
70-
? Path.Combine(cacheRoot, cacheOptions.CacheFolder)
71-
: Path.GetFullPath(Path.Combine(cacheRoot, cacheOptions.CacheFolder), contentRootPath);
87+
return PathUtils.EnsureTrailingSlash(cacheFolderPath);
7288
}
7389

7490
/// <inheritdoc/>

src/ImageSharp.Web/PathUtils.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.IO;
6+
7+
namespace SixLabors.ImageSharp.Web
8+
{
9+
internal static class PathUtils
10+
{
11+
/// <summary>
12+
/// Ensures the path ends with a trailing slash (directory separator).
13+
/// </summary>
14+
/// <param name="path">The path.</param>
15+
/// <returns>
16+
/// The path with a trailing slash.
17+
/// </returns>
18+
internal static string EnsureTrailingSlash(string path)
19+
{
20+
if (!string.IsNullOrEmpty(path) &&
21+
path[path.Length - 1] != Path.DirectorySeparatorChar)
22+
{
23+
return path + Path.DirectorySeparatorChar;
24+
}
25+
26+
return path;
27+
}
28+
29+
/// <summary>
30+
/// Determines whether the <paramref name="path" /> is located underneath the specified <paramref name="rootPath" />.
31+
/// </summary>
32+
/// <param name="path">The fully qualified path to test.</param>
33+
/// <param name="rootPath">The root path (needs to end with a directory separator).</param>
34+
/// <returns>
35+
/// <c>true</c> if the path is located underneath the specified root path; otherwise, <c>false</c>.
36+
/// </returns>
37+
internal static bool IsUnderneathRoot(string path, string rootPath)
38+
=> path.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase);
39+
}
40+
}

src/ImageSharp.Web/Providers/PhysicalFileSystemProvider.cs

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@ public PhysicalFileSystemProvider(
4747

4848
this.providerRootPath = GetProviderRoot(options.Value, environment.WebRootPath, environment.ContentRootPath);
4949
this.formatUtilities = formatUtilities;
50-
51-
// Disable provider by default when no root path is configured or webroot doesn't exist
52-
if (this.providerRootPath == null)
53-
{
54-
this.Match = _ => false;
55-
}
5650
}
5751

5852
/// <inheritdoc/>
@@ -70,7 +64,7 @@ public Task<IImageResolver> GetAsync(HttpContext context)
7064
{
7165
// Use Join because request path starts with a slash
7266
string fullPath = Path.GetFullPath(Path.Join(this.providerRootPath, context.Request.Path.Value));
73-
if (fullPath.StartsWith(this.providerRootPath, StringComparison.OrdinalIgnoreCase))
67+
if (PathUtils.IsUnderneathRoot(fullPath, this.providerRootPath))
7468
{
7569
// Check to see if the file exists
7670
var fileInfo = new FileInfo(fullPath);
@@ -94,42 +88,24 @@ public Task<IImageResolver> GetAsync(HttpContext context)
9488
internal static string GetProviderRoot(PhysicalFileSystemProviderOptions providerOptions, string webRootPath, string contentRootPath)
9589
{
9690
string providerRootPath = providerOptions.ProviderRootPath ?? webRootPath;
97-
if (providerRootPath == null)
91+
if (string.IsNullOrEmpty(providerRootPath))
9892
{
99-
// Default to /wwwroot if it exists
100-
string wwwroot = Path.Combine(contentRootPath, "wwwroot");
101-
if (Directory.Exists(wwwroot))
102-
{
103-
providerRootPath = wwwroot;
104-
}
93+
throw new InvalidOperationException("The provider root path can't be determined, make sure it's explicitly configured or the webroot is set.");
10594
}
10695

107-
if (!string.IsNullOrEmpty(providerRootPath))
96+
if (!Path.IsPathFullyQualified(providerRootPath))
10897
{
109-
string fullPath = Path.IsPathFullyQualified(providerRootPath)
110-
? providerRootPath
111-
: Path.GetFullPath(providerRootPath, contentRootPath);
112-
113-
if (!Directory.Exists(fullPath))
114-
{
115-
Directory.CreateDirectory(fullPath);
116-
}
117-
118-
return EnsureTrailingSlash(fullPath);
98+
// Ensure this is an absolute path (resolved to the content root path)
99+
providerRootPath = Path.GetFullPath(providerRootPath, contentRootPath);
119100
}
120101

121-
return null;
122-
}
123-
124-
internal static string EnsureTrailingSlash(string path)
125-
{
126-
if (!string.IsNullOrEmpty(path) &&
127-
path[path.Length - 1] != Path.DirectorySeparatorChar)
102+
// Ensure directory exists
103+
if (!Directory.Exists(providerRootPath))
128104
{
129-
return path + Path.DirectorySeparatorChar;
105+
Directory.CreateDirectory(providerRootPath);
130106
}
131107

132-
return path;
108+
return PathUtils.EnsureTrailingSlash(providerRootPath);
133109
}
134110
}
135111
}

tests/ImageSharp.Web.Tests/Caching/PhysicialFileSystemCacheTests.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@ public void FilePathMatchesReference(string key, int cacheFolderDepth, string ex
2323

2424
[Theory]
2525
#if OS_LINUX
26-
[InlineData("cacheFolder", "/Users/username", null, null, "/Users/username/cacheFolder")]
27-
[InlineData("cacheFolder", null, "/Users/WebRoot", null, "/Users/WebRoot/cacheFolder")]
28-
[InlineData("cacheFolder", "../Temp", null, "/Users/this/a/root", "/Users/this/a/Temp/cacheFolder")]
26+
[InlineData("cacheFolder", "/Users/username", null, null, "/Users/username/cacheFolder/")]
27+
[InlineData("cacheFolder", null, "/Users/WebRoot", null, "/Users/WebRoot/cacheFolder/")]
28+
[InlineData("cacheFolder", "../Temp", null, "/Users/this/a/root", "/Users/this/a/Temp/cacheFolder/")]
2929
#elif OS_OSX
30-
[InlineData("cacheFolder", "/Users/username", null, null, "/Users/username/cacheFolder")]
31-
[InlineData("cacheFolder", null, "/Users/WebRoot", null, "/Users/WebRoot/cacheFolder")]
32-
[InlineData("cacheFolder", "../Temp", null, "/Users/this/a/root", "/Users/this/a/Temp/cacheFolder")]
30+
[InlineData("cacheFolder", "/Users/username", null, null, "/Users/username/cacheFolder/")]
31+
[InlineData("cacheFolder", null, "/Users/WebRoot", null, "/Users/WebRoot/cacheFolder/")]
32+
[InlineData("cacheFolder", "../Temp", null, "/Users/this/a/root", "/Users/this/a/Temp/cacheFolder/")]
3333
#elif OS_WINDOWS
34-
[InlineData("cacheFolder", "C:/Temp", null, null, "C:/Temp\\cacheFolder")]
35-
[InlineData("cacheFolder", null, "C:/WebRoot", null, "C:/WebRoot\\cacheFolder")]
36-
[InlineData("cacheFolder", "../Temp", null, "C:/this/a/root", "C:\\this\\a\\Temp\\cacheFolder")]
34+
[InlineData("cacheFolder", "C:/Temp", null, null, "C:/Temp\\cacheFolder\\")]
35+
[InlineData("cacheFolder", null, "C:/WebRoot", null, "C:/WebRoot\\cacheFolder\\")]
36+
[InlineData("cacheFolder", "../Temp", null, "C:/this/a/root", "C:\\this\\a\\Temp\\cacheFolder\\")]
3737
#endif
3838
public void CacheRootFromOptions(string cacheFolder, string cacheRoot, string webRootPath, string contentRootPath, string expected)
3939
{

0 commit comments

Comments
 (0)