Added overload to PathString.StartsWithSegments to allow specifying StringComparison:
- This allows us to have a fast-path (or just be more explicit) for the comparison by doing case-sensitive checks (which are cheaper)
This commit is contained in:
parent
61466af7a3
commit
8ecb147332
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Http
|
||||||
/// <param name="value">The unescaped path to be assigned to the Value property.</param>
|
/// <param name="value">The unescaped path to be assigned to the Value property.</param>
|
||||||
public PathString(string value)
|
public PathString(string value)
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrEmpty(value) && value[0] != '/')
|
if (!string.IsNullOrEmpty(value) && value[0] != '/')
|
||||||
{
|
{
|
||||||
throw new ArgumentException(""/*Resources.Exception_PathMustStartWithSlash*/, nameof(value));
|
throw new ArgumentException(""/*Resources.Exception_PathMustStartWithSlash*/, nameof(value));
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Http
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasValue
|
public bool HasValue
|
||||||
{
|
{
|
||||||
get { return !String.IsNullOrEmpty(_value); }
|
get { return !string.IsNullOrEmpty(_value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -98,23 +98,61 @@ namespace Microsoft.AspNet.Http
|
||||||
return new PathString("/" + uri.GetComponents(UriComponents.Path, UriFormat.Unescaped));
|
return new PathString("/" + uri.GetComponents(UriComponents.Path, UriFormat.Unescaped));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the beginning of this <see cref="PathString"/> instance matches the specified <see cref="PathString"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The <see cref="PathString"/> to compare.</param>
|
||||||
|
/// <returns>true if value matches the beginning of this string; otherwise, false.</returns>
|
||||||
public bool StartsWithSegments(PathString other)
|
public bool StartsWithSegments(PathString other)
|
||||||
{
|
{
|
||||||
string value1 = Value ?? String.Empty;
|
return StartsWithSegments(other, StringComparison.OrdinalIgnoreCase);
|
||||||
string value2 = other.Value ?? String.Empty;
|
}
|
||||||
if (value1.StartsWith(value2, StringComparison.OrdinalIgnoreCase))
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the beginning of this <see cref="PathString"/> instance matches the specified <see cref="PathString"/> when compared
|
||||||
|
/// using the specified comparison option.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The <see cref="PathString"/> to compare.</param>
|
||||||
|
/// <param name="comparisonType">One of the enumeration values that determines how this <see cref="PathString"/> and value are compared.</param>
|
||||||
|
/// <returns>true if value matches the beginning of this string; otherwise, false.</returns>
|
||||||
|
public bool StartsWithSegments(PathString other, StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
var value1 = Value ?? string.Empty;
|
||||||
|
var value2 = other.Value ?? string.Empty;
|
||||||
|
if (value1.StartsWith(value2, comparisonType))
|
||||||
{
|
{
|
||||||
return value1.Length == value2.Length || value1[value2.Length] == '/';
|
return value1.Length == value2.Length || value1[value2.Length] == '/';
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the beginning of this PathString instance matches the specified <see cref="PathString"/> when compared
|
||||||
|
/// using the specified comparison option and returns the remaining segments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The <see cref="PathString"/> to compare.</param>
|
||||||
|
/// <param name="remaining">The remaining segments after the match.</param>
|
||||||
|
/// <returns>true if value matches the beginning of this string; otherwise, false.</returns>
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Secondary information needed after boolean result obtained")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Secondary information needed after boolean result obtained")]
|
||||||
public bool StartsWithSegments(PathString other, out PathString remaining)
|
public bool StartsWithSegments(PathString other, out PathString remaining)
|
||||||
{
|
{
|
||||||
string value1 = Value ?? String.Empty;
|
return StartsWithSegments(other, StringComparison.OrdinalIgnoreCase, out remaining);
|
||||||
string value2 = other.Value ?? String.Empty;
|
}
|
||||||
if (value1.StartsWith(value2, StringComparison.OrdinalIgnoreCase))
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the beginning of this <see cref="PathString"/> instance matches the specified <see cref="PathString"/> and returns
|
||||||
|
/// the remaining segments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The <see cref="PathString"/> to compare.</param>
|
||||||
|
/// <param name="comparisonType">One of the enumeration values that determines how this <see cref="PathString"/> and value are compared.</param>
|
||||||
|
/// <param name="remaining">The remaining segments after the match.</param>
|
||||||
|
/// <returns>true if value matches the beginning of this string; otherwise, false.</returns>
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Secondary information needed after boolean result obtained")]
|
||||||
|
public bool StartsWithSegments(PathString other, StringComparison comparisonType, out PathString remaining)
|
||||||
|
{
|
||||||
|
var value1 = Value ?? string.Empty;
|
||||||
|
var value2 = other.Value ?? string.Empty;
|
||||||
|
if (value1.StartsWith(value2, comparisonType))
|
||||||
{
|
{
|
||||||
if (value1.Length == value2.Length || value1[value2.Length] == '/')
|
if (value1.Length == value2.Length || value1[value2.Length] == '/')
|
||||||
{
|
{
|
||||||
|
|
@ -278,7 +316,7 @@ namespace Microsoft.AspNet.Http
|
||||||
/// Implicitly calls ToString().
|
/// Implicitly calls ToString().
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path"></param>
|
/// <param name="path"></param>
|
||||||
public static implicit operator string(PathString path)
|
public static implicit operator string (PathString path)
|
||||||
{
|
{
|
||||||
return path.ToString();
|
return path.ToString();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -70,5 +71,81 @@ namespace Microsoft.AspNet.Http
|
||||||
result = path + "text";
|
result = path + "text";
|
||||||
Assert.Equal("/pathtext", result);
|
Assert.Equal("/pathtext", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("/test/path", "/TEST", true)]
|
||||||
|
[InlineData("/test/path", "/TEST/pa", false)]
|
||||||
|
[InlineData("/TEST/PATH", "/test", true)]
|
||||||
|
[InlineData("/TEST/path", "/test/pa", false)]
|
||||||
|
[InlineData("/test/PATH/path/TEST", "/TEST/path/PATH", true)]
|
||||||
|
public void StartsWithSegments_DoesACaseInsensitiveMatch(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)]
|
||||||
|
[InlineData("/TEST/PATH", "/test", true)]
|
||||||
|
[InlineData("/TEST/path", "/test/pa", false)]
|
||||||
|
[InlineData("/test/PATH/path/TEST", "/TEST/path/PATH", true)]
|
||||||
|
public void StartsWithSegmentsWithRemainder_DoesACaseInsensitiveMatch(string sourcePath, string testPath, bool expectedResult)
|
||||||
|
{
|
||||||
|
var source = new PathString(sourcePath);
|
||||||
|
var test = new PathString(testPath);
|
||||||
|
|
||||||
|
PathString remaining;
|
||||||
|
var result = source.StartsWithSegments(test, out remaining);
|
||||||
|
|
||||||
|
Assert.Equal(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("/test/path", "/TEST", StringComparison.OrdinalIgnoreCase, true)]
|
||||||
|
[InlineData("/test/path", "/TEST", StringComparison.Ordinal, false)]
|
||||||
|
[InlineData("/test/path", "/TEST/pa", StringComparison.OrdinalIgnoreCase, false)]
|
||||||
|
[InlineData("/test/path", "/TEST/pa", StringComparison.Ordinal, false)]
|
||||||
|
[InlineData("/TEST/PATH", "/test", StringComparison.OrdinalIgnoreCase, true)]
|
||||||
|
[InlineData("/TEST/PATH", "/test", StringComparison.Ordinal, false)]
|
||||||
|
[InlineData("/TEST/path", "/test/pa", StringComparison.OrdinalIgnoreCase, false)]
|
||||||
|
[InlineData("/TEST/path", "/test/pa", StringComparison.Ordinal, false)]
|
||||||
|
[InlineData("/test/PATH/path/TEST", "/TEST/path/PATH", StringComparison.OrdinalIgnoreCase, true)]
|
||||||
|
[InlineData("/test/PATH/path/TEST", "/TEST/path/PATH", StringComparison.Ordinal, false)]
|
||||||
|
public void StartsWithSegments_DoesMatchUsingSpecifiedComparison(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)]
|
||||||
|
[InlineData("/test/path", "/TEST/pa", StringComparison.OrdinalIgnoreCase, false)]
|
||||||
|
[InlineData("/test/path", "/TEST/pa", StringComparison.Ordinal, false)]
|
||||||
|
[InlineData("/TEST/PATH", "/test", StringComparison.OrdinalIgnoreCase, true)]
|
||||||
|
[InlineData("/TEST/PATH", "/test", StringComparison.Ordinal, false)]
|
||||||
|
[InlineData("/TEST/path", "/test/pa", StringComparison.OrdinalIgnoreCase, false)]
|
||||||
|
[InlineData("/TEST/path", "/test/pa", StringComparison.Ordinal, false)]
|
||||||
|
[InlineData("/test/PATH/path/TEST", "/TEST/path/PATH", StringComparison.OrdinalIgnoreCase, true)]
|
||||||
|
[InlineData("/test/PATH/path/TEST", "/TEST/path/PATH", StringComparison.Ordinal, false)]
|
||||||
|
public void StartsWithSegmentsWithRemainder_DoesMatchUsingSpecifiedComparison(string sourcePath, string testPath, StringComparison comparison, bool expectedResult)
|
||||||
|
{
|
||||||
|
var source = new PathString(sourcePath);
|
||||||
|
var test = new PathString(testPath);
|
||||||
|
|
||||||
|
PathString remaining;
|
||||||
|
var result = source.StartsWithSegments(test, comparison, out remaining);
|
||||||
|
|
||||||
|
Assert.Equal(expectedResult, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue