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); }