//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Text;
using TouchSocket.Core;
namespace TouchSocket.Http.WebSockets
{
///
/// WSTools
///
public static class WSTools
{
///
/// 应答。
///
public const string acceptMask = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
///
/// 构建数据
///
///
///
///
///
///
///
public static bool Build(ByteBlock byteBlock, WSDataFrame dataFrame, byte[] buffer, int offset, int length)
{
int payloadLength;
byte[] extLen;
if (length < 126)
{
payloadLength = length;
extLen = new byte[0];
}
else if (length < 65536)
{
payloadLength = 126;
extLen = TouchSocketBitConverter.BigEndian.GetBytes((ushort)length);
}
else
{
payloadLength = 127;
extLen = TouchSocketBitConverter.BigEndian.GetBytes((ulong)length);
}
int header = dataFrame.FIN ? 1 : 0;
header = (header << 1) + (dataFrame.RSV1 ? 1 : 0);
header = (header << 1) + (dataFrame.RSV2 ? 1 : 0);
header = (header << 1) + (dataFrame.RSV3 ? 1 : 0);
header = (header << 4) + (ushort)dataFrame.Opcode;
if (dataFrame.Mask)
{
header = (header << 1) + 1;
}
else
{
header = (header << 1) + 0;
}
header = (header << 7) + payloadLength;
byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes((ushort)header));
if (payloadLength > 125)
{
byteBlock.Write(extLen, 0, extLen.Length);
}
if (dataFrame.Mask)
{
byteBlock.Write(dataFrame.MaskingKey, 0, 4);
}
if (payloadLength > 0)
{
if (dataFrame.Mask)
{
if (byteBlock.Capacity < byteBlock.Pos + length)
{
byteBlock.SetCapacity(byteBlock.Pos + length, true);
}
WSTools.DoMask(byteBlock.Buffer, byteBlock.Pos, buffer, offset, length, dataFrame.MaskingKey);
byteBlock.SetLength(byteBlock.Pos + length);
}
else
{
byteBlock.Write(buffer, offset, length);
}
}
return true;
}
///
/// 计算Base64值
///
///
///
public static string CalculateBase64Key(string str)
{
return (str + acceptMask).ToSha1(Encoding.UTF8).ToBase64();
}
///
/// 获取Base64随即字符串。
///
///
public static string CreateBase64Key()
{
var src = new byte[16];
new Random().NextBytes(src);
return Convert.ToBase64String(src);
}
///
/// 掩码运算
///
///
///
///
///
///
///
public static void DoMask(byte[] storeBuf, int sOffset, byte[] buffer, int offset, int length, byte[] masks)
{
for (var i = 0; i < length; i++)
{
storeBuf[sOffset + i] = (byte)(buffer[offset + i] ^ masks[i % 4]);
}
}
///
/// 获取WS的请求头
///
///
///
///
///
///
public static HttpRequest GetWSRequest(string host, string url, string version, out string base64Key)
{
HttpRequest request = new HttpRequest
{
Method = "GET",
Protocols = "HTTP",
ProtocolVersion = "1.1"
};
request.SetUrl(url);
request.SetHeader(HttpHeaders.Host, host);
request.SetHeader(HttpHeaders.Pragma, "no-cache");
request.SetHeader(HttpHeaders.UserAgent, "TouchSocket.Http.WebSockets");
request.SetHeader(HttpHeaders.Origin, "RRQM");
request.SetHeader(HttpHeaders.AcceptEncoding, "deflate, br");
request.SetHeaderByKey("Connection", "upgrade");
request.SetHeaderByKey("Upgrade", "websocket");
request.SetHeaderByKey("Sec-WebSocket-Version", $"{version}");
base64Key = CreateBase64Key();
request.SetHeaderByKey("Sec-WebSocket-Key", base64Key);
return request;
}
///
/// 获取响应
///
///
///
///
public static bool TryGetResponse(HttpRequest request, HttpResponse response)
{
string upgrade = request.GetHeader(HttpHeaders.Upgrade);
if (string.IsNullOrEmpty(upgrade))
{
return false;
}
string connection = request.GetHeader(HttpHeaders.Connection);
if (string.IsNullOrEmpty(connection))
{
return false;
}
string secWebSocketKey = request.GetHeader("sec-websocket-key");
if (string.IsNullOrEmpty(secWebSocketKey))
{
return false;
}
response.StatusCode = "101";
response.StatusMessage = "switching protocols";
response.SetHeader(HttpHeaders.Connection, "upgrade");
response.SetHeader(HttpHeaders.Upgrade, "websocket");
response.SetHeader("sec-websocket-accept", CalculateBase64Key(secWebSocketKey));
return true;
}
}
}