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.
|
||||
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 BinaryWriter _writer;
|
||||
private SHA256 _sha256;
|
||||
|
|
@ -25,16 +33,16 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_memory == null)
|
||||
if (_stream == null)
|
||||
{
|
||||
_memory = new MemoryStream(InitialStreamSize);
|
||||
_stream = new MemoryStream(InitialStreamSize);
|
||||
}
|
||||
|
||||
return _memory;
|
||||
return _stream;
|
||||
}
|
||||
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()
|
||||
{
|
||||
if (Stream.Capacity > MaximumStreamSize)
|
||||
if (_chars != null && _chars.Length > MaximumCharsLength)
|
||||
{
|
||||
Stream = null;
|
||||
Reader = null;
|
||||
Writer = null;
|
||||
_chars = null;
|
||||
}
|
||||
else
|
||||
|
||||
if (_stream != null)
|
||||
{
|
||||
Stream.Position = 0L;
|
||||
Stream.SetLength(0L);
|
||||
if (Stream.Capacity > MaximumStreamSize)
|
||||
{
|
||||
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;
|
||||
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 stream = serializationContext.Stream;
|
||||
stream.Write(unprotectedBytes, 0, unprotectedBytes.Length);
|
||||
stream.Write(unprotectedBytes, offset: 0, count: unprotectedBytes.Length);
|
||||
stream.Position = 0L;
|
||||
|
||||
var reader = serializationContext.Reader;
|
||||
|
|
@ -156,7 +165,19 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
writer.Flush();
|
||||
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
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue