Split IOHelper into platform specific versions
This commit is contained in:
@@ -21,6 +21,14 @@ namespace Umbraco.Core.IO
|
||||
/// <returns></returns>
|
||||
string MapPath(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the path has a root, and is considered fully qualified for the OS it is on
|
||||
/// See https://github.com/dotnet/runtime/blob/30769e8f31b20be10ca26e27ec279cd4e79412b9/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs#L281 for the .NET Standard 2.1 version of this
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check</param>
|
||||
/// <returns>True if the path is fully qualified, false otherwise</returns>
|
||||
bool IsPathFullyQualified(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the current filepath matches a directory where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
@@ -45,7 +53,7 @@ namespace Umbraco.Core.IO
|
||||
/// <returns>A value indicating whether the filepath is valid.</returns>
|
||||
bool VerifyFileExtension(string filePath, IEnumerable<string> validFileExtensions);
|
||||
|
||||
bool PathStartsWith(string path, string root, char separator);
|
||||
bool PathStartsWith(string path, string root, params char[] separators);
|
||||
|
||||
void EnsurePathExists(string path);
|
||||
|
||||
|
||||
@@ -4,12 +4,13 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
public class IOHelper : IIOHelper
|
||||
public abstract class IOHelper : IIOHelper
|
||||
{
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
|
||||
@@ -29,7 +30,7 @@ namespace Umbraco.Core.IO
|
||||
if (virtualPath.StartsWith("~"))
|
||||
retval = virtualPath.Replace("~", _hostingEnvironment.ApplicationVirtualPath);
|
||||
|
||||
if (virtualPath.StartsWith("/") && virtualPath.StartsWith(_hostingEnvironment.ApplicationVirtualPath) == false)
|
||||
if (virtualPath.StartsWith("/") && !PathStartsWith(virtualPath, _hostingEnvironment.ApplicationVirtualPath))
|
||||
retval = _hostingEnvironment.ApplicationVirtualPath + "/" + virtualPath.TrimStart('/');
|
||||
|
||||
return retval;
|
||||
@@ -64,19 +65,18 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
if (path == null) throw new ArgumentNullException(nameof(path));
|
||||
|
||||
// Check if the path is already mapped
|
||||
if ((path.Length >= 2 && path[1] == Path.VolumeSeparatorChar)
|
||||
|| path.StartsWith(@"\\")) //UNC Paths start with "\\". If the site is running off a network drive mapped paths will look like "\\Whatever\Boo\Bar"
|
||||
// Check if the path is already mapped - TODO: This should be switched to Path.IsPathFullyQualified once we are on Net Standard 2.1
|
||||
if (Path.IsPathRooted(path) &&
|
||||
(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || // Linux paths are fully qualified as long as they are rooted, Windows paths can be rooted but not fully qualified
|
||||
((path.Length >= 2 && path[1] == Path.VolumeSeparatorChar) || path.StartsWith(@"\\") //UNC Paths start with "\\". If the site is running off a network drive mapped paths will look like "\\Whatever\Boo\Bar"
|
||||
)))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
// Check that we even have an HttpContext! otherwise things will fail anyways
|
||||
// http://umbraco.codeplex.com/workitem/30946
|
||||
|
||||
|
||||
if (_hostingEnvironment.IsHosted)
|
||||
{
|
||||
var result = (!string.IsNullOrEmpty(path) && (path.StartsWith("~") || path.StartsWith(_hostingEnvironment.ApplicationVirtualPath)))
|
||||
var result = (!string.IsNullOrEmpty(path) && (path.StartsWith("~") || PathStartsWith(path, _hostingEnvironment.ApplicationVirtualPath)))
|
||||
? _hostingEnvironment.MapPathWebRoot(path)
|
||||
: _hostingEnvironment.MapPathWebRoot("~/" + path.TrimStart('/'));
|
||||
|
||||
@@ -91,6 +91,14 @@ namespace Umbraco.Core.IO
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the path has a root, and is considered fully qualified for the OS it is on
|
||||
/// See https://github.com/dotnet/runtime/blob/30769e8f31b20be10ca26e27ec279cd4e79412b9/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs#L281 for the .NET Standard 2.1 version of this
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check</param>
|
||||
/// <returns>True if the path is fully qualified, false otherwise</returns>
|
||||
public abstract bool IsPathFullyQualified(string path);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the current filepath matches a directory where the user is allowed to edit a file.
|
||||
@@ -121,7 +129,7 @@ namespace Umbraco.Core.IO
|
||||
// not going to fix everything today
|
||||
|
||||
var mappedRoot = MapPath(_hostingEnvironment.ApplicationVirtualPath);
|
||||
if (filePath.StartsWith(mappedRoot) == false)
|
||||
if (!PathStartsWith(filePath, mappedRoot))
|
||||
filePath = _hostingEnvironment.MapPathContentRoot(filePath);
|
||||
|
||||
// yes we can (see above)
|
||||
@@ -131,10 +139,10 @@ namespace Umbraco.Core.IO
|
||||
foreach (var dir in validDirs)
|
||||
{
|
||||
var validDir = dir;
|
||||
if (validDir.StartsWith(mappedRoot) == false)
|
||||
if (!PathStartsWith(validDir, mappedRoot))
|
||||
validDir = _hostingEnvironment.MapPathContentRoot(validDir);
|
||||
|
||||
if (PathStartsWith(filePath, validDir, Path.DirectorySeparatorChar))
|
||||
if (PathStartsWith(filePath, validDir))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -153,16 +161,7 @@ namespace Umbraco.Core.IO
|
||||
return ext != null && validFileExtensions.Contains(ext.TrimStart('.'));
|
||||
}
|
||||
|
||||
public bool PathStartsWith(string path, string root, char separator)
|
||||
{
|
||||
// either it is identical to root,
|
||||
// or it is root + separator + anything
|
||||
|
||||
if (path.StartsWith(root, StringComparison.OrdinalIgnoreCase) == false) return false;
|
||||
if (path.Length == root.Length) return true;
|
||||
if (path.Length < root.Length) return false;
|
||||
return path[root.Length] == separator;
|
||||
}
|
||||
public abstract bool PathStartsWith(string path, string root, params char[] separators);
|
||||
|
||||
public void EnsurePathExists(string path)
|
||||
{
|
||||
@@ -181,7 +180,7 @@ namespace Umbraco.Core.IO
|
||||
if (path.IsFullPath())
|
||||
{
|
||||
var rootDirectory = MapPath("~");
|
||||
var relativePath = path.ToLowerInvariant().Replace(rootDirectory.ToLowerInvariant(), string.Empty);
|
||||
var relativePath = PathStartsWith(path, rootDirectory) ? path.Substring(rootDirectory.Length) : path;
|
||||
path = relativePath;
|
||||
}
|
||||
|
||||
|
||||
28
src/Umbraco.Core/IO/IOHelperLinux.cs
Normal file
28
src/Umbraco.Core/IO/IOHelperLinux.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Hosting;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
public class IOHelperLinux : IOHelper
|
||||
{
|
||||
public IOHelperLinux(IHostingEnvironment hostingEnvironment) : base(hostingEnvironment)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsPathFullyQualified(string path) => Path.IsPathRooted(path);
|
||||
|
||||
public override bool PathStartsWith(string path, string root, params char[] separators)
|
||||
{
|
||||
// either it is identical to root,
|
||||
// or it is root + separator + anything
|
||||
|
||||
if (separators == null || separators.Length == 0) separators = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
|
||||
if (!path.StartsWith(root, StringComparison.Ordinal)) return false;
|
||||
if (path.Length == root.Length) return true;
|
||||
if (path.Length < root.Length) return false;
|
||||
return separators.Contains(path[root.Length]);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/Umbraco.Core/IO/IOHelperOSX.cs
Normal file
29
src/Umbraco.Core/IO/IOHelperOSX.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Hosting;
|
||||
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
public class IOHelperOSX : IOHelper
|
||||
{
|
||||
public IOHelperOSX(IHostingEnvironment hostingEnvironment) : base(hostingEnvironment)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsPathFullyQualified(string path) => Path.IsPathRooted(path);
|
||||
|
||||
public override bool PathStartsWith(string path, string root, params char[] separators)
|
||||
{
|
||||
// either it is identical to root,
|
||||
// or it is root + separator + anything
|
||||
|
||||
if (separators == null || separators.Length == 0) separators = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
|
||||
if (!path.StartsWith(root, StringComparison.OrdinalIgnoreCase)) return false;
|
||||
if (path.Length == root.Length) return true;
|
||||
if (path.Length < root.Length) return false;
|
||||
return separators.Contains(path[root.Length]);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/Umbraco.Core/IO/IOHelperWindows.cs
Normal file
55
src/Umbraco.Core/IO/IOHelperWindows.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Hosting;
|
||||
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
public class IOHelperWindows : IOHelper
|
||||
{
|
||||
public IOHelperWindows(IHostingEnvironment hostingEnvironment) : base(hostingEnvironment)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsPathFullyQualified(string path)
|
||||
{
|
||||
// TODO: This implementation is taken from the .NET Standard 2.1 implementation. We should switch to using Path.IsPathFullyQualified once we are on .NET Standard 2.1
|
||||
|
||||
if (path.Length < 2)
|
||||
{
|
||||
// It isn't fixed, it must be relative. There is no way to specify a fixed
|
||||
// path with one character (or less).
|
||||
return false;
|
||||
}
|
||||
|
||||
if (path[0] == Path.DirectorySeparatorChar || path[0] == Path.AltDirectorySeparatorChar)
|
||||
{
|
||||
// There is no valid way to specify a relative path with two initial slashes or
|
||||
// \? as ? isn't valid for drive relative paths and \??\ is equivalent to \\?\
|
||||
return path[1] == '?' || path[1] == Path.DirectorySeparatorChar || path[1] == Path.AltDirectorySeparatorChar;
|
||||
}
|
||||
|
||||
// The only way to specify a fixed path that doesn't begin with two slashes
|
||||
// is the drive, colon, slash format- i.e. C:\
|
||||
return (path.Length >= 3)
|
||||
&& (path[1] == Path.VolumeSeparatorChar)
|
||||
&& (path[2] == Path.DirectorySeparatorChar || path[2] == Path.AltDirectorySeparatorChar)
|
||||
// To match old behavior we'll check the drive character for validity as the path is technically
|
||||
// not qualified if you don't have a valid drive. "=:\" is the "=" file's default data stream.
|
||||
&& ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'));
|
||||
}
|
||||
|
||||
public override bool PathStartsWith(string path, string root, params char[] separators)
|
||||
{
|
||||
// either it is identical to root,
|
||||
// or it is root + separator + anything
|
||||
|
||||
if (separators == null || separators.Length == 0) separators = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
|
||||
if (!path.StartsWith(root, StringComparison.OrdinalIgnoreCase)) return false;
|
||||
if (path.Length == root.Length) return true;
|
||||
if (path.Length < root.Length) return false;
|
||||
return separators.Contains(path[root.Length]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ using Umbraco.Core.Strings;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Tests.Common.Builders;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Umbraco.Tests.Common
|
||||
{
|
||||
@@ -86,7 +87,11 @@ namespace Umbraco.Tests.Common
|
||||
get
|
||||
{
|
||||
if (_ioHelper == null)
|
||||
_ioHelper = new IOHelper(GetHostingEnvironment());
|
||||
{
|
||||
var hostingEnvironment = GetHostingEnvironment();
|
||||
_ioHelper = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? new IOHelperLinux(hostingEnvironment)
|
||||
: (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? (IIOHelper)new IOHelperOSX(hostingEnvironment) : new IOHelperWindows(hostingEnvironment));
|
||||
}
|
||||
return _ioHelper;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +373,8 @@ namespace Umbraco.Extensions
|
||||
throw new InvalidOperationException($"Could not resolve type {typeof(GlobalSettings)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}");
|
||||
|
||||
hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment);
|
||||
ioHelper = new IOHelper(hostingEnvironment);
|
||||
ioHelper = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? new IOHelperLinux(hostingEnvironment)
|
||||
: (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? (IIOHelper)new IOHelperOSX(hostingEnvironment) : new IOHelperWindows(hostingEnvironment));
|
||||
AddLogger(services, hostingEnvironment, loggingConfiguration, configuration);
|
||||
backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings);
|
||||
profiler = GetWebProfiler(hostingEnvironment);
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Umbraco.Web
|
||||
var hostingEnvironment = new AspNetHostingEnvironment(Options.Create(hostingSettings));
|
||||
var loggingConfiguration = new LoggingConfiguration(
|
||||
Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "App_Data\\Logs"));
|
||||
var ioHelper = new IOHelper(hostingEnvironment);
|
||||
var ioHelper = new IOHelperWindows(hostingEnvironment);
|
||||
var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration, new ConfigurationRoot(new List<IConfigurationProvider>()));
|
||||
|
||||
var backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, ioHelper, _loggerFactory.CreateLogger<AspNetBackOfficeInfo>(), Options.Create(webRoutingSettings));
|
||||
|
||||
Reference in New Issue
Block a user