231 lines
7.6 KiB
C#
231 lines
7.6 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace AspNetCoreModule.Test.WebSocketClient
|
|
{
|
|
public static class WebSocketClientUtility
|
|
{
|
|
public static FrameType GetFrameType(byte[] inputData)
|
|
{
|
|
if(inputData.Length==0)
|
|
return FrameType.NonControlFrame;
|
|
|
|
byte firstByte = inputData[0];
|
|
|
|
switch (firstByte)
|
|
{
|
|
case 0x80:
|
|
return FrameType.ContinuationFrameEnd;
|
|
case 0:
|
|
return FrameType.Continuation;
|
|
case 0x81:
|
|
return FrameType.Text;
|
|
case 0x01:
|
|
return FrameType.SegmentedText;
|
|
case 0x82:
|
|
return FrameType.Binary;
|
|
case 0x02:
|
|
return FrameType.SegmentedBinary;
|
|
case 0x88:
|
|
return FrameType.Close;
|
|
case 0x89:
|
|
return FrameType.Ping;
|
|
case 0x8A:
|
|
return FrameType.Pong;
|
|
}
|
|
return FrameType.NonControlFrame;
|
|
}
|
|
|
|
public static string GetFrameString(byte[] inputData)
|
|
{
|
|
int frameStartingIndex;
|
|
int dataLength;
|
|
return GetFrameString(inputData, out frameStartingIndex, out dataLength);
|
|
}
|
|
|
|
public static string GetFrameString(byte[] inputData, out int frameStartingIndex, out int frameDataLength)
|
|
{
|
|
string content;
|
|
|
|
FrameType frameType = GetFrameType(inputData);
|
|
int startingIndex = 2;
|
|
int dataLength = 0;
|
|
|
|
if (frameType != FrameType.NonControlFrame && frameType != FrameType.ContinuationControlled)
|
|
{
|
|
int frameLength = inputData[1];
|
|
|
|
if (IsFrameMasked(inputData))
|
|
{
|
|
frameLength = inputData[1] ^ 128;
|
|
|
|
if (frameLength < WebSocketConstants.SMALL_LENGTH_FLAG)
|
|
{
|
|
startingIndex = 6;
|
|
dataLength = inputData[1] ^ 128;
|
|
}
|
|
else if (frameLength == WebSocketConstants.SMALL_LENGTH_FLAG)
|
|
{
|
|
startingIndex = 8;
|
|
dataLength = (int)GetFrameSize(inputData, 2, 4);
|
|
}
|
|
else if (frameLength == WebSocketConstants.LARGE_LENGTH_FLAG)
|
|
{
|
|
startingIndex = 14;
|
|
dataLength = (int)GetFrameSize(inputData, 2, 10);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (frameLength < WebSocketConstants.SMALL_LENGTH_FLAG)
|
|
{
|
|
startingIndex = 2;
|
|
dataLength = inputData[1];
|
|
}
|
|
else if (frameLength == WebSocketConstants.SMALL_LENGTH_FLAG)
|
|
{
|
|
startingIndex = 4;
|
|
dataLength = (int)GetFrameSize(inputData, 2, 4);
|
|
}
|
|
else if (frameLength == WebSocketConstants.LARGE_LENGTH_FLAG)
|
|
{
|
|
startingIndex = 10;
|
|
dataLength = (int)GetFrameSize(inputData, 2, 10);
|
|
}
|
|
}
|
|
|
|
content = Encoding.UTF8.GetString(inputData, startingIndex, (inputData.Length - startingIndex < dataLength) ? inputData.Length - startingIndex : dataLength);
|
|
}
|
|
else
|
|
{
|
|
startingIndex = 0;
|
|
dataLength = 0;
|
|
content = Encoding.UTF8.GetString(inputData, 0, inputData.Length);
|
|
}
|
|
|
|
frameStartingIndex = startingIndex;
|
|
frameDataLength = dataLength;
|
|
return content;
|
|
}
|
|
|
|
public static uint GetFrameSize(byte[] inputData, int start, int length)
|
|
{
|
|
byte[] bytes = SubArray(inputData, 2, length - 2);
|
|
|
|
if (BitConverter.IsLittleEndian)
|
|
Array.Reverse(bytes);
|
|
|
|
if (length > 4)
|
|
return BitConverter.ToUInt32(bytes, 0);
|
|
else
|
|
return BitConverter.ToUInt16(bytes, 0);
|
|
}
|
|
|
|
public static byte[] GetFramedTextDataInBytes(string data)
|
|
{
|
|
return GetFramedDataInBytes(0x81, data);
|
|
}
|
|
public static byte[] GetFramedTextDataInBytes(string data, byte opCode)
|
|
{
|
|
return GetFramedDataInBytes(opCode, data);
|
|
}
|
|
|
|
public static byte[] GetFramedBinaryDataInBytes(string data)
|
|
{
|
|
return GetFramedDataInBytes(0x82, data);
|
|
}
|
|
|
|
private static byte[] GetFramedDataInBytes(byte dataType, string data)
|
|
{
|
|
var a = BitConverter.GetBytes(data.Length);
|
|
var framelist = GetByteArrayFromNumber(dataType, data.Length);
|
|
|
|
|
|
byte[] datalist = Encoding.UTF8.GetBytes(data);
|
|
|
|
var frame = JoinTwoArrays(framelist, datalist);
|
|
return frame;
|
|
}
|
|
|
|
|
|
public static byte[] GetByteArrayFromNumber(byte dataType, int number)
|
|
{
|
|
if (number < 126)
|
|
{
|
|
return new byte[] {dataType, (byte)(number | 128),0,0,0,0 };
|
|
}
|
|
else
|
|
{
|
|
byte lengthByte = WebSocketConstants.LARGE_LENGTH_BYTE;
|
|
int lengthBits = 16;
|
|
|
|
if (number < 65536)
|
|
{
|
|
lengthByte = WebSocketConstants.SMALL_LENGTH_BYTE;
|
|
lengthBits = 4;
|
|
}
|
|
|
|
var framelist = new byte[] { dataType, lengthByte };
|
|
string hexValue = (number).ToString("X");
|
|
hexValue = PrependZeroes(hexValue, lengthBits - hexValue.Length);
|
|
|
|
var sizeArray = JoinTwoArrays(StringToByteArray(hexValue), new byte[]{0,0,0,0});
|
|
|
|
return JoinTwoArrays(framelist, sizeArray);
|
|
}
|
|
}
|
|
|
|
public static string PrependZeroes(string hex, int zeroes)
|
|
{
|
|
for (int i = 0; i < zeroes; i++)
|
|
{
|
|
hex = "0" + hex;
|
|
}
|
|
return hex;
|
|
}
|
|
|
|
public static byte[] StringToByteArray(string hex)
|
|
{
|
|
return Enumerable.Range(0, hex.Length)
|
|
.Where(x => x % 2 == 0)
|
|
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
|
|
.ToArray();
|
|
}
|
|
|
|
public static bool IsFrameMasked(byte[] inputData)
|
|
{
|
|
bool frameMasked = false;
|
|
FrameType frameType = GetFrameType(inputData);
|
|
|
|
if (frameType != FrameType.NonControlFrame && inputData[1] > 127)
|
|
frameMasked = true;
|
|
|
|
return frameMasked;
|
|
}
|
|
|
|
public static byte[] JoinTwoArrays(byte[] aArray, byte[] bArray)
|
|
{
|
|
var concat = new byte[aArray.Length + bArray.Length];
|
|
|
|
Buffer.BlockCopy(aArray, 0, concat, 0, aArray.Length);
|
|
Buffer.BlockCopy(bArray, 0, concat, aArray.Length, bArray.Length);
|
|
|
|
return concat;
|
|
|
|
}
|
|
|
|
public static T[] SubArray<T>(this T[] data, int index, int length)
|
|
{
|
|
T[] result = new T[length];
|
|
Array.Copy(data, index, result, 0, length);
|
|
return result;
|
|
}
|
|
|
|
public static string WebSocketUri = null;
|
|
public static int WebSocketVersion { get { return 13; } }
|
|
}
|
|
} |