Spanified Webencoders.Base64UrlEncode (#11047)
This commit is contained in:
parent
4d1262c39b
commit
90ab2cb965
|
|
@ -233,6 +233,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
public static string Base64UrlEncode(byte[] input) { throw null; }
|
||||
public static int Base64UrlEncode(byte[] input, int offset, char[] output, int outputOffset, int count) { throw null; }
|
||||
public static string Base64UrlEncode(byte[] input, int offset, int count) { throw null; }
|
||||
public static string Base64UrlEncode(System.ReadOnlySpan<byte> input) { throw null; }
|
||||
public static int GetArraySizeRequiredToDecode(int count) { throw null; }
|
||||
public static int GetArraySizeRequiredToEncode(int count) { throw null; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.WebEncoders.Sources;
|
||||
|
|
@ -220,6 +221,9 @@ namespace Microsoft.Extensions.Internal
|
|||
|
||||
ValidateParameters(input.Length, nameof(input), offset, count);
|
||||
|
||||
#if NETCOREAPP3_0
|
||||
return Base64UrlEncode(input.AsSpan(offset, count));
|
||||
#else
|
||||
// Special-case empty input
|
||||
if (count == 0)
|
||||
{
|
||||
|
|
@ -229,7 +233,8 @@ namespace Microsoft.Extensions.Internal
|
|||
var buffer = new char[GetArraySizeRequiredToEncode(count)];
|
||||
var numBase64Chars = Base64UrlEncode(input, offset, buffer, outputOffset: 0, count: count);
|
||||
|
||||
return new String(buffer, startIndex: 0, length: numBase64Chars);
|
||||
return new string(buffer, startIndex: 0, length: numBase64Chars);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -280,6 +285,9 @@ namespace Microsoft.Extensions.Internal
|
|||
nameof(count));
|
||||
}
|
||||
|
||||
#if NETCOREAPP3_0
|
||||
return Base64UrlEncode(input.AsSpan(offset, count), output.AsSpan(outputOffset));
|
||||
#else
|
||||
// Special-case empty input.
|
||||
if (count == 0)
|
||||
{
|
||||
|
|
@ -311,6 +319,7 @@ namespace Microsoft.Extensions.Internal
|
|||
}
|
||||
|
||||
return numBase64Chars;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -327,6 +336,73 @@ namespace Microsoft.Extensions.Internal
|
|||
return checked(numWholeOrPartialInputBlocks * 4);
|
||||
}
|
||||
|
||||
#if NETCOREAPP3_0
|
||||
/// <summary>
|
||||
/// Encodes <paramref name="input"/> using base64url encoding.
|
||||
/// </summary>
|
||||
/// <param name="input">The binary input to encode.</param>
|
||||
/// <returns>The base64url-encoded form of <paramref name="input"/>.</returns>
|
||||
public static string Base64UrlEncode(ReadOnlySpan<byte> input)
|
||||
{
|
||||
if (input.IsEmpty)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
int bufferSize = GetArraySizeRequiredToEncode(input.Length);
|
||||
|
||||
char[] bufferToReturnToPool = null;
|
||||
Span<char> buffer = bufferSize <= 128
|
||||
? stackalloc char[bufferSize]
|
||||
: bufferToReturnToPool = ArrayPool<char>.Shared.Rent(bufferSize);
|
||||
|
||||
var numBase64Chars = Base64UrlEncode(input, buffer);
|
||||
var base64Url = new string(buffer.Slice(0, numBase64Chars));
|
||||
|
||||
if (bufferToReturnToPool != null)
|
||||
{
|
||||
ArrayPool<char>.Shared.Return(bufferToReturnToPool);
|
||||
}
|
||||
|
||||
return base64Url;
|
||||
}
|
||||
|
||||
private static int Base64UrlEncode(ReadOnlySpan<byte> input, Span<char> output)
|
||||
{
|
||||
Debug.Assert(output.Length >= GetArraySizeRequiredToEncode(input.Length));
|
||||
|
||||
if (input.IsEmpty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use base64url encoding with no padding characters. See RFC 4648, Sec. 5.
|
||||
|
||||
Convert.TryToBase64Chars(input, output, out int charsWritten);
|
||||
|
||||
// Fix up '+' -> '-' and '/' -> '_'. Drop padding characters.
|
||||
for (var i = 0; i < charsWritten; i++)
|
||||
{
|
||||
var ch = output[i];
|
||||
if (ch == '+')
|
||||
{
|
||||
output[i] = '-';
|
||||
}
|
||||
else if (ch == '/')
|
||||
{
|
||||
output[i] = '_';
|
||||
}
|
||||
else if (ch == '=')
|
||||
{
|
||||
// We've reached a padding character; truncate the remainder.
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return charsWritten;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static int GetNumBase64PaddingCharsInString(string str)
|
||||
{
|
||||
// Assumption: input contains a well-formed base64 string with no whitespace.
|
||||
|
|
|
|||
|
|
@ -105,11 +105,10 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
|
|||
|
||||
private static string MakeNewConnectionId()
|
||||
{
|
||||
// TODO: Use Span when WebEncoders implements Span methods https://github.com/aspnet/Home/issues/2966
|
||||
// 128 bit buffer / 8 bits per byte = 16 bytes
|
||||
var buffer = new byte[16];
|
||||
_keyGenerator.GetBytes(buffer);
|
||||
Span<byte> buffer = stackalloc byte[16];
|
||||
// Generate the id with RNGCrypto because we want a cryptographically random id, which GUID is not
|
||||
_keyGenerator.GetBytes(buffer);
|
||||
return WebEncoders.Base64UrlEncode(buffer);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue