Use spans for complex segments (#9817)

This commit is contained in:
David Fowler 2019-04-30 22:56:53 -07:00 committed by GitHub
parent f08da14f1b
commit 8af14399b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 18 deletions

View File

@ -228,13 +228,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
for (var i = 0; i < captures.Length; i++) for (var i = 0; i < captures.Length; i++)
{ {
var parameterName = captures[i].parameterName; (var parameterName, var segmentIndex, var slotIndex) = captures[i];
if (segments.Length > captures[i].segmentIndex)
if ((uint)segmentIndex < (uint)segments.Length)
{ {
var segment = segments[captures[i].segmentIndex]; var segment = segments[segmentIndex];
if (parameterName != null && segment.Length > 0) if (parameterName != null && segment.Length > 0)
{ {
slots[captures[i].slotIndex] = new KeyValuePair<string, object>( slots[slotIndex] = new KeyValuePair<string, object>(
parameterName, parameterName,
path.Substring(segment.Start, segment.Length)); path.Substring(segment.Start, segment.Length));
} }
@ -249,7 +250,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
ReadOnlySpan<PathSegment> segments) ReadOnlySpan<PathSegment> segments)
{ {
// Read segmentIndex to local both to skip double read from stack value // Read segmentIndex to local both to skip double read from stack value
// and to use the same in-bounds validated varaible to access the array. // and to use the same in-bounds validated variable to access the array.
var segmentIndex = catchAll.segmentIndex; var segmentIndex = catchAll.segmentIndex;
if ((uint)segmentIndex < (uint)segments.Length) if ((uint)segmentIndex < (uint)segments.Length)
{ {
@ -271,7 +272,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
(var complexSegment, var segmentIndex) = complexSegments[i]; (var complexSegment, var segmentIndex) = complexSegments[i];
var segment = segments[segmentIndex]; var segment = segments[segmentIndex];
var text = path.Substring(segment.Start, segment.Length); var text = path.AsSpan(segment.Start, segment.Length);
if (!RoutePatternMatcher.MatchComplexSegment(complexSegment, text, values)) if (!RoutePatternMatcher.MatchComplexSegment(complexSegment, text, values))
{ {
Logger.CandidateRejectedByComplexSegment(_logger, path, endpoint, complexSegment); Logger.CandidateRejectedByComplexSegment(_logger, path, endpoint, complexSegment);

View File

@ -160,7 +160,7 @@ namespace Microsoft.AspNetCore.Routing
} }
if (!pathSegment.IsSimple) if (!pathSegment.IsSimple)
{ {
if (!MatchComplexSegment(pathSegment, requestSegment.ToString(), values)) if (!MatchComplexSegment(pathSegment, requestSegment.AsSpan(), values))
{ {
return false; return false;
} }
@ -292,7 +292,7 @@ namespace Microsoft.AspNetCore.Routing
internal static bool MatchComplexSegment( internal static bool MatchComplexSegment(
RoutePatternPathSegment routeSegment, RoutePatternPathSegment routeSegment,
string requestSegment, ReadOnlySpan<char> requestSegment,
RouteValueDictionary values) RouteValueDictionary values)
{ {
var indexOfLastSegment = routeSegment.Parts.Count - 1; var indexOfLastSegment = routeSegment.Parts.Count - 1;
@ -336,7 +336,7 @@ namespace Microsoft.AspNetCore.Routing
private static bool MatchComplexSegmentCore( private static bool MatchComplexSegmentCore(
RoutePatternPathSegment routeSegment, RoutePatternPathSegment routeSegment,
string requestSegment, ReadOnlySpan<char> requestSegment,
RouteValueDictionary values, RouteValueDictionary values,
int indexOfLastSegmentUsed) int indexOfLastSegmentUsed)
{ {
@ -366,14 +366,14 @@ namespace Microsoft.AspNetCore.Routing
Debug.Assert(part.IsLiteral || part.IsSeparator); Debug.Assert(part.IsLiteral || part.IsSeparator);
lastLiteral = part; lastLiteral = part;
var startIndex = lastIndex - 1; var startIndex = lastIndex;
// If we have a pending parameter subsegment, we must leave at least one character for that // If we have a pending parameter subsegment, we must leave at least one character for that
if (parameterNeedsValue != null) if (parameterNeedsValue != null)
{ {
startIndex--; startIndex--;
} }
if (startIndex < 0) if (startIndex == 0)
{ {
return false; return false;
} }
@ -382,17 +382,15 @@ namespace Microsoft.AspNetCore.Routing
if (part.IsLiteral) if (part.IsLiteral)
{ {
var literal = (RoutePatternLiteralPart)part; var literal = (RoutePatternLiteralPart)part;
indexOfLiteral = requestSegment.LastIndexOf( indexOfLiteral = requestSegment.Slice(0, startIndex).LastIndexOf(
literal.Content, literal.Content,
startIndex,
StringComparison.OrdinalIgnoreCase); StringComparison.OrdinalIgnoreCase);
} }
else else
{ {
var literal = (RoutePatternSeparatorPart)part; var literal = (RoutePatternSeparatorPart)part;
indexOfLiteral = requestSegment.LastIndexOf( indexOfLiteral = requestSegment.Slice(0, startIndex).LastIndexOf(
literal.Content, literal.Content,
startIndex,
StringComparison.OrdinalIgnoreCase); StringComparison.OrdinalIgnoreCase);
} }
@ -465,9 +463,9 @@ namespace Microsoft.AspNetCore.Routing
} }
} }
var parameterValueString = requestSegment.Substring(parameterStartIndex, parameterTextLength); var parameterValueSpan = requestSegment.Slice(parameterStartIndex, parameterTextLength);
if (string.IsNullOrEmpty(parameterValueString)) if (parameterValueSpan.Length == 0)
{ {
// If we're here that means we have a segment that contains multiple sub-segments. // If we're here that means we have a segment that contains multiple sub-segments.
// For these segments all parameters must have non-empty values. If the parameter // For these segments all parameters must have non-empty values. If the parameter
@ -478,7 +476,7 @@ namespace Microsoft.AspNetCore.Routing
else else
{ {
// If there's a value in the segment for this parameter, use the subsegment value // If there's a value in the segment for this parameter, use the subsegment value
outValues.Add(parameterNeedsValue.Name, parameterValueString); outValues.Add(parameterNeedsValue.Name, new string(parameterValueSpan));
} }
parameterNeedsValue = null; parameterNeedsValue = null;