diff --git a/src/Shared/WebEncoders/WebEncoders.cs b/src/Shared/WebEncoders/WebEncoders.cs
index 640e231cd0d6..8d92baa94c51 100644
--- a/src/Shared/WebEncoders/WebEncoders.cs
+++ b/src/Shared/WebEncoders/WebEncoders.cs
@@ -28,6 +28,11 @@ namespace Microsoft.Extensions.Internal;
#endif
static class WebEncoders
{
+#if NET9_0_OR_GREATER
+ /// SearchValues for the two Base64 and two Base64Url chars that differ from each other.
+ private static readonly SearchValues s_base64vsBase64UrlDifferentiators = SearchValues.Create("+/-_");
+#endif
+
///
/// Decodes a base64url-encoded string.
///
@@ -69,9 +74,11 @@ public static byte[] Base64UrlDecode(string input, int offset, int count)
#if NET9_0_OR_GREATER
// Legacy behavior of Base64UrlDecode supports either Base64 or Base64Url input.
- // If it doesn't have + or /, it can be treated as Base64Url.
+ // If it has a - or _, or if it doesn't have + or /, it can be treated as Base64Url.
+ // Searching for any of them allows us to stop the search as early as we know whether Base64Url should be used.
ReadOnlySpan inputSpan = input.AsSpan(offset, count);
- if (!inputSpan.ContainsAny('+', '/'))
+ int indexOfFirstDifferentiator = inputSpan.IndexOfAny(s_base64vsBase64UrlDifferentiators);
+ if (indexOfFirstDifferentiator < 0 || inputSpan[indexOfFirstDifferentiator] is '-' or '_')
{
return Base64Url.DecodeFromChars(inputSpan);
}
@@ -124,9 +131,11 @@ public static byte[] Base64UrlDecode(string input, int offset, char[] buffer, in
#if NET9_0_OR_GREATER
// Legacy behavior of Base64UrlDecode supports either Base64 or Base64Url input.
- // If it doesn't have + or /, it can be treated as Base64Url.
+ // If it has a - or _, or if it doesn't have + or /, it can be treated as Base64Url.
+ // Searching for any of them allows us to stop the search as early as we know Base64Url should be used.
ReadOnlySpan inputSpan = input.AsSpan(offset, count);
- if (!inputSpan.ContainsAny('+', '/'))
+ int indexOfFirstDifferentiator = inputSpan.IndexOfAny(s_base64vsBase64UrlDifferentiators);
+ if (indexOfFirstDifferentiator < 0 || inputSpan[indexOfFirstDifferentiator] is '-' or '_')
{
return Base64Url.DecodeFromChars(inputSpan);
}