Skip to content

Commit 4ddc291

Browse files
committed
Use new Base64Url API
1 parent 9c108a6 commit 4ddc291

File tree

8 files changed

+197
-319
lines changed

8 files changed

+197
-319
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Buffers.Text;
6+
using BenchmarkDotNet.Attributes;
7+
using Microsoft.IdentityModel.Tokens;
8+
9+
namespace Microsoft.IdentityModel.Benchmarks
10+
{
11+
// dotnet run -c release -f net9.0 --filter Microsoft.IdentityModel.Benchmarks.Base64UrlEncoderTests*
12+
13+
[MemoryDiagnoser]
14+
public class Base64UrlEncoderTests
15+
{
16+
private const string base64UrlEncodedString = "V1aOrL0rTJZYRxPHmMZdTWR0-ilwg9V9iEoKSn3CYl5vmBNqsM0x4VtvRbK8nCmnCIc2__QE92D4vQDR8AQ2j_BljJUkNY51VrbZ1wBar_7X2NktF_AQLkqDmwuagjhONR9_MIVysq36EAqxoHAwHHJx87XrrOkPDD8kiQ2uZEgPgK-4o02hhjsETU7KWiOKg4nKlLUU2YwuW2ZQxVubPfEv5SrW8BDgvNwPseyXfKrznhNAQHgwUX6sh1lTBm-cQdujkNsG62DeJSA2o9A_IhpKOuyQpaNda6U8jbBh3FGZhmFAm6yxNag3b6jAVlxphRNDvlm6UprgoFbvzcuH8W5ZH60LjNxsSKLH8W3gHIc7jhDA0vH2T8Nf2HEqFmqcsGr6aNm86ilWg1tchS_DlFPWqu8Wm3EEHTSJcd7BxMTvr9syRLICmhVsfHwdgMy1WfKklnyGJ_RT3kvbfCPQ2sSRMiOqCkdwCUECu-CcxS4CiIanlWnIpllmBov6vawcR6o6gmcFuqxhw2rp3815glnF7jNkmr7hsd0DPQ7qRUOHlGkF8_Sgretbgpb61y8a8DlVLlb7nBBQbTFif-lBAH4gfWWeNF9A3RFPQ8e8UKghJ7u_4ua9W_Lk_xpDkyGDXrkAzTYLxOGujRaWexOpwWSOKsXgIqXa94px0HAUIAVwP2Gy_gWcVz47ayedXh1Tcqb3K1hDlzZt4XK6O9eu-lAgy6gBltSrkntumDB-XEkxRabh8FNMln_LeEh_TgwWX4iVBR1-VD-VJw1e_aypVWj_E178TjCeb6Lc9pKD_r2VAieZpVp0c15g3vxznBWPD5mviHnK_NbSiccodSfpzGJbUsBuvKvhK4EFSw4_YlWJFlEXj3XYtiqO60crVynlEEqegLncI6RrjWe8WEfXEm_yeiglH5I-asU5sl0pBdLRdeg1xo1SZfR-CtgJ0dliwGkPDE6HcyGqhddMbIze_5I8ZazQ31PQaShhXtdH3K_cWXe4WhpR-_qYTrwib89ux2zZxePCkb_RXyvd09hv1J1kkmTf9f7q1xXfiBw49Iun90tJaOMru6PeL3Ayixj4d2C-rnwS43jcRJJ_SBiRgpBQo3Gg893UkxY2l2prQa-zU9GdbwlfDF9Htijxm75SuoxOldhTFDcpw6QqKjt1116gfkmgg16hXjvNhV8sCqxmHdKoIM6EOKVy5MAIJcg_-wbAVhbJQ205udIPb49GY1yDePieu2eQa6TU8Pn66YK5Kl4K6kCmOY6NpDdhDk6BwyJ6Z9wz2nF8OwF2mDKpMdP2nkFnq8iq2z9o7s7HwIP8pbr99kvMlw";
17+
// Add padding
18+
private static readonly string base64EncodedString = base64UrlEncodedString.Replace('-', '+').Replace('_', '/') + "==";
19+
// Add "padding" without adding special characters
20+
private static readonly string base64NoSpecialCharsEncodedString = base64UrlEncodedString.Replace('-', 'A').Replace('_', 'B') + "ab";
21+
// Add padding as only special characters (Base64-encoded but could be decoded with Base64Url API)
22+
private static readonly string base64NoSpecialCharsExceptPaddingEncodedString = base64UrlEncodedString.Replace('-', 'A').Replace('_', 'B') + "==";
23+
private static readonly string decodedString = Base64UrlEncoder.Decode(base64UrlEncodedString);
24+
private static readonly byte[] decodedBytes = Base64UrlEncoder.DecodeBytes(base64UrlEncodedString);
25+
26+
[Benchmark]
27+
public void Decode_String_Base64Url() => Base64UrlEncoder.Decode(base64UrlEncodedString);
28+
29+
[Benchmark]
30+
public void Decode_Span_Base64Url() => Base64UrlEncoder.Decode(base64UrlEncodedString.AsSpan());
31+
32+
[Benchmark]
33+
public void DecodeBytes_Base64Url() => Base64UrlEncoder.DecodeBytes(base64UrlEncodedString);
34+
35+
[Benchmark]
36+
public void Decode_Span_Output_Base64Url() => Base64UrlEncoder.Decode(base64UrlEncodedString.AsSpan(), new byte[Base64.GetMaxDecodedFromUtf8Length(base64UrlEncodedString.Length + 2)]);
37+
38+
[Benchmark]
39+
public void Decode_String_Base64() => Base64UrlEncoder.Decode(base64EncodedString);
40+
41+
[Benchmark]
42+
public void Decode_Span_Base64() => Base64UrlEncoder.Decode(base64EncodedString.AsSpan());
43+
44+
[Benchmark]
45+
public void DecodeBytes_Base64() => Base64UrlEncoder.DecodeBytes(base64EncodedString);
46+
47+
[Benchmark]
48+
public void Decode_Span_Output_Base64() => Base64UrlEncoder.Decode(base64EncodedString.AsSpan(), new byte[Base64.GetMaxDecodedFromUtf8Length(base64EncodedString.Length + 2)]);
49+
50+
[Benchmark]
51+
public void Decode_String_Base64NoSpecialChars() => Base64UrlEncoder.Decode(base64NoSpecialCharsEncodedString);
52+
53+
[Benchmark]
54+
public void Decode_Span_Base64NoSpecialChars() => Base64UrlEncoder.Decode(base64NoSpecialCharsEncodedString.AsSpan());
55+
56+
[Benchmark]
57+
public void DecodeBytes_Base64NoSpecialChars() => Base64UrlEncoder.DecodeBytes(base64NoSpecialCharsEncodedString);
58+
59+
[Benchmark]
60+
public void Decode_Span_Output_Base64NoSpecialChars() => Base64UrlEncoder.Decode(base64NoSpecialCharsEncodedString.AsSpan(), new byte[Base64.GetMaxDecodedFromUtf8Length(base64NoSpecialCharsEncodedString.Length + 2)]);
61+
62+
[Benchmark]
63+
public void Decode_String_Base64NoSpecialCharsExceptPadding() => Base64UrlEncoder.Decode(base64NoSpecialCharsExceptPaddingEncodedString);
64+
65+
[Benchmark]
66+
public void Decode_Span_Base64NoSpecialCharsExceptPadding() => Base64UrlEncoder.Decode(base64NoSpecialCharsExceptPaddingEncodedString.AsSpan());
67+
68+
[Benchmark]
69+
public void DecodeBytes_Base64NoSpecialCharsExceptPadding() => Base64UrlEncoder.DecodeBytes(base64NoSpecialCharsExceptPaddingEncodedString);
70+
71+
[Benchmark]
72+
public void Decode_Span_Output_Base64NoSpecialCharsExceptPadding() => Base64UrlEncoder.Decode(base64NoSpecialCharsExceptPaddingEncodedString.AsSpan(), new byte[Base64.GetMaxDecodedFromUtf8Length(base64NoSpecialCharsExceptPaddingEncodedString.Length + 2)]);
73+
74+
[Benchmark]
75+
public void Encode_String_Base64Url() => Base64UrlEncoder.Encode(decodedString);
76+
77+
[Benchmark]
78+
public void Encode_Bytes_Base64Url() => Base64UrlEncoder.Encode(decodedBytes);
79+
80+
[Benchmark]
81+
public void Encode_Span_Base64Url() => Base64UrlEncoder.Encode(decodedBytes, new char[Base64.GetMaxEncodedToUtf8Length(decodedBytes.Length)]);
82+
83+
[Benchmark]
84+
public void Encode_Bytes_Offset_Length_Base64Url() => Base64UrlEncoder.Encode(decodedBytes, decodedBytes.Length / 2, decodedBytes.Length / 2 - 10);
85+
}
86+
}

benchmark/Microsoft.IdentityModel.Benchmarks/identitymodel.benchmarks.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,8 @@ scenarios:
5757
variables:
5858
filterArg: "*ValidateTokenAsyncTests*"
5959

60+
Base64UrlEncoderTests:
61+
application:
62+
job: benchmarks
63+
variables:
64+
filterArg: "*Base64UrlEncoderTests*"

build/dependencies.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<SystemMemoryVersion>4.5.5</SystemMemoryVersion>
1212
<SystemSecurityCryptographyCngVersion>4.5.0</SystemSecurityCryptographyCngVersion>
1313
<SystemTextJson>8.0.4</SystemTextJson>
14+
<MicrosoftBclMemory>9.0.0-rc.1.24431.7</MicrosoftBclMemory>
1415
</PropertyGroup>
1516

1617
</Project>

src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,15 +569,22 @@ internal JsonClaimSet CreateClaimSet(ReadOnlySpan<char> strSpan, int startIndex,
569569
{
570570
int outputSize = Base64UrlEncoding.ValidateAndGetOutputSize(strSpan, startIndex, length);
571571

572-
byte[] output = ArrayPool<byte>.Shared.Rent(outputSize);
572+
byte[] rented = null;
573+
574+
const int MaxStackallocThreshold = 256;
575+
Span<byte> output = outputSize <= MaxStackallocThreshold
576+
? stackalloc byte[outputSize]
577+
: (rented = ArrayPool<byte>.Shared.Rent(outputSize));
578+
573579
try
574580
{
575581
Base64UrlEncoder.Decode(strSpan.Slice(startIndex, length), output);
576-
return createHeaderClaimSet ? CreateHeaderClaimSet(output.AsSpan()) : CreatePayloadClaimSet(output.AsSpan());
582+
return createHeaderClaimSet ? CreateHeaderClaimSet(output) : CreatePayloadClaimSet(output);
577583
}
578584
finally
579585
{
580-
ArrayPool<byte>.Shared.Return(output, true);
586+
if (rented is not null)
587+
ArrayPool<byte>.Shared.Return(rented, true);
581588
}
582589
}
583590

0 commit comments

Comments
 (0)