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 string Base64UrlEncode(byte[] input) { throw null; }
|
||||||
public static int Base64UrlEncode(byte[] input, int offset, char[] output, int outputOffset, int count) { 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(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 GetArraySizeRequiredToDecode(int count) { throw null; }
|
||||||
public static int GetArraySizeRequiredToEncode(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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Microsoft.Extensions.WebEncoders.Sources;
|
using Microsoft.Extensions.WebEncoders.Sources;
|
||||||
|
|
@ -220,6 +221,9 @@ namespace Microsoft.Extensions.Internal
|
||||||
|
|
||||||
ValidateParameters(input.Length, nameof(input), offset, count);
|
ValidateParameters(input.Length, nameof(input), offset, count);
|
||||||
|
|
||||||
|
#if NETCOREAPP3_0
|
||||||
|
return Base64UrlEncode(input.AsSpan(offset, count));
|
||||||
|
#else
|
||||||
// Special-case empty input
|
// Special-case empty input
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -229,7 +233,8 @@ namespace Microsoft.Extensions.Internal
|
||||||
var buffer = new char[GetArraySizeRequiredToEncode(count)];
|
var buffer = new char[GetArraySizeRequiredToEncode(count)];
|
||||||
var numBase64Chars = Base64UrlEncode(input, offset, buffer, outputOffset: 0, count: 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>
|
/// <summary>
|
||||||
|
|
@ -280,6 +285,9 @@ namespace Microsoft.Extensions.Internal
|
||||||
nameof(count));
|
nameof(count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NETCOREAPP3_0
|
||||||
|
return Base64UrlEncode(input.AsSpan(offset, count), output.AsSpan(outputOffset));
|
||||||
|
#else
|
||||||
// Special-case empty input.
|
// Special-case empty input.
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -311,6 +319,7 @@ namespace Microsoft.Extensions.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
return numBase64Chars;
|
return numBase64Chars;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -327,6 +336,73 @@ namespace Microsoft.Extensions.Internal
|
||||||
return checked(numWholeOrPartialInputBlocks * 4);
|
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)
|
private static int GetNumBase64PaddingCharsInString(string str)
|
||||||
{
|
{
|
||||||
// Assumption: input contains a well-formed base64 string with no whitespace.
|
// 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()
|
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
|
// 128 bit buffer / 8 bits per byte = 16 bytes
|
||||||
var buffer = new byte[16];
|
Span<byte> buffer = stackalloc byte[16];
|
||||||
_keyGenerator.GetBytes(buffer);
|
|
||||||
// Generate the id with RNGCrypto because we want a cryptographically random id, which GUID is not
|
// Generate the id with RNGCrypto because we want a cryptographically random id, which GUID is not
|
||||||
|
_keyGenerator.GetBytes(buffer);
|
||||||
return WebEncoders.Base64UrlEncode(buffer);
|
return WebEncoders.Base64UrlEncode(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue