diff --git a/src/Http/Http.Abstractions/src/PathString.cs b/src/Http/Http.Abstractions/src/PathString.cs
index 485f99b4cda8..15b5798fba9d 100644
--- a/src/Http/Http.Abstractions/src/PathString.cs
+++ b/src/Http/Http.Abstractions/src/PathString.cs
@@ -212,6 +212,12 @@ public static PathString FromUriComponent(Uri uri)
///
/// The to compare.
/// true if value matches the beginning of this string; otherwise, false.
+ ///
+ /// When the parameter contains a trailing slash, the being checked
+ /// must either exactly match or include a trailing slash. For instance, for a of "/a/b",
+ /// this method will return true for "/a", but will return false for "/a/".
+ /// Whereas, a of "/a//b/" will return true when compared with "/a/".
+ ///
public bool StartsWithSegments(PathString other)
{
return StartsWithSegments(other, StringComparison.OrdinalIgnoreCase);
@@ -224,6 +230,12 @@ public bool StartsWithSegments(PathString other)
/// The to compare.
/// One of the enumeration values that determines how this and value are compared.
/// true if value matches the beginning of this string; otherwise, false.
+ ///
+ /// When the parameter contains a trailing slash, the being checked
+ /// must either exactly match or include a trailing slash. For instance, for a of "/a/b",
+ /// this method will return true for "/a", but will return false for "/a/".
+ /// Whereas, a of "/a//b/" will return true when compared with "/a/".
+ ///
public bool StartsWithSegments(PathString other, StringComparison comparisonType)
{
var value1 = Value ?? string.Empty;
@@ -242,6 +254,12 @@ public bool StartsWithSegments(PathString other, StringComparison comparisonType
/// The to compare.
/// The remaining segments after the match.
/// true if value matches the beginning of this string; otherwise, false.
+ ///
+ /// When the parameter contains a trailing slash, the being checked
+ /// must either exactly match or include a trailing slash. For instance, for a of "/a/b",
+ /// this method will return true for "/a", but will return false for "/a/".
+ /// Whereas, a of "/a//b/" will return true when compared with "/a/".
+ ///
public bool StartsWithSegments(PathString other, out PathString remaining)
{
return StartsWithSegments(other, StringComparison.OrdinalIgnoreCase, out remaining);
@@ -255,6 +273,12 @@ public bool StartsWithSegments(PathString other, out PathString remaining)
/// One of the enumeration values that determines how this and value are compared.
/// The remaining segments after the match.
/// true if value matches the beginning of this string; otherwise, false.
+ ///
+ /// When the parameter contains a trailing slash, the being checked
+ /// must either exactly match or include a trailing slash. For instance, for a of "/a/b",
+ /// this method will return true for "/a", but will return false for "/a/".
+ /// Whereas, a of "/a//b/" will return true when compared with "/a/".
+ ///
public bool StartsWithSegments(PathString other, StringComparison comparisonType, out PathString remaining)
{
var value1 = Value ?? string.Empty;
@@ -279,6 +303,12 @@ public bool StartsWithSegments(PathString other, StringComparison comparisonType
/// The matched segments with the original casing in the source value.
/// The remaining segments after the match.
/// true if value matches the beginning of this string; otherwise, false.
+ ///
+ /// When the parameter contains a trailing slash, the being checked
+ /// must either exactly match or include a trailing slash. For instance, for a of "/a/b",
+ /// this method will return true for "/a", but will return false for "/a/".
+ /// Whereas, a of "/a//b/" will return true when compared with "/a/".
+ ///
public bool StartsWithSegments(PathString other, out PathString matched, out PathString remaining)
{
return StartsWithSegments(other, StringComparison.OrdinalIgnoreCase, out matched, out remaining);
@@ -293,6 +323,12 @@ public bool StartsWithSegments(PathString other, out PathString matched, out Pat
/// The matched segments with the original casing in the source value.
/// The remaining segments after the match.
/// true if value matches the beginning of this string; otherwise, false.
+ ///
+ /// When the parameter contains a trailing slash, the being checked
+ /// must either exactly match or include a trailing slash. For instance, for a of "/a/b",
+ /// this method will return true for "/a", but will return false for "/a/".
+ /// Whereas, a of "/a//b/" will return true when compared with "/a/".
+ ///
public bool StartsWithSegments(PathString other, StringComparison comparisonType, out PathString matched, out PathString remaining)
{
var value1 = Value ?? string.Empty;
diff --git a/src/Http/Http.Abstractions/test/PathStringTests.cs b/src/Http/Http.Abstractions/test/PathStringTests.cs
index b45278c3977c..7b1ec3782e97 100644
--- a/src/Http/Http.Abstractions/test/PathStringTests.cs
+++ b/src/Http/Http.Abstractions/test/PathStringTests.cs
@@ -126,6 +126,22 @@ public void StartsWithSegments_DoesACaseInsensitiveMatch(string sourcePath, stri
Assert.Equal(expectedResult, result);
}
+ [Theory]
+ [InlineData("/a/", "/a/", true)]
+ [InlineData("/a/b", "/a/", false)]
+ [InlineData("/a/b/", "/a/", false)]
+ [InlineData("/a//b", "/a/", true)]
+ [InlineData("/a//b/", "/a/", true)]
+ public void StartsWithSegments_DoesMatchExactPathOrPathWithExtraTrailingSlash(string sourcePath, string testPath, bool expectedResult)
+ {
+ var source = new PathString(sourcePath);
+ var test = new PathString(testPath);
+
+ var result = source.StartsWithSegments(test);
+
+ Assert.Equal(expectedResult, result);
+ }
+
[Theory]
[InlineData("/test/path", "/TEST", true)]
[InlineData("/test/path", "/TEST/pa", false)]
@@ -142,6 +158,22 @@ public void StartsWithSegmentsWithRemainder_DoesACaseInsensitiveMatch(string sou
Assert.Equal(expectedResult, result);
}
+ [Theory]
+ [InlineData("/a/", "/a/", true)]
+ [InlineData("/a/b", "/a/", false)]
+ [InlineData("/a/b/", "/a/", false)]
+ [InlineData("/a//b", "/a/", true)]
+ [InlineData("/a//b/", "/a/", true)]
+ public void StartsWithSegmentsWithRemainder_DoesMatchExactPathOrPathWithExtraTrailingSlash(string sourcePath, string testPath, bool expectedResult)
+ {
+ var source = new PathString(sourcePath);
+ var test = new PathString(testPath);
+
+ var result = source.StartsWithSegments(test, out var remaining);
+
+ Assert.Equal(expectedResult, result);
+ }
+
[Theory]
[InlineData("/test/path", "/TEST", StringComparison.OrdinalIgnoreCase, true)]
[InlineData("/test/path", "/TEST", StringComparison.Ordinal, false)]
@@ -163,6 +195,27 @@ public void StartsWithSegments_DoesMatchUsingSpecifiedComparison(string sourcePa
Assert.Equal(expectedResult, result);
}
+ [Theory]
+ [InlineData("/a/", "/a/", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("/a/", "/a/", StringComparison.Ordinal, true)]
+ [InlineData("/a/b", "/a/", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("/a/b", "/a/", StringComparison.Ordinal, false)]
+ [InlineData("/a/b/", "/a/", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("/a/b/", "/a/", StringComparison.Ordinal, false)]
+ [InlineData("/a//b", "/a/", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("/a//b", "/a/", StringComparison.Ordinal, true)]
+ [InlineData("/a//b/", "/a/", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("/a//b/", "/a/", StringComparison.Ordinal, true)]
+ public void StartsWithSegments_DoesMatchExactPathOrPathWithExtraTrailingSlashUsingSpecifiedComparison(string sourcePath, string testPath, StringComparison comparison, bool expectedResult)
+ {
+ var source = new PathString(sourcePath);
+ var test = new PathString(testPath);
+
+ var result = source.StartsWithSegments(test, comparison);
+
+ Assert.Equal(expectedResult, result);
+ }
+
[Theory]
[InlineData("/test/path", "/TEST", StringComparison.OrdinalIgnoreCase, true)]
[InlineData("/test/path", "/TEST", StringComparison.Ordinal, false)]
@@ -184,6 +237,27 @@ public void StartsWithSegmentsWithRemainder_DoesMatchUsingSpecifiedComparison(st
Assert.Equal(expectedResult, result);
}
+ [Theory]
+ [InlineData("/a/", "/a/", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("/a/", "/a/", StringComparison.Ordinal, true)]
+ [InlineData("/a/b", "/a/", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("/a/b", "/a/", StringComparison.Ordinal, false)]
+ [InlineData("/a/b/", "/a/", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("/a/b/", "/a/", StringComparison.Ordinal, false)]
+ [InlineData("/a//b", "/a/", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("/a//b", "/a/", StringComparison.Ordinal, true)]
+ [InlineData("/a//b/", "/a/", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("/a//b/", "/a/", StringComparison.Ordinal, true)]
+ public void StartsWithSegmentsWithRemainder_DoesMatchExactPathOrPathWithExtraTrailingSlashUsingSpecifiedComparison(string sourcePath, string testPath, StringComparison comparison, bool expectedResult)
+ {
+ var source = new PathString(sourcePath);
+ var test = new PathString(testPath);
+
+ var result = source.StartsWithSegments(test, comparison, out var remaining);
+
+ Assert.Equal(expectedResult, result);
+ }
+
[Theory]
// unreserved
[InlineData("/abc123.-_~", "/abc123.-_~")]