/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/SignalR/common/Shared/BinaryMessageParser.cs
85 строк
3 KB
Pranav K
Use file scoped namespaces (#38076)
06 ноя 2021, 03:52
Не верифицирован
06 ноя 2021, 03:52
a450cb6
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Buffers; namespace Microsoft.AspNetCore.Internal; internal static class BinaryMessageParser { private const int MaxLengthPrefixSize = 5; public static bool TryParseMessage(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> payload) { if (buffer.IsEmpty) { payload = default; return false; } // The payload starts with a length prefix encoded as a VarInt. VarInts use the most significant bit // as a marker whether the byte is the last byte of the VarInt or if it spans to the next byte. Bytes // appear in the reverse order - i.e. the first byte contains the least significant bits of the value // Examples: // VarInt: 0x35 - %00110101 - the most significant bit is 0 so the value is %x0110101 i.e. 0x35 (53) // VarInt: 0x80 0x25 - %10000000 %00101001 - the most significant bit of the first byte is 1 so the // remaining bits (%x0000000) are the lowest bits of the value. The most significant bit of the second // byte is 0 meaning this is last byte of the VarInt. The actual value bits (%x0101001) need to be // prepended to the bits we already read so the values is %01010010000000 i.e. 0x1480 (5248) // We support payloads up to 2GB so the biggest number we support is 7fffffff which when encoded as // VarInt is 0xFF 0xFF 0xFF 0xFF 0x07 - hence the maximum length prefix is 5 bytes. var length = 0U; var numBytes = 0; var lengthPrefixBuffer = buffer.Slice(0, Math.Min(MaxLengthPrefixSize, buffer.Length)); var span = GetSpan(lengthPrefixBuffer); byte byteRead; do { byteRead = span[numBytes]; length = length | (((uint)(byteRead & 0x7f)) << (numBytes * 7)); numBytes++; } while (numBytes < lengthPrefixBuffer.Length && ((byteRead & 0x80) != 0)); // size bytes are missing if ((byteRead & 0x80) != 0 && (numBytes < MaxLengthPrefixSize)) { payload = default; return false; } if ((byteRead & 0x80) != 0 || (numBytes == MaxLengthPrefixSize && byteRead > 7)) { throw new FormatException("Messages over 2GB in size are not supported."); } // We don't have enough data if (buffer.Length < length + numBytes) { payload = default; return false; } // Get the payload payload = buffer.Slice(numBytes, (int)length); // Skip the payload buffer = buffer.Slice(numBytes + (int)length); return true; } private static ReadOnlySpan<byte> GetSpan(in ReadOnlySequence<byte> lengthPrefixBuffer) { if (lengthPrefixBuffer.IsSingleSegment) { return lengthPrefixBuffer.First.Span; } // Should be rare return lengthPrefixBuffer.ToArray(); } }