Pool `char`s used for base64url-encoding and -decoding
- #23 part 4 - depends on aspnet/HttpAbstractions@8c120a0 nits: - correct name of a field in `AntiforgerySerializationContext` - avoid allocations when returning an `AntiforgerySerializationContext` in (unlikely) case `Stream` is unused - name literal `int` parameters
This commit is contained in:
parent
c2f4bd0be5
commit
478edc1735
|
|
@ -16,7 +16,15 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||||
// Don't let the MemoryStream grow beyond 1 MB.
|
// Don't let the MemoryStream grow beyond 1 MB.
|
||||||
private const int MaximumStreamSize = 0x100000;
|
private const int MaximumStreamSize = 0x100000;
|
||||||
|
|
||||||
private MemoryStream _memory;
|
// Start _chars off with length 256 (18 bytes is protected into 116 bytes then encoded into 156 characters).
|
||||||
|
// Double length from there if necessary.
|
||||||
|
private const int InitialCharsLength = 256;
|
||||||
|
|
||||||
|
// Don't let _chars grow beyond 512k characters.
|
||||||
|
private const int MaximumCharsLength = 0x80000;
|
||||||
|
|
||||||
|
private char[] _chars;
|
||||||
|
private MemoryStream _stream;
|
||||||
private BinaryReader _reader;
|
private BinaryReader _reader;
|
||||||
private BinaryWriter _writer;
|
private BinaryWriter _writer;
|
||||||
private SHA256 _sha256;
|
private SHA256 _sha256;
|
||||||
|
|
@ -25,16 +33,16 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_memory == null)
|
if (_stream == null)
|
||||||
{
|
{
|
||||||
_memory = new MemoryStream(InitialStreamSize);
|
_stream = new MemoryStream(InitialStreamSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _memory;
|
return _stream;
|
||||||
}
|
}
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
_memory = value;
|
_stream = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,19 +99,43 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public char[] GetChars(int count)
|
||||||
|
{
|
||||||
|
if (_chars == null || _chars.Length < count)
|
||||||
|
{
|
||||||
|
var newLength = _chars == null ? InitialCharsLength : checked(_chars.Length * 2);
|
||||||
|
while (newLength < count)
|
||||||
|
{
|
||||||
|
newLength = checked(newLength * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
_chars = new char[newLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
return _chars;
|
||||||
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
if (Stream.Capacity > MaximumStreamSize)
|
if (_chars != null && _chars.Length > MaximumCharsLength)
|
||||||
{
|
{
|
||||||
Stream = null;
|
_chars = null;
|
||||||
Reader = null;
|
|
||||||
Writer = null;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (_stream != null)
|
||||||
{
|
{
|
||||||
Stream.Position = 0L;
|
if (Stream.Capacity > MaximumStreamSize)
|
||||||
Stream.SetLength(0L);
|
{
|
||||||
|
Stream = null;
|
||||||
|
Reader = null;
|
||||||
|
Writer = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Stream.Position = 0L;
|
||||||
|
Stream.SetLength(0L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -42,10 +42,19 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||||
Exception innerException = null;
|
Exception innerException = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var tokenBytes = WebEncoders.Base64UrlDecode(serializedToken);
|
var count = serializedToken.Length;
|
||||||
|
var charsRequired = WebEncoders.GetArraySizeRequiredToDecode(count);
|
||||||
|
var chars = serializationContext.GetChars(charsRequired);
|
||||||
|
var tokenBytes = WebEncoders.Base64UrlDecode(
|
||||||
|
serializedToken,
|
||||||
|
offset: 0,
|
||||||
|
buffer: chars,
|
||||||
|
bufferOffset: 0,
|
||||||
|
count: count);
|
||||||
|
|
||||||
var unprotectedBytes = _cryptoSystem.Unprotect(tokenBytes);
|
var unprotectedBytes = _cryptoSystem.Unprotect(tokenBytes);
|
||||||
var stream = serializationContext.Stream;
|
var stream = serializationContext.Stream;
|
||||||
stream.Write(unprotectedBytes, 0, unprotectedBytes.Length);
|
stream.Write(unprotectedBytes, offset: 0, count: unprotectedBytes.Length);
|
||||||
stream.Position = 0L;
|
stream.Position = 0L;
|
||||||
|
|
||||||
var reader = serializationContext.Reader;
|
var reader = serializationContext.Reader;
|
||||||
|
|
@ -156,7 +165,19 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||||
|
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
var stream = serializationContext.Stream;
|
var stream = serializationContext.Stream;
|
||||||
return WebEncoders.Base64UrlEncode(_cryptoSystem.Protect(stream.ToArray()));
|
var bytes = _cryptoSystem.Protect(stream.ToArray());
|
||||||
|
|
||||||
|
var count = bytes.Length;
|
||||||
|
var charsRequired = WebEncoders.GetArraySizeRequiredToEncode(count);
|
||||||
|
var chars = serializationContext.GetChars(charsRequired);
|
||||||
|
var outputLength = WebEncoders.Base64UrlEncode(
|
||||||
|
bytes,
|
||||||
|
offset: 0,
|
||||||
|
output: chars,
|
||||||
|
outputOffset: 0,
|
||||||
|
count: count);
|
||||||
|
|
||||||
|
return new string(chars, startIndex: 0, length: outputLength);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue