The 'api/files?physical_path={value}' endpoint now returns a single resource. Added better support for physical paths using the alternate directory separator character.
This commit is contained in:
Родитель
658f98cf5e
Коммит
a1a5b1dd76
|
@ -39,12 +39,11 @@ namespace Microsoft.IIS.Administration.Files
|
|||
|
||||
public IEnumerable<string> GetClaims(string path)
|
||||
{
|
||||
var absolutePath = PathUtil.GetFullPath(path);
|
||||
var claims = new List<string>();
|
||||
|
||||
//
|
||||
// Path must be absolute with no environment variables
|
||||
if (!absolutePath.Equals(path, StringComparison.OrdinalIgnoreCase)) {
|
||||
if (!PathUtil.IsFullPath(path)) {
|
||||
return claims;
|
||||
}
|
||||
|
||||
|
@ -52,7 +51,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
// Best match
|
||||
foreach (var location in Options.Locations) {
|
||||
|
||||
if (PathUtil.PathStartsWith(absolutePath, location.Path)) {
|
||||
if (HasPrefix(path, location.Path)) {
|
||||
|
||||
claims = location.Claims;
|
||||
|
||||
|
@ -62,5 +61,35 @@ namespace Microsoft.IIS.Administration.Files
|
|||
|
||||
return claims;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static bool HasPrefix(string path, string prefix)
|
||||
{
|
||||
//
|
||||
// Remove trailing separator (if any) from prefix
|
||||
if (prefix.Length > 0 && prefix.LastIndexOfAny(PathUtil.SEPARATORS) == prefix.Length - 1) {
|
||||
prefix = prefix.Substring(0, prefix.Length - 1);
|
||||
}
|
||||
|
||||
if (prefix.Length > path.Length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var testParts = path.Split(PathUtil.SEPARATORS);
|
||||
var prefixParts = prefix.Split(PathUtil.SEPARATORS);
|
||||
|
||||
if (prefixParts.Length > testParts.Length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < prefixParts.Length; i++) {
|
||||
if (!prefixParts[i].Equals(testParts[i], StringComparison.OrdinalIgnoreCase)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,9 @@ namespace Microsoft.IIS.Administration.Files
|
|||
|
||||
public class FilesController : ApiBaseController
|
||||
{
|
||||
private const string nameKey = "name";
|
||||
private const string physicalPathKey = "physical_path";
|
||||
|
||||
IFileOptions _options;
|
||||
IFileProvider _provider = FileProvider.Default;
|
||||
|
||||
|
@ -29,18 +32,22 @@ namespace Microsoft.IIS.Administration.Files
|
|||
public object Get()
|
||||
{
|
||||
string parentUuid = Context.Request.Query[Defines.PARENT_IDENTIFIER];
|
||||
string name = Context.Request.Query["name"];
|
||||
string physicalPath = Context.Request.Query["physical_path"];
|
||||
string name = Context.Request.Query[nameKey];
|
||||
string physicalPath = Context.Request.Query[physicalPathKey];
|
||||
|
||||
var files = new List<object>();
|
||||
Fields fields = Context.Request.GetFields();
|
||||
|
||||
if (!string.IsNullOrEmpty(name)) {
|
||||
if (name.IndexOfAny(PathUtil.InvalidFileNameChars) != -1) {
|
||||
throw new ApiArgumentException("name");
|
||||
throw new ApiArgumentException(nameKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (physicalPath != null) {
|
||||
return GetByPhysicalPath(physicalPath, fields);
|
||||
}
|
||||
|
||||
if (parentUuid != null) {
|
||||
var fileId = FileId.FromUuid(parentUuid);
|
||||
|
||||
|
@ -50,9 +57,6 @@ namespace Microsoft.IIS.Administration.Files
|
|||
|
||||
FillWithChildren(files, fileId.PhysicalPath, $"*{name}*", fields);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(physicalPath)) {
|
||||
FillFromPhysicalPath(files, physicalPath, fields);
|
||||
}
|
||||
else {
|
||||
FillFromLocations(files, name, fields);
|
||||
}
|
||||
|
@ -204,6 +208,41 @@ namespace Microsoft.IIS.Administration.Files
|
|||
|
||||
|
||||
|
||||
private object GetByPhysicalPath(string physicalPath, Fields fields)
|
||||
{
|
||||
if (string.IsNullOrEmpty(physicalPath)) {
|
||||
throw new ApiArgumentException(physicalPathKey);
|
||||
}
|
||||
|
||||
physicalPath = System.Environment.ExpandEnvironmentVariables(physicalPath);
|
||||
|
||||
if (!PathUtil.IsPathRooted(physicalPath)) {
|
||||
throw new ApiArgumentException(physicalPathKey);
|
||||
}
|
||||
|
||||
try {
|
||||
physicalPath = PathUtil.GetFullPath(physicalPath);
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
throw new ApiArgumentException(physicalPathKey);
|
||||
}
|
||||
|
||||
object model = null;
|
||||
|
||||
if (_provider.FileExists(physicalPath)) {
|
||||
model = FilesHelper.FileToJsonModel(_provider.GetFileInfo(physicalPath), fields);
|
||||
}
|
||||
else if (_provider.DirectoryExists(physicalPath)) {
|
||||
model = FilesHelper.DirectoryToJsonModel(_provider.GetDirectoryInfo(physicalPath), fields);
|
||||
}
|
||||
|
||||
if (model == null) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private void FillWithChildren(List<object> models, string physicalPath, string nameFilter, Fields fields)
|
||||
{
|
||||
//
|
||||
|
@ -219,16 +258,6 @@ namespace Microsoft.IIS.Administration.Files
|
|||
}
|
||||
}
|
||||
|
||||
private void FillFromPhysicalPath(List<object> models, string physicalPath, Fields fields)
|
||||
{
|
||||
if (_provider.FileExists(physicalPath)) {
|
||||
models.Add(FilesHelper.FileToJsonModelRef(_provider.GetFileInfo(physicalPath), fields));
|
||||
}
|
||||
else if (_provider.DirectoryExists(physicalPath)) {
|
||||
models.Add(FilesHelper.DirectoryToJsonModelRef(_provider.GetDirectoryInfo(physicalPath), fields));
|
||||
}
|
||||
}
|
||||
|
||||
private void FillFromLocations(List<object> models, string nameFilter, Fields fields)
|
||||
{
|
||||
foreach (var location in _options.Locations) {
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
|
||||
var expanded = Environment.ExpandEnvironmentVariables(path);
|
||||
|
||||
if (!Path.IsPathRooted(expanded)) {
|
||||
if (!IsPathRooted(expanded)) {
|
||||
throw new ArgumentException("Path must be rooted.", nameof(path));
|
||||
}
|
||||
|
||||
|
@ -43,74 +43,45 @@ namespace Microsoft.IIS.Administration.Files
|
|||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
//
|
||||
// Expand to make sure the path is rooted before calling GetFullPath
|
||||
var expanded = Environment.ExpandEnvironmentVariables(path);
|
||||
|
||||
if (!Path.IsPathRooted(expanded)) {
|
||||
if (!IsPathRooted(expanded)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return path.Equals(Path.GetFullPath(expanded), StringComparison.OrdinalIgnoreCase);
|
||||
bool ret = false;
|
||||
try {
|
||||
ret = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)
|
||||
.Equals(Path.GetFullPath(expanded), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
//
|
||||
// Argument exception for invalid paths such as '////' (Invalid network share format)
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int PrefixSegments(string prefix, string path, StringComparison stringComparison = StringComparison.OrdinalIgnoreCase)
|
||||
{
|
||||
if (prefix == null) {
|
||||
throw new ArgumentNullException(nameof(prefix));
|
||||
return ret;
|
||||
}
|
||||
if (path == null) {
|
||||
|
||||
public static bool IsPathRooted(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) {
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
if (!Path.IsPathRooted(prefix) || !Path.IsPathRooted(path)) {
|
||||
throw new ArgumentException("Paths must be rooted.");
|
||||
|
||||
if (!Path.IsPathRooted(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var prefixParts = prefix.TrimEnd(SEPARATORS).Split(SEPARATORS);
|
||||
var pathParts = path.TrimEnd(SEPARATORS).Split(SEPARATORS);
|
||||
|
||||
if (prefixParts.Length > pathParts.Length) {
|
||||
return -1;
|
||||
// Prevent cases such as 'c:'
|
||||
if (path.IndexOfAny(SEPARATORS) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
while (pathParts.Length > index && prefixParts.Length > index && prefixParts[index].Equals(pathParts[index], stringComparison)) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (prefixParts.Length > index) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return index == 0 ? -1 : index;
|
||||
}
|
||||
|
||||
public static bool IsParentPath(string parent, string child)
|
||||
{
|
||||
var prefixSegments = PathUtil.PrefixSegments(parent, child);
|
||||
if (prefixSegments > 0 && NumberOfSegments(child) > NumberOfSegments(parent)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int NumberOfSegments(string path)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
if (!path.StartsWith("/")) {
|
||||
throw new ArgumentException("Path must begin with '/'.");
|
||||
}
|
||||
|
||||
return path.TrimEnd(SEPARATORS).Split(SEPARATORS).Length;
|
||||
}
|
||||
|
||||
public static string TrimStart(this string val, string prefix, StringComparison stringComparision = StringComparison.Ordinal)
|
||||
{
|
||||
if (val.StartsWith(prefix, stringComparision)) {
|
||||
val = val.Remove(0, prefix.Length);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public static string RemoveLastSegment(string path)
|
||||
{
|
||||
|
@ -127,37 +98,6 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return ret == "/" ? ret : ret.TrimEnd('/');
|
||||
}
|
||||
|
||||
public static bool PathStartsWith(string path, string prefix)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) {
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
if (string.IsNullOrEmpty(prefix)) {
|
||||
throw new ArgumentNullException(nameof(prefix));
|
||||
}
|
||||
|
||||
if (prefix.Length > path.Length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var separators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
|
||||
|
||||
var testParts = path.Split(separators);
|
||||
var prefixParts = prefix.TrimEnd(separators).Split(separators);
|
||||
|
||||
if (prefixParts.Length > testParts.Length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < prefixParts.Length; i++) {
|
||||
if (!prefixParts[i].Equals(testParts[i], StringComparison.OrdinalIgnoreCase)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidFileName(string name)
|
||||
{
|
||||
return !string.IsNullOrEmpty(name) &&
|
||||
|
|
|
@ -280,6 +280,7 @@ namespace Microsoft.IIS.Administration.WebServer.Applications
|
|||
|
||||
if (physicalPath != null) {
|
||||
|
||||
physicalPath = physicalPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var expanded = System.Environment.ExpandEnvironmentVariables(physicalPath);
|
||||
|
||||
if (!PathUtil.IsFullPath(expanded)) {
|
||||
|
@ -294,7 +295,7 @@ namespace Microsoft.IIS.Administration.WebServer.Applications
|
|||
|
||||
var rootVDir = app.VirtualDirectories["/"];
|
||||
if (rootVDir != null) {
|
||||
rootVDir.PhysicalPath = physicalPath.Replace('/', '\\');
|
||||
rootVDir.PhysicalPath = physicalPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Microsoft.IIS.Administration.WebServer.Compression
|
|||
|
||||
DynamicHelper.If((object) model.directory, v => {
|
||||
|
||||
v = v.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var expanded = System.Environment.ExpandEnvironmentVariables(v);
|
||||
|
||||
if (!PathUtil.IsFullPath(expanded)) {
|
||||
|
|
|
@ -314,7 +314,7 @@ namespace Microsoft.IIS.Administration.WebServer.Files
|
|||
Application parentApp = null;
|
||||
var maxMatch = 0;
|
||||
foreach (var app in site.Applications) {
|
||||
var matchingPrefix = PathUtil.PrefixSegments(app.Path, path);
|
||||
var matchingPrefix = PrefixSegments(app.Path, path);
|
||||
if (matchingPrefix > maxMatch) {
|
||||
parentApp = app;
|
||||
maxMatch = matchingPrefix;
|
||||
|
@ -339,7 +339,7 @@ namespace Microsoft.IIS.Administration.WebServer.Files
|
|||
var testPath = path.TrimStart(parentApp.Path.TrimEnd('/'), StringComparison.OrdinalIgnoreCase);
|
||||
testPath = testPath == string.Empty ? "/" : testPath;
|
||||
foreach (var vdir in parentApp.VirtualDirectories) {
|
||||
var matchingPrefix = PathUtil.PrefixSegments(vdir.Path, testPath);
|
||||
var matchingPrefix = PrefixSegments(vdir.Path, testPath);
|
||||
if (matchingPrefix > maxMatch) {
|
||||
parentVdir = vdir;
|
||||
maxMatch = matchingPrefix;
|
||||
|
@ -389,7 +389,17 @@ namespace Microsoft.IIS.Administration.WebServer.Files
|
|||
}
|
||||
}
|
||||
|
||||
var absolute = PathUtil.GetFullPath(path);
|
||||
string absolute = null;
|
||||
|
||||
try {
|
||||
absolute = PathUtil.GetFullPath(path);
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
//
|
||||
// Argument exception for invalid paths such as '////' (Invalid network share format)
|
||||
return false;
|
||||
}
|
||||
|
||||
var slashIndex = absolute.IndexOf(Path.DirectorySeparatorChar);
|
||||
if (!absolute.Substring(slashIndex, absolute.Length - slashIndex).Equals(path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar))) {
|
||||
return false;
|
||||
|
@ -482,5 +492,44 @@ namespace Microsoft.IIS.Administration.WebServer.Files
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static int PrefixSegments(string prefix, string path, StringComparison stringComparison = StringComparison.OrdinalIgnoreCase)
|
||||
{
|
||||
if (prefix == null) {
|
||||
throw new ArgumentNullException(nameof(prefix));
|
||||
}
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
if (!PathUtil.IsPathRooted(prefix) || !PathUtil.IsPathRooted(path)) {
|
||||
throw new ArgumentException("Paths must be rooted.");
|
||||
}
|
||||
|
||||
var prefixParts = prefix.TrimEnd(PathUtil.SEPARATORS).Split(PathUtil.SEPARATORS);
|
||||
var pathParts = path.TrimEnd(PathUtil.SEPARATORS).Split(PathUtil.SEPARATORS);
|
||||
|
||||
if (prefixParts.Length > pathParts.Length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
while (pathParts.Length > index && prefixParts.Length > index && prefixParts[index].Equals(pathParts[index], stringComparison)) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (prefixParts.Length > index) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return index == 0 ? -1 : index;
|
||||
}
|
||||
|
||||
private static string TrimStart(this string val, string prefix, StringComparison stringComparision = StringComparison.Ordinal)
|
||||
{
|
||||
if (val.StartsWith(prefix, stringComparision)) {
|
||||
val = val.Remove(0, prefix.Length);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
|
||||
DynamicHelper.If((object)model.directory, v => {
|
||||
|
||||
v = v.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var expanded = System.Environment.ExpandEnvironmentVariables(v);
|
||||
|
||||
if (!PathUtil.IsFullPath(expanded)) {
|
||||
|
|
|
@ -238,7 +238,7 @@ namespace Microsoft.IIS.Administration.WebServer.Logging
|
|||
CentralBinaryLogFile bFile = logSection.CentralBinaryLogFile;
|
||||
|
||||
DynamicHelper.If((object)bSettings.directory, v => {
|
||||
EnsureCanUseDirectory(v);
|
||||
EnsureCanUseDirectory(ref v);
|
||||
bFile.Directory = v;
|
||||
});
|
||||
|
||||
|
@ -256,7 +256,7 @@ namespace Microsoft.IIS.Administration.WebServer.Logging
|
|||
CentralW3CLogFile wFile = logSection.CentralW3CLogFile;
|
||||
|
||||
DynamicHelper.If((object)wSettings.directory, v => {
|
||||
EnsureCanUseDirectory(v);
|
||||
EnsureCanUseDirectory(ref v);
|
||||
wFile.Directory = v;
|
||||
});
|
||||
|
||||
|
@ -310,7 +310,7 @@ namespace Microsoft.IIS.Administration.WebServer.Logging
|
|||
dynamic siteSettings = model;
|
||||
|
||||
DynamicHelper.If((object)siteSettings.directory, v => {
|
||||
EnsureCanUseDirectory(v);
|
||||
EnsureCanUseDirectory(ref v);
|
||||
siteLogFile.Directory = v;
|
||||
});
|
||||
|
||||
|
@ -515,8 +515,9 @@ namespace Microsoft.IIS.Administration.WebServer.Logging
|
|||
|
||||
|
||||
|
||||
private static void EnsureCanUseDirectory(string path)
|
||||
private static void EnsureCanUseDirectory(ref string path)
|
||||
{
|
||||
path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var expanded = System.Environment.ExpandEnvironmentVariables(path);
|
||||
|
||||
if (!PathUtil.IsFullPath(expanded)) {
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
throw new ApiArgumentException("image");
|
||||
}
|
||||
|
||||
AssertCanUseImage(image);
|
||||
AssertCanUseImage(ref image);
|
||||
|
||||
var globalCollection = GetGlobalModulesCollection();
|
||||
|
||||
|
@ -294,7 +294,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
string image = DynamicHelper.Value(model.image);
|
||||
|
||||
if (image != null) {
|
||||
AssertCanUseImage(image);
|
||||
AssertCanUseImage(ref image);
|
||||
globalModule.Image = image;
|
||||
}
|
||||
|
||||
|
@ -552,8 +552,9 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
|
||||
|
||||
|
||||
private static void AssertCanUseImage(string path)
|
||||
private static void AssertCanUseImage(ref string path)
|
||||
{
|
||||
path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var expanded = System.Environment.ExpandEnvironmentVariables(path);
|
||||
|
||||
if (!PathUtil.IsFullPath(expanded)) {
|
||||
|
|
|
@ -377,6 +377,7 @@ namespace Microsoft.IIS.Administration.WebServer.Sites
|
|||
|
||||
if(physicalPath != null) {
|
||||
|
||||
physicalPath = physicalPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var expanded = System.Environment.ExpandEnvironmentVariables(physicalPath);
|
||||
|
||||
if (!PathUtil.IsFullPath(expanded)) {
|
||||
|
@ -396,7 +397,7 @@ namespace Microsoft.IIS.Administration.WebServer.Sites
|
|||
|
||||
if (rootVDir != null) {
|
||||
|
||||
rootVDir.PhysicalPath = physicalPath.Replace('/', '\\');
|
||||
rootVDir.PhysicalPath = physicalPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,6 +193,7 @@ namespace Microsoft.IIS.Administration.WebServer.VirtualDirectories
|
|||
|
||||
if(physicalPath != null) {
|
||||
|
||||
physicalPath = physicalPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
var expanded = System.Environment.ExpandEnvironmentVariables(physicalPath);
|
||||
|
||||
if (!PathUtil.IsFullPath(expanded)) {
|
||||
|
@ -205,7 +206,7 @@ namespace Microsoft.IIS.Administration.WebServer.VirtualDirectories
|
|||
throw new NotFoundException("physical_path");
|
||||
}
|
||||
|
||||
vdir.PhysicalPath = physicalPath.Replace('/', '\\');
|
||||
vdir.PhysicalPath = physicalPath;
|
||||
}
|
||||
|
||||
if (model.identity != null) {
|
||||
|
|
|
@ -92,15 +92,6 @@ namespace Microsoft.IIS.Administration.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsParentPath()
|
||||
{
|
||||
Assert.True(PathUtil.IsParentPath("/", "/a"));
|
||||
Assert.True(PathUtil.IsParentPath("/a/b", "/a/b/c"));
|
||||
Assert.False(PathUtil.IsParentPath("/", "/"));
|
||||
Assert.False(PathUtil.IsParentPath("/a/b", "/a/bc"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsExactVdirPath()
|
||||
{
|
||||
|
@ -221,29 +212,6 @@ namespace Microsoft.IIS.Administration.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PrefixSegments()
|
||||
{
|
||||
var path = "/";
|
||||
|
||||
Assert.Equal(PathUtil.PrefixSegments("/", path), 1);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/a", path), -1);
|
||||
|
||||
path = "/abc/def/ghi";
|
||||
|
||||
Assert.Equal(PathUtil.PrefixSegments("/", path), 1);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/abc", path), 2);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/abc/", path), 2);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/abcd/", path), -1);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/aBc/", path), 2);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/aBc/", path, StringComparison.Ordinal), -1);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/abc/def", path), 3);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/abc/def/", path), 3);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/abc/defg/", path), -1);
|
||||
Assert.Equal(PathUtil.PrefixSegments("/abca/def/", path), -1);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveLastSegment()
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче