Got at least one data fetching method working; turns out, we can't use a patched LogicStack to get the data
This commit is contained in:
239
Vendor/EmbedIO-3.5.2/WebSockets/Internal/WebSocketFrame.cs
vendored
Normal file
239
Vendor/EmbedIO-3.5.2/WebSockets/Internal/WebSocketFrame.cs
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using EmbedIO.Net.Internal;
|
||||
using Swan;
|
||||
|
||||
namespace EmbedIO.WebSockets.Internal
|
||||
{
|
||||
internal class WebSocketFrame
|
||||
{
|
||||
internal static readonly byte[] EmptyPingBytes = CreatePingFrame().ToArray();
|
||||
|
||||
internal WebSocketFrame(Opcode opcode, PayloadData payloadData)
|
||||
: this(Fin.Final, opcode, payloadData)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketFrame(Fin fin, Opcode opcode, byte[] data, bool compressed)
|
||||
: this(fin, opcode, new PayloadData(data), compressed)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketFrame(
|
||||
Fin fin,
|
||||
Opcode opcode,
|
||||
PayloadData payloadData,
|
||||
bool compressed = false)
|
||||
{
|
||||
Fin = fin;
|
||||
Rsv1 = IsOpcodeData(opcode) && compressed ? Rsv.On : Rsv.Off;
|
||||
Rsv2 = Rsv.Off;
|
||||
Rsv3 = Rsv.Off;
|
||||
Opcode = opcode;
|
||||
|
||||
var len = payloadData.Length;
|
||||
if (len < 126)
|
||||
{
|
||||
PayloadLength = (byte)len;
|
||||
ExtendedPayloadLength = Array.Empty<byte>();
|
||||
}
|
||||
else if (len < 0x010000)
|
||||
{
|
||||
PayloadLength = 126;
|
||||
ExtendedPayloadLength = ((ushort)len).ToByteArray(Endianness.Big);
|
||||
}
|
||||
else
|
||||
{
|
||||
PayloadLength = 127;
|
||||
ExtendedPayloadLength = len.ToByteArray(Endianness.Big);
|
||||
}
|
||||
|
||||
Mask = Mask.Off;
|
||||
MaskingKey = Array.Empty<byte>();
|
||||
PayloadData = payloadData;
|
||||
}
|
||||
|
||||
internal WebSocketFrame(
|
||||
Fin fin,
|
||||
Rsv rsv1,
|
||||
Rsv rsv2,
|
||||
Rsv rsv3,
|
||||
Opcode opcode,
|
||||
Mask mask,
|
||||
byte payloadLength)
|
||||
{
|
||||
Fin = fin;
|
||||
Rsv1 = rsv1;
|
||||
Rsv2 = rsv2;
|
||||
Rsv3 = rsv3;
|
||||
Opcode = opcode;
|
||||
Mask = mask;
|
||||
PayloadLength = payloadLength;
|
||||
}
|
||||
|
||||
public byte[]? ExtendedPayloadLength { get; internal set; }
|
||||
|
||||
public Fin Fin { get; internal set; }
|
||||
|
||||
public bool IsCompressed => Rsv1 == Rsv.On;
|
||||
|
||||
public bool IsFragment => Fin == Fin.More || Opcode == Opcode.Cont;
|
||||
|
||||
public bool IsMasked => Mask == Mask.On;
|
||||
|
||||
public Mask Mask { get; internal set; }
|
||||
|
||||
public byte[] MaskingKey { get; internal set; }
|
||||
|
||||
public Opcode Opcode { get; internal set; }
|
||||
|
||||
public PayloadData PayloadData { get; internal set; }
|
||||
|
||||
public byte PayloadLength { get; internal set; }
|
||||
|
||||
public Rsv Rsv1 { get; internal set; }
|
||||
|
||||
public Rsv Rsv2 { get; internal set; }
|
||||
|
||||
public Rsv Rsv3 { get; internal set; }
|
||||
|
||||
internal int ExtendedPayloadLengthCount => PayloadLength < 126 ? 0 : (PayloadLength == 126 ? 2 : 8);
|
||||
|
||||
internal ulong FullPayloadLength => PayloadLength < 126
|
||||
? PayloadLength
|
||||
: PayloadLength == 126
|
||||
? BitConverter.ToUInt16(ExtendedPayloadLength.ToHostOrder(Endianness.Big), 0)
|
||||
: BitConverter.ToUInt64(ExtendedPayloadLength.ToHostOrder(Endianness.Big), 0);
|
||||
|
||||
public IEnumerator<byte> GetEnumerator() => ((IEnumerable<byte>)ToArray()).GetEnumerator();
|
||||
|
||||
public string PrintToString()
|
||||
{
|
||||
// Payload Length
|
||||
var payloadLen = PayloadLength;
|
||||
|
||||
// Extended Payload Length
|
||||
var extPayloadLen = payloadLen > 125 ? FullPayloadLength.ToString(CultureInfo.InvariantCulture) : string.Empty;
|
||||
|
||||
// Masking Key
|
||||
var maskingKey = BitConverter.ToString(MaskingKey);
|
||||
|
||||
// Payload Data
|
||||
var payload = payloadLen == 0
|
||||
? string.Empty
|
||||
: payloadLen > 125
|
||||
? "---"
|
||||
: Opcode == Opcode.Text && !(IsFragment || IsMasked || IsCompressed)
|
||||
? PayloadData.ApplicationData.ToArray().ToText()
|
||||
: PayloadData.ToString();
|
||||
|
||||
return $@"
|
||||
FIN: {Fin}
|
||||
RSV1: {Rsv1}
|
||||
RSV2: {Rsv2}
|
||||
RSV3: {Rsv3}
|
||||
Opcode: {Opcode}
|
||||
MASK: {Mask}
|
||||
Payload Length: {payloadLen}
|
||||
Extended Payload Length: {extPayloadLen}
|
||||
Masking Key: {maskingKey}
|
||||
Payload Data: {payload}";
|
||||
}
|
||||
|
||||
public byte[] ToArray()
|
||||
{
|
||||
using var buff = new MemoryStream();
|
||||
var header = (int)Fin;
|
||||
|
||||
header = (header << 1) + (int)Rsv1;
|
||||
header = (header << 1) + (int)Rsv2;
|
||||
header = (header << 1) + (int)Rsv3;
|
||||
header = (header << 4) + (int)Opcode;
|
||||
header = (header << 1) + (int)Mask;
|
||||
header = (header << 7) + PayloadLength;
|
||||
buff.Write(((ushort)header).ToByteArray(Endianness.Big), 0, 2);
|
||||
|
||||
if (PayloadLength > 125)
|
||||
{
|
||||
buff.Write(ExtendedPayloadLength, 0, PayloadLength == 126 ? 2 : 8);
|
||||
}
|
||||
|
||||
if (Mask == Mask.On)
|
||||
{
|
||||
buff.Write(MaskingKey, 0, 4);
|
||||
}
|
||||
|
||||
if (PayloadLength > 0)
|
||||
{
|
||||
var bytes = PayloadData.ToArray();
|
||||
if (PayloadLength < 127)
|
||||
{
|
||||
buff.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
using var input = new MemoryStream(bytes);
|
||||
input.CopyTo(buff, 1024);
|
||||
}
|
||||
}
|
||||
|
||||
return buff.ToArray();
|
||||
}
|
||||
|
||||
public override string ToString() => BitConverter.ToString(ToArray());
|
||||
|
||||
internal static WebSocketFrame CreateCloseFrame(PayloadData? payloadData) => new (Fin.Final, Opcode.Close, payloadData ?? new PayloadData());
|
||||
|
||||
internal static WebSocketFrame CreatePingFrame() => new (Fin.Final, Opcode.Ping, new PayloadData());
|
||||
|
||||
internal static WebSocketFrame CreatePingFrame(byte[] data) => new (Fin.Final, Opcode.Ping, new PayloadData(data));
|
||||
|
||||
internal void Validate(WebSocket webSocket)
|
||||
{
|
||||
if (!IsMasked)
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.ProtocolError, "A frame from a client isn't masked.");
|
||||
}
|
||||
|
||||
if (webSocket.InContinuation && (Opcode == Opcode.Text || Opcode == Opcode.Binary))
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.ProtocolError,
|
||||
"A data frame has been received while receiving continuation frames.");
|
||||
}
|
||||
|
||||
if (IsCompressed && webSocket.Compression == CompressionMethod.None)
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.ProtocolError,
|
||||
"A compressed frame has been received without any agreement for it.");
|
||||
}
|
||||
|
||||
if (Rsv2 == Rsv.On)
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.ProtocolError,
|
||||
"The RSV2 of a frame is non-zero without any negotiation for it.");
|
||||
}
|
||||
|
||||
if (Rsv3 == Rsv.On)
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.ProtocolError,
|
||||
"The RSV3 of a frame is non-zero without any negotiation for it.");
|
||||
}
|
||||
}
|
||||
|
||||
internal void Unmask()
|
||||
{
|
||||
if (Mask == Mask.Off)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mask = Mask.Off;
|
||||
PayloadData.Mask(MaskingKey);
|
||||
MaskingKey = Array.Empty<byte>();
|
||||
}
|
||||
|
||||
private static bool IsOpcodeData(Opcode opcode) => opcode == Opcode.Text || opcode == Opcode.Binary;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user