Use Utf8Parser instead of custom code (#1200)
This commit is contained in:
parent
66ab939cff
commit
588d9cdb11
|
|
@ -2,13 +2,13 @@
|
||||||
// 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.Text;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.SignalR.Internal.Encoders
|
namespace Microsoft.AspNetCore.SignalR.Internal.Encoders
|
||||||
{
|
{
|
||||||
public static class LengthPrefixedTextMessageParser
|
public static class LengthPrefixedTextMessageParser
|
||||||
{
|
{
|
||||||
private const int Int32OverflowLength = 10;
|
|
||||||
private const char FieldDelimiter = ':';
|
private const char FieldDelimiter = ':';
|
||||||
private const char MessageDelimiter = ';';
|
private const char MessageDelimiter = ';';
|
||||||
|
|
||||||
|
|
@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Encoders
|
||||||
|
|
||||||
var lengthSpan = buffer.Slice(0, index);
|
var lengthSpan = buffer.Slice(0, index);
|
||||||
|
|
||||||
if (!TryParseInt32(lengthSpan, out length, out var bytesConsumed) || bytesConsumed < lengthSpan.Length)
|
if (!Utf8Parser.TryParse(buffer, out length, out var bytesConsumed) || bytesConsumed < lengthSpan.Length)
|
||||||
{
|
{
|
||||||
throw new FormatException($"Invalid length: '{Encoding.UTF8.GetString(lengthSpan.ToArray())}'");
|
throw new FormatException($"Invalid length: '{Encoding.UTF8.GetString(lengthSpan.ToArray())}'");
|
||||||
}
|
}
|
||||||
|
|
@ -90,96 +90,5 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Encoders
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryParseInt32(ReadOnlySpan<byte> text, out int value, out int bytesConsumed)
|
|
||||||
{
|
|
||||||
if (text.Length < 1)
|
|
||||||
{
|
|
||||||
bytesConsumed = 0;
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int indexOfFirstDigit = 0;
|
|
||||||
int sign = 1;
|
|
||||||
if (text[0] == '-')
|
|
||||||
{
|
|
||||||
indexOfFirstDigit = 1;
|
|
||||||
sign = -1;
|
|
||||||
}
|
|
||||||
else if (text[0] == '+')
|
|
||||||
{
|
|
||||||
indexOfFirstDigit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int overflowLength = Int32OverflowLength + indexOfFirstDigit;
|
|
||||||
|
|
||||||
// Parse the first digit separately. If invalid here, we need to return false.
|
|
||||||
int firstDigit = text[indexOfFirstDigit] - 48; // '0'
|
|
||||||
if (firstDigit < 0 || firstDigit > 9)
|
|
||||||
{
|
|
||||||
bytesConsumed = 0;
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int parsedValue = firstDigit;
|
|
||||||
|
|
||||||
if (text.Length < overflowLength)
|
|
||||||
{
|
|
||||||
// Length is less than Int32OverflowLength; overflow is not possible
|
|
||||||
for (int index = indexOfFirstDigit + 1; index < text.Length; index++)
|
|
||||||
{
|
|
||||||
int nextDigit = text[index] - 48; // '0'
|
|
||||||
if (nextDigit < 0 || nextDigit > 9)
|
|
||||||
{
|
|
||||||
bytesConsumed = index;
|
|
||||||
value = parsedValue * sign;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
parsedValue = parsedValue * 10 + nextDigit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Length is greater than Int32OverflowLength; overflow is only possible after Int32OverflowLength
|
|
||||||
// digits. There may be no overflow after Int32OverflowLength if there are leading zeroes.
|
|
||||||
for (int index = indexOfFirstDigit + 1; index < overflowLength - 1; index++)
|
|
||||||
{
|
|
||||||
int nextDigit = text[index] - 48; // '0'
|
|
||||||
if (nextDigit < 0 || nextDigit > 9)
|
|
||||||
{
|
|
||||||
bytesConsumed = index;
|
|
||||||
value = parsedValue * sign;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
parsedValue = parsedValue * 10 + nextDigit;
|
|
||||||
}
|
|
||||||
for (int index = overflowLength - 1; index < text.Length; index++)
|
|
||||||
{
|
|
||||||
int nextDigit = text[index] - 48; // '0'
|
|
||||||
if (nextDigit < 0 || nextDigit > 9)
|
|
||||||
{
|
|
||||||
bytesConsumed = index;
|
|
||||||
value = parsedValue * sign;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// If parsedValue > (int.MaxValue / 10), any more appended digits will cause overflow.
|
|
||||||
// if parsedValue == (int.MaxValue / 10), any nextDigit greater than 7 or 8 (depending on sign) implies overflow.
|
|
||||||
bool positive = sign > 0;
|
|
||||||
bool nextDigitTooLarge = nextDigit > 8 || (positive && nextDigit > 7);
|
|
||||||
if (parsedValue > int.MaxValue / 10 || parsedValue == int.MaxValue / 10 && nextDigitTooLarge)
|
|
||||||
{
|
|
||||||
bytesConsumed = 0;
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
parsedValue = parsedValue * 10 + nextDigit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesConsumed = text.Length;
|
|
||||||
value = parsedValue * sign;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue