Skip to content

Commit

Permalink
Use SearchValues in PathString (#49117)
Browse files Browse the repository at this point in the history
  • Loading branch information
MihaZupan committed Jul 5, 2023
1 parent fdfb0d2 commit b287b92
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 99 deletions.
66 changes: 0 additions & 66 deletions src/Http/Http.Abstractions/src/Internal/PathStringHelper.cs

This file was deleted.

69 changes: 36 additions & 33 deletions src/Http/Http.Abstractions/src/PathString.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
Expand All @@ -18,6 +19,9 @@ namespace Microsoft.AspNetCore.Http;
[DebuggerDisplay("{Value}")]
public readonly struct PathString : IEquatable<PathString>
{
private static readonly SearchValues<char> s_validPathChars =
SearchValues.Create("!$&'()*+,-./0123456789:;=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~");

internal const int StackAllocThreshold = 128;

/// <summary>
Expand Down Expand Up @@ -68,27 +72,18 @@ public override string ToString()
/// <returns>The escaped path value</returns>
public string ToUriComponent()
{
if (!HasValue)
{
return string.Empty;
}

var value = Value;
var i = 0;
for (; i < value.Length; i++)
{
if (!PathStringHelper.IsValidPathChar(value[i]) || PathStringHelper.IsPercentEncodedChar(value, i))
{
break;
}
}

if (i < value.Length)
if (string.IsNullOrEmpty(value))
{
return ToEscapedUriComponent(value, i);
return string.Empty;
}

return value;
var indexOfInvalidChar = value.AsSpan().IndexOfAnyExcept(s_validPathChars);

return indexOfInvalidChar < 0
? value
: ToEscapedUriComponent(value, indexOfInvalidChar);
}

private static string ToEscapedUriComponent(string value, int i)
Expand All @@ -99,10 +94,10 @@ private static string ToEscapedUriComponent(string value, int i)
var count = i;
var requiresEscaping = false;

while (i < value.Length)
while ((uint)i < (uint)value.Length)
{
var isPercentEncodedChar = PathStringHelper.IsPercentEncodedChar(value, i);
if (PathStringHelper.IsValidPathChar(value[i]) || isPercentEncodedChar)
var isPercentEncodedChar = false;
if (s_validPathChars.Contains(value[i]) || (isPercentEncodedChar = Uri.IsHexEncoding(value, i)))
{
if (requiresEscaping)
{
Expand All @@ -122,8 +117,18 @@ private static string ToEscapedUriComponent(string value, int i)
}
else
{
count++;
i++;
// We just saw a character we don't want to escape. It's likely there are more, do a vectorized search.
var charsToSkip = value.AsSpan(i).IndexOfAnyExcept(s_validPathChars);

if (charsToSkip < 0)
{
// Only valid characters remain
count += value.Length - i;
break;
}

count += charsToSkip;
i += charsToSkip;
}
}
else
Expand All @@ -150,21 +155,19 @@ private static string ToEscapedUriComponent(string value, int i)
}
else
{
if (count > 0)
{
buffer ??= new StringBuilder(value.Length * 3);
Debug.Assert(count > 0);
Debug.Assert(buffer is not null);

if (requiresEscaping)
{
buffer.Append(Uri.EscapeDataString(value.Substring(start, count)));
}
else
{
buffer.Append(value, start, count);
}
if (requiresEscaping)
{
buffer.Append(Uri.EscapeDataString(value.Substring(start, count)));
}
else
{
buffer.Append(value, start, count);
}

return buffer?.ToString() ?? string.Empty;
return buffer.ToString();
}
}

Expand Down

0 comments on commit b287b92

Please sign in to comment.