using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Timers;
using WebSocketSharp.Net;
using WebSocketSharp.Net.WebSockets;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("sta")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("sta.blockhead")]
[assembly: AssemblyDescription("websocket-sharp provides the WebSocket protocol client and server.\r\n\r\nIt supports:\r\n- RFC 6455\r\n- WebSocket Client and Server\r\n- Per-message Compression extension\r\n- Secure Connection\r\n- HTTP Authentication (Basic/Digest)\r\n- Query String, Origin header and Cookies\r\n- Connecting through the HTTP Proxy server\r\n- .NET 3.5 or later (includes compatible)")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("websocket-sharp")]
[assembly: AssemblyTitle("websocket-sharp")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace WebSocketSharp
{
public enum ByteOrder
{
Little,
Big
}
public class CloseEventArgs : EventArgs
{
private bool _clean;
private PayloadData _payloadData;
internal PayloadData PayloadData => _payloadData;
public ushort Code => _payloadData.Code;
public string Reason => _payloadData.Reason ?? string.Empty;
public bool WasClean
{
get
{
return _clean;
}
internal set
{
_clean = value;
}
}
internal CloseEventArgs()
{
_payloadData = PayloadData.Empty;
}
internal CloseEventArgs(ushort code)
: this(code, null)
{
}
internal CloseEventArgs(CloseStatusCode code)
: this((ushort)code, null)
{
}
internal CloseEventArgs(PayloadData payloadData)
{
_payloadData = payloadData;
}
internal CloseEventArgs(ushort code, string reason)
{
_payloadData = new PayloadData(code, reason);
}
internal CloseEventArgs(CloseStatusCode code, string reason)
: this((ushort)code, reason)
{
}
}
public enum CloseStatusCode : ushort
{
Normal = 1000,
Away = 1001,
ProtocolError = 1002,
UnsupportedData = 1003,
Undefined = 1004,
NoStatus = 1005,
Abnormal = 1006,
InvalidData = 1007,
PolicyViolation = 1008,
TooBig = 1009,
MandatoryExtension = 1010,
ServerError = 1011,
TlsHandshakeFailure = 1015
}
public enum CompressionMethod : byte
{
None,
Deflate
}
public class ErrorEventArgs : EventArgs
{
private Exception _exception;
private string _message;
public Exception Exception => _exception;
public string Message => _message;
internal ErrorEventArgs(string message)
: this(message, null)
{
}
internal ErrorEventArgs(string message, Exception exception)
{
_message = message;
_exception = exception;
}
}
public static class Ext
{
private static readonly byte[] _last = new byte[1];
private static readonly int _retry = 5;
private const string _tspecials = "()<>@,;:\\\"/[]?={} \t";
private static byte[] compress(this byte[] data)
{
if (data.LongLength == 0L)
{
return data;
}
using MemoryStream stream = new MemoryStream(data);
return stream.compressToArray();
}
private static MemoryStream compress(this Stream stream)
{
MemoryStream memoryStream = new MemoryStream();
if (stream.Length == 0L)
{
return memoryStream;
}
stream.Position = 0L;
using DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, leaveOpen: true);
stream.CopyTo(deflateStream, 1024);
deflateStream.Close();
memoryStream.Write(_last, 0, 1);
memoryStream.Position = 0L;
return memoryStream;
}
private static byte[] compressToArray(this Stream stream)
{
using MemoryStream memoryStream = stream.compress();
memoryStream.Close();
return memoryStream.ToArray();
}
private static byte[] decompress(this byte[] data)
{
if (data.LongLength == 0L)
{
return data;
}
using MemoryStream stream = new MemoryStream(data);
return stream.decompressToArray();
}
private static MemoryStream decompress(this Stream stream)
{
MemoryStream memoryStream = new MemoryStream();
if (stream.Length == 0L)
{
return memoryStream;
}
stream.Position = 0L;
using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true);
deflateStream.CopyTo(memoryStream, 1024);
memoryStream.Position = 0L;
return memoryStream;
}
private static byte[] decompressToArray(this Stream stream)
{
using MemoryStream memoryStream = stream.decompress();
memoryStream.Close();
return memoryStream.ToArray();
}
private static void times(this ulong n, Action action)
{
for (ulong num = 0uL; num < n; num++)
{
action();
}
}
internal static byte[] Append(this ushort code, string reason)
{
byte[] array = code.InternalToByteArray(ByteOrder.Big);
if (reason != null && reason.Length > 0)
{
List<byte> list = new List<byte>(array);
list.AddRange(Encoding.UTF8.GetBytes(reason));
array = list.ToArray();
}
return array;
}
internal static void Close(this WebSocketSharp.Net.HttpListenerResponse response, WebSocketSharp.Net.HttpStatusCode code)
{
response.StatusCode = (int)code;
response.OutputStream.Close();
}
internal static void CloseWithAuthChallenge(this WebSocketSharp.Net.HttpListenerResponse response, string challenge)
{
response.Headers.InternalSet("WWW-Authenticate", challenge, response: true);
response.Close(WebSocketSharp.Net.HttpStatusCode.Unauthorized);
}
internal static byte[] Compress(this byte[] data, CompressionMethod method)
{
if (method != CompressionMethod.Deflate)
{
return data;
}
return data.compress();
}
internal static Stream Compress(this Stream stream, CompressionMethod method)
{
if (method != CompressionMethod.Deflate)
{
return stream;
}
return stream.compress();
}
internal static byte[] CompressToArray(this Stream stream, CompressionMethod method)
{
if (method != CompressionMethod.Deflate)
{
return stream.ToByteArray();
}
return stream.compressToArray();
}
internal static bool Contains<T>(this IEnumerable<T> source, Func<T, bool> condition)
{
foreach (T item in source)
{
if (condition(item))
{
return true;
}
}
return false;
}
internal static bool ContainsTwice(this string[] values)
{
int len = values.Length;
int end = len - 1;
Func<int, bool> seek = null;
seek = delegate(int idx)
{
if (idx == end)
{
return false;
}
string text = values[idx];
for (int i = idx + 1; i < len; i++)
{
if (values[i] == text)
{
return true;
}
}
return seek(++idx);
};
return seek(0);
}
internal static T[] Copy<T>(this T[] source, int length)
{
T[] array = new T[length];
Array.Copy(source, 0, array, 0, length);
return array;
}
internal static T[] Copy<T>(this T[] source, long length)
{
T[] array = new T[length];
Array.Copy(source, 0L, array, 0L, length);
return array;
}
internal static void CopyTo(this Stream source, Stream destination, int bufferLength)
{
byte[] buffer = new byte[bufferLength];
int num = 0;
while ((num = source.Read(buffer, 0, bufferLength)) > 0)
{
destination.Write(buffer, 0, num);
}
}
internal static void CopyToAsync(this Stream source, Stream destination, int bufferLength, Action completed, Action<Exception> error)
{
byte[] buff = new byte[bufferLength];
AsyncCallback callback = null;
callback = delegate(IAsyncResult ar)
{
try
{
int num = source.EndRead(ar);
if (num <= 0)
{
if (completed != null)
{
completed();
}
}
else
{
destination.Write(buff, 0, num);
source.BeginRead(buff, 0, bufferLength, callback, null);
}
}
catch (Exception obj2)
{
if (error != null)
{
error(obj2);
}
}
};
try
{
source.BeginRead(buff, 0, bufferLength, callback, null);
}
catch (Exception obj)
{
if (error != null)
{
error(obj);
}
}
}
internal static byte[] Decompress(this byte[] data, CompressionMethod method)
{
if (method != CompressionMethod.Deflate)
{
return data;
}
return data.decompress();
}
internal static Stream Decompress(this Stream stream, CompressionMethod method)
{
if (method != CompressionMethod.Deflate)
{
return stream;
}
return stream.decompress();
}
internal static byte[] DecompressToArray(this Stream stream, CompressionMethod method)
{
if (method != CompressionMethod.Deflate)
{
return stream.ToByteArray();
}
return stream.decompressToArray();
}
internal static bool EqualsWith(this int value, char c, Action<int> action)
{
action(value);
return value == c;
}
internal static string GetAbsolutePath(this Uri uri)
{
if (uri.IsAbsoluteUri)
{
return uri.AbsolutePath;
}
string originalString = uri.OriginalString;
if (originalString[0] != '/')
{
return null;
}
int num = originalString.IndexOfAny(new char[2] { '?', '#' });
if (num <= 0)
{
return originalString;
}
return originalString.Substring(0, num);
}
internal static string GetDnsSafeHost(this Uri uri, bool bracketIPv6)
{
if (!bracketIPv6 || uri.HostNameType != UriHostNameType.IPv6)
{
return uri.DnsSafeHost;
}
return uri.Host;
}
internal static string GetMessage(this CloseStatusCode code)
{
return code switch
{
CloseStatusCode.TlsHandshakeFailure => "An error has occurred during a TLS handshake.",
CloseStatusCode.ServerError => "WebSocket server got an internal error.",
CloseStatusCode.MandatoryExtension => "WebSocket client didn't receive expected extension(s).",
CloseStatusCode.TooBig => "A too big message has been received.",
CloseStatusCode.PolicyViolation => "A policy violation has occurred.",
CloseStatusCode.InvalidData => "Invalid data has been received.",
CloseStatusCode.Abnormal => "An exception has occurred.",
CloseStatusCode.UnsupportedData => "Unsupported data has been received.",
CloseStatusCode.ProtocolError => "A WebSocket protocol error has occurred.",
_ => string.Empty,
};
}
internal static string GetName(this string nameAndValue, char separator)
{
int num = nameAndValue.IndexOf(separator);
if (num <= 0)
{
return null;
}
return nameAndValue.Substring(0, num).Trim();
}
internal static string GetValue(this string nameAndValue, char separator)
{
int num = nameAndValue.IndexOf(separator);
if (num <= -1 || num >= nameAndValue.Length - 1)
{
return null;
}
return nameAndValue.Substring(num + 1).Trim();
}
internal static string GetValue(this string nameAndValue, char separator, bool unquote)
{
int num = nameAndValue.IndexOf(separator);
if (num < 0 || num == nameAndValue.Length - 1)
{
return null;
}
string text = nameAndValue.Substring(num + 1).Trim();
if (!unquote)
{
return text;
}
return text.Unquote();
}
internal static byte[] InternalToByteArray(this ushort value, ByteOrder order)
{
byte[] bytes = BitConverter.GetBytes(value);
if (!order.IsHostOrder())
{
Array.Reverse((Array)bytes);
}
return bytes;
}
internal static byte[] InternalToByteArray(this ulong value, ByteOrder order)
{
byte[] bytes = BitConverter.GetBytes(value);
if (!order.IsHostOrder())
{
Array.Reverse((Array)bytes);
}
return bytes;
}
internal static bool IsCompressionExtension(this string value, CompressionMethod method)
{
return value.StartsWith(method.ToExtensionString());
}
internal static bool IsControl(this byte opcode)
{
if (opcode > 7)
{
return opcode < 16;
}
return false;
}
internal static bool IsControl(this Opcode opcode)
{
return (int)opcode >= 8;
}
internal static bool IsData(this byte opcode)
{
if (opcode != 1)
{
return opcode == 2;
}
return true;
}
internal static bool IsData(this Opcode opcode)
{
if (opcode != Opcode.Text)
{
return opcode == Opcode.Binary;
}
return true;
}
internal static bool IsPortNumber(this int value)
{
if (value > 0)
{
return value < 65536;
}
return false;
}
internal static bool IsReserved(this ushort code)
{
if (code != 1004 && code != 1005 && code != 1006)
{
return code == 1015;
}
return true;
}
internal static bool IsReserved(this CloseStatusCode code)
{
if (code != CloseStatusCode.Undefined && code != CloseStatusCode.NoStatus && code != CloseStatusCode.Abnormal)
{
return code == CloseStatusCode.TlsHandshakeFailure;
}
return true;
}
internal static bool IsSupported(this byte opcode)
{
return Enum.IsDefined(typeof(Opcode), opcode);
}
internal static bool IsText(this string value)
{
int length = value.Length;
for (int i = 0; i < length; i++)
{
char c = value[i];
if (c < ' ')
{
if (!Contains("\r\n\t", c))
{
return false;
}
if (c == '\n')
{
i++;
if (i == length)
{
break;
}
c = value[i];
if (!Contains(" \t", c))
{
return false;
}
}
}
else if (c == '\u007f')
{
return false;
}
}
return true;
}
internal static bool IsToken(this string value)
{
foreach (char c in value)
{
if (c < ' ')
{
return false;
}
if (c >= '\u007f')
{
return false;
}
if (Contains("()<>@,;:\\\"/[]?={} \t", c))
{
return false;
}
}
return true;
}
internal static string Quote(this string value)
{
return string.Format("\"{0}\"", value.Replace("\"", "\\\""));
}
internal static byte[] ReadBytes(this Stream stream, int length)
{
byte[] array = new byte[length];
int num = 0;
try
{
int num2 = 0;
while (length > 0)
{
num2 = stream.Read(array, num, length);
if (num2 != 0)
{
num += num2;
length -= num2;
continue;
}
break;
}
}
catch
{
}
return array.SubArray(0, num);
}
internal static byte[] ReadBytes(this Stream stream, long length, int bufferLength)
{
using MemoryStream memoryStream = new MemoryStream();
try
{
byte[] buffer = new byte[bufferLength];
int num = 0;
while (length > 0)
{
if (length < bufferLength)
{
bufferLength = (int)length;
}
num = stream.Read(buffer, 0, bufferLength);
if (num != 0)
{
memoryStream.Write(buffer, 0, num);
length -= num;
continue;
}
break;
}
}
catch
{
}
memoryStream.Close();
return memoryStream.ToArray();
}
internal static void ReadBytesAsync(this Stream stream, int length, Action<byte[]> completed, Action<Exception> error)
{
byte[] buff = new byte[length];
int offset = 0;
int retry = 0;
AsyncCallback callback = null;
callback = delegate(IAsyncResult ar)
{
try
{
int num = stream.EndRead(ar);
if (num == 0 && retry < _retry)
{
retry++;
stream.BeginRead(buff, offset, length, callback, null);
}
else if (num == 0 || num == length)
{
if (completed != null)
{
completed(buff.SubArray(0, offset + num));
}
}
else
{
retry = 0;
offset += num;
length -= num;
stream.BeginRead(buff, offset, length, callback, null);
}
}
catch (Exception obj2)
{
if (error != null)
{
error(obj2);
}
}
};
try
{
stream.BeginRead(buff, offset, length, callback, null);
}
catch (Exception obj)
{
if (error != null)
{
error(obj);
}
}
}
internal static void ReadBytesAsync(this Stream stream, long length, int bufferLength, Action<byte[]> completed, Action<Exception> error)
{
MemoryStream dest = new MemoryStream();
byte[] buff = new byte[bufferLength];
int retry = 0;
Action<long> read = null;
read = delegate(long len)
{
if (len < bufferLength)
{
bufferLength = (int)len;
}
stream.BeginRead(buff, 0, bufferLength, delegate(IAsyncResult ar)
{
try
{
int num = stream.EndRead(ar);
if (num > 0)
{
dest.Write(buff, 0, num);
}
if (num == 0 && retry < _retry)
{
int num2 = retry;
retry = num2 + 1;
read(len);
}
else if (num == 0 || num == len)
{
if (completed != null)
{
dest.Close();
completed(dest.ToArray());
}
dest.Dispose();
}
else
{
retry = 0;
read(len - num);
}
}
catch (Exception obj2)
{
dest.Dispose();
if (error != null)
{
error(obj2);
}
}
}, null);
};
try
{
read(length);
}
catch (Exception obj)
{
dest.Dispose();
if (error != null)
{
error(obj);
}
}
}
internal static string RemovePrefix(this string value, params string[] prefixes)
{
int num = 0;
foreach (string text in prefixes)
{
if (value.StartsWith(text))
{
num = text.Length;
break;
}
}
if (num <= 0)
{
return value;
}
return value.Substring(num);
}
internal static T[] Reverse<T>(this T[] array)
{
int num = array.Length;
T[] array2 = new T[num];
int num2 = num - 1;
for (int i = 0; i <= num2; i++)
{
array2[i] = array[num2 - i];
}
return array2;
}
internal static IEnumerable<string> SplitHeaderValue(this string value, params char[] separators)
{
int len = value.Length;
string seps = new string(separators);
StringBuilder buff = new StringBuilder(32);
bool escaped = false;
bool quoted = false;
for (int i = 0; i < len; i++)
{
char c = value[i];
switch (c)
{
case '"':
if (escaped)
{
escaped = !escaped;
}
else
{
quoted = !quoted;
}
break;
case '\\':
if (i < len - 1 && value[i + 1] == '"')
{
escaped = true;
}
break;
default:
if (Contains(seps, c) && !quoted)
{
yield return buff.ToString();
buff.Length = 0;
continue;
}
break;
}
buff.Append(c);
}
if (buff.Length > 0)
{
yield return buff.ToString();
}
}
internal static byte[] ToByteArray(this Stream stream)
{
using MemoryStream memoryStream = new MemoryStream();
stream.Position = 0L;
stream.CopyTo(memoryStream, 1024);
memoryStream.Close();
return memoryStream.ToArray();
}
internal static CompressionMethod ToCompressionMethod(this string value)
{
foreach (CompressionMethod value2 in Enum.GetValues(typeof(CompressionMethod)))
{
if (value2.ToExtensionString() == value)
{
return value2;
}
}
return CompressionMethod.None;
}
internal static string ToExtensionString(this CompressionMethod method, params string[] parameters)
{
if (method == CompressionMethod.None)
{
return string.Empty;
}
string text = $"permessage-{method.ToString().ToLower()}";
if (parameters == null || parameters.Length == 0)
{
return text;
}
return string.Format("{0}; {1}", text, parameters.ToString("; "));
}
internal static IPAddress ToIPAddress(this string value)
{
if (value == null || value.Length == 0)
{
return null;
}
if (IPAddress.TryParse(value, out IPAddress address))
{
return address;
}
try
{
return Dns.GetHostAddresses(value)[0];
}
catch
{
return null;
}
}
internal static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
return new List<TSource>(source);
}
internal static string ToString(this IPAddress address, bool bracketIPv6)
{
if (!bracketIPv6 || address.AddressFamily != AddressFamily.InterNetworkV6)
{
return address.ToString();
}
return $"[{address.ToString()}]";
}
internal static ushort ToUInt16(this byte[] source, ByteOrder sourceOrder)
{
return BitConverter.ToUInt16(source.ToHostOrder(sourceOrder), 0);
}
internal static ulong ToUInt64(this byte[] source, ByteOrder sourceOrder)
{
return BitConverter.ToUInt64(source.ToHostOrder(sourceOrder), 0);
}
internal static string TrimSlashFromEnd(this string value)
{
string text = value.TrimEnd(new char[1] { '/' });
if (text.Length <= 0)
{
return "/";
}
return text;
}
internal static string TrimSlashOrBackslashFromEnd(this string value)
{
string text = value.TrimEnd('/', '\\');
if (text.Length <= 0)
{
return value[0].ToString();
}
return text;
}
internal static bool TryCreateWebSocketUri(this string uriString, out Uri result, out string message)
{
result = null;
message = null;
Uri uri = uriString.ToUri();
if (uri == null)
{
message = "An invalid URI string.";
return false;
}
if (!uri.IsAbsoluteUri)
{
message = "A relative URI.";
return false;
}
string scheme = uri.Scheme;
if (!(scheme == "ws") && !(scheme == "wss"))
{
message = "The scheme part is not 'ws' or 'wss'.";
return false;
}
int port = uri.Port;
if (port == 0)
{
message = "The port part is zero.";
return false;
}
if (uri.Fragment.Length > 0)
{
message = "It includes the fragment component.";
return false;
}
result = ((port != -1) ? uri : new Uri(string.Format("{0}://{1}:{2}{3}", scheme, uri.Host, (scheme == "ws") ? 80 : 443, uri.PathAndQuery)));
return true;
}
internal static bool TryGetUTF8DecodedString(this byte[] bytes, out string s)
{
s = null;
try
{
s = Encoding.UTF8.GetString(bytes);
}
catch
{
return false;
}
return true;
}
internal static bool TryGetUTF8EncodedBytes(this string s, out byte[] bytes)
{
bytes = null;
try
{
bytes = Encoding.UTF8.GetBytes(s);
}
catch
{
return false;
}
return true;
}
internal static bool TryOpenRead(this FileInfo fileInfo, out FileStream fileStream)
{
fileStream = null;
try
{
fileStream = fileInfo.OpenRead();
}
catch
{
return false;
}
return true;
}
internal static string Unquote(this string value)
{
int num = value.IndexOf('"');
if (num < 0)
{
return value;
}
int num2 = value.LastIndexOf('"') - num - 1;
if (num2 >= 0)
{
if (num2 != 0)
{
return value.Substring(num + 1, num2).Replace("\\\"", "\"");
}
return string.Empty;
}
return value;
}
internal static string UTF8Decode(this byte[] bytes)
{
try
{
return Encoding.UTF8.GetString(bytes);
}
catch
{
return null;
}
}
internal static byte[] UTF8Encode(this string s)
{
return Encoding.UTF8.GetBytes(s);
}
internal static void WriteBytes(this Stream stream, byte[] bytes, int bufferLength)
{
using MemoryStream memoryStream = new MemoryStream(bytes);
memoryStream.CopyTo(stream, bufferLength);
}
internal static void WriteBytesAsync(this Stream stream, byte[] bytes, int bufferLength, Action completed, Action<Exception> error)
{
MemoryStream input = new MemoryStream(bytes);
input.CopyToAsync(stream, bufferLength, delegate
{
if (completed != null)
{
completed();
}
input.Dispose();
}, delegate(Exception ex)
{
input.Dispose();
if (error != null)
{
error(ex);
}
});
}
public static bool Contains(this string value, params char[] chars)
{
if (chars != null && chars.Length != 0)
{
if (value != null && value.Length != 0)
{
return value.IndexOfAny(chars) > -1;
}
return false;
}
return true;
}
public static bool Contains(this NameValueCollection collection, string name)
{
if (collection == null || collection.Count <= 0)
{
return false;
}
return collection[name] != null;
}
public static bool Contains(this NameValueCollection collection, string name, string value)
{
if (collection == null || collection.Count == 0)
{
return false;
}
string text = collection[name];
if (text == null)
{
return false;
}
string[] array = text.Split(new char[1] { ',' });
for (int i = 0; i < array.Length; i++)
{
if (array[i].Trim().Equals(value, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
public static void Emit(this EventHandler eventHandler, object sender, EventArgs e)
{
eventHandler?.Invoke(sender, e);
}
public static void Emit<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e) where TEventArgs : EventArgs
{
eventHandler?.Invoke(sender, e);
}
public static WebSocketSharp.Net.CookieCollection GetCookies(this NameValueCollection headers, bool response)
{
string name = (response ? "Set-Cookie" : "Cookie");
if (headers == null || !headers.Contains(name))
{
return new WebSocketSharp.Net.CookieCollection();
}
return WebSocketSharp.Net.CookieCollection.Parse(headers[name], response);
}
public static string GetDescription(this WebSocketSharp.Net.HttpStatusCode code)
{
return ((int)code).GetStatusDescription();
}
public static string GetStatusDescription(this int code)
{
return code switch
{
100 => "Continue",
101 => "Switching Protocols",
102 => "Processing",
200 => "OK",
201 => "Created",
202 => "Accepted",
203 => "Non-Authoritative Information",
204 => "No Content",
205 => "Reset Content",
206 => "Partial Content",
207 => "Multi-Status",
300 => "Multiple Choices",
301 => "Moved Permanently",
302 => "Found",
303 => "See Other",
304 => "Not Modified",
305 => "Use Proxy",
307 => "Temporary Redirect",
400 => "Bad Request",
401 => "Unauthorized",
402 => "Payment Required",
403 => "Forbidden",
404 => "Not Found",
405 => "Method Not Allowed",
406 => "Not Acceptable",
407 => "Proxy Authentication Required",
408 => "Request Timeout",
409 => "Conflict",
410 => "Gone",
411 => "Length Required",
412 => "Precondition Failed",
413 => "Request Entity Too Large",
414 => "Request-Uri Too Long",
415 => "Unsupported Media Type",
416 => "Requested Range Not Satisfiable",
417 => "Expectation Failed",
422 => "Unprocessable Entity",
423 => "Locked",
424 => "Failed Dependency",
500 => "Internal Server Error",
501 => "Not Implemented",
502 => "Bad Gateway",
503 => "Service Unavailable",
504 => "Gateway Timeout",
505 => "Http Version Not Supported",
507 => "Insufficient Storage",
_ => string.Empty,
};
}
public static bool IsCloseStatusCode(this ushort value)
{
if (value > 999)
{
return value < 5000;
}
return false;
}
public static bool IsEnclosedIn(this string value, char c)
{
if (value != null && value.Length > 1 && value[0] == c)
{
return value[value.Length - 1] == c;
}
return false;
}
public static bool IsHostOrder(this ByteOrder order)
{
return BitConverter.IsLittleEndian == (order == ByteOrder.Little);
}
public static bool IsLocal(this IPAddress address)
{
if (address == null)
{
return false;
}
if (address.Equals(IPAddress.Any))
{
return true;
}
if (address.Equals(IPAddress.Loopback))
{
return true;
}
if (Socket.OSSupportsIPv6)
{
if (address.Equals(IPAddress.IPv6Any))
{
return true;
}
if (address.Equals(IPAddress.IPv6Loopback))
{
return true;
}
}
IPAddress[] hostAddresses = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress obj in hostAddresses)
{
if (address.Equals(obj))
{
return true;
}
}
return false;
}
public static bool IsNullOrEmpty(this string value)
{
if (value != null)
{
return value.Length == 0;
}
return true;
}
public static bool IsPredefinedScheme(this string value)
{
if (value == null || value.Length < 2)
{
return false;
}
switch (value[0])
{
case 'h':
if (!(value == "http"))
{
return value == "https";
}
return true;
case 'w':
if (!(value == "ws"))
{
return value == "wss";
}
return true;
case 'f':
if (!(value == "file"))
{
return value == "ftp";
}
return true;
case 'g':
return value == "gopher";
case 'm':
return value == "mailto";
case 'n':
{
char c = value[1];
if (c != 'e')
{
return value == "nntp";
}
if (!(value == "news") && !(value == "net.pipe"))
{
return value == "net.tcp";
}
return true;
}
default:
return false;
}
}
public static bool IsUpgradeTo(this WebSocketSharp.Net.HttpListenerRequest request, string protocol)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
if (protocol == null)
{
throw new ArgumentNullException("protocol");
}
if (protocol.Length == 0)
{
throw new ArgumentException("An empty string.", "protocol");
}
if (request.Headers.Contains("Upgrade", protocol))
{
return request.Headers.Contains("Connection", "Upgrade");
}
return false;
}
public static bool MaybeUri(this string value)
{
if (value == null || value.Length == 0)
{
return false;
}
int num = value.IndexOf(':');
if (num == -1)
{
return false;
}
if (num >= 10)
{
return false;
}
return value.Substring(0, num).IsPredefinedScheme();
}
public static T[] SubArray<T>(this T[] array, int startIndex, int length)
{
int num;
if (array == null || (num = array.Length) == 0)
{
return new T[0];
}
if (startIndex < 0 || length <= 0 || startIndex + length > num)
{
return new T[0];
}
if (startIndex == 0 && length == num)
{
return array;
}
T[] array2 = new T[length];
Array.Copy(array, startIndex, array2, 0, length);
return array2;
}
public static T[] SubArray<T>(this T[] array, long startIndex, long length)
{
long num;
if (array == null || (num = array.LongLength) == 0L)
{
return new T[0];
}
if (startIndex < 0 || length <= 0 || startIndex + length > num)
{
return new T[0];
}
if (startIndex == 0L && length == num)
{
return array;
}
T[] array2 = new T[length];
Array.Copy(array, startIndex, array2, 0L, length);
return array2;
}
public static void Times(this int n, Action action)
{
if (n > 0 && action != null)
{
((ulong)n).times(action);
}
}
public static void Times(this long n, Action action)
{
if (n > 0 && action != null)
{
((ulong)n).times(action);
}
}
public static void Times(this uint n, Action action)
{
if (n != 0 && action != null)
{
times(n, action);
}
}
public static void Times(this ulong n, Action action)
{
if (n != 0 && action != null)
{
n.times(action);
}
}
public static void Times(this int n, Action<int> action)
{
if (n > 0 && action != null)
{
for (int i = 0; i < n; i++)
{
action(i);
}
}
}
public static void Times(this long n, Action<long> action)
{
if (n > 0 && action != null)
{
for (long num = 0L; num < n; num++)
{
action(num);
}
}
}
public static void Times(this uint n, Action<uint> action)
{
if (n != 0 && action != null)
{
for (uint num = 0u; num < n; num++)
{
action(num);
}
}
}
public static void Times(this ulong n, Action<ulong> action)
{
if (n != 0 && action != null)
{
for (ulong num = 0uL; num < n; num++)
{
action(num);
}
}
}
public static T To<T>(this byte[] source, ByteOrder sourceOrder) where T : struct
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (source.Length == 0)
{
return default(T);
}
Type typeFromHandle = typeof(T);
byte[] value = source.ToHostOrder(sourceOrder);
if (!(typeFromHandle == typeof(bool)))
{
if (!(typeFromHandle == typeof(char)))
{
if (!(typeFromHandle == typeof(double)))
{
if (!(typeFromHandle == typeof(short)))
{
if (!(typeFromHandle == typeof(int)))
{
if (!(typeFromHandle == typeof(long)))
{
if (!(typeFromHandle == typeof(float)))
{
if (!(typeFromHandle == typeof(ushort)))
{
if (!(typeFromHandle == typeof(uint)))
{
if (!(typeFromHandle == typeof(ulong)))
{
return default(T);
}
return (T)(object)BitConverter.ToUInt64(value, 0);
}
return (T)(object)BitConverter.ToUInt32(value, 0);
}
return (T)(object)BitConverter.ToUInt16(value, 0);
}
return (T)(object)BitConverter.ToSingle(value, 0);
}
return (T)(object)BitConverter.ToInt64(value, 0);
}
return (T)(object)BitConverter.ToInt32(value, 0);
}
return (T)(object)BitConverter.ToInt16(value, 0);
}
return (T)(object)BitConverter.ToDouble(value, 0);
}
return (T)(object)BitConverter.ToChar(value, 0);
}
return (T)(object)BitConverter.ToBoolean(value, 0);
}
public static byte[] ToByteArray<T>(this T value, ByteOrder order) where T : struct
{
Type typeFromHandle = typeof(T);
byte[] array = ((typeFromHandle == typeof(bool)) ? BitConverter.GetBytes((bool)(object)value) : ((!(typeFromHandle == typeof(byte))) ? ((typeFromHandle == typeof(char)) ? BitConverter.GetBytes((char)(object)value) : ((typeFromHandle == typeof(double)) ? BitConverter.GetBytes((double)(object)value) : ((typeFromHandle == typeof(short)) ? BitConverter.GetBytes((short)(object)value) : ((typeFromHandle == typeof(int)) ? BitConverter.GetBytes((int)(object)value) : ((typeFromHandle == typeof(long)) ? BitConverter.GetBytes((long)(object)value) : ((typeFromHandle == typeof(float)) ? BitConverter.GetBytes((float)(object)value) : ((typeFromHandle == typeof(ushort)) ? BitConverter.GetBytes((ushort)(object)value) : ((typeFromHandle == typeof(uint)) ? BitConverter.GetBytes((uint)(object)value) : ((typeFromHandle == typeof(ulong)) ? BitConverter.GetBytes((ulong)(object)value) : WebSocket.EmptyBytes))))))))) : new byte[1] { (byte)(object)value }));
if (array.Length > 1 && !order.IsHostOrder())
{
Array.Reverse((Array)array);
}
return array;
}
public static byte[] ToHostOrder(this byte[] source, ByteOrder sourceOrder)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (source.Length <= 1 || sourceOrder.IsHostOrder())
{
return source;
}
return source.Reverse();
}
public static string ToString<T>(this T[] array, string separator)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
int num = array.Length;
if (num == 0)
{
return string.Empty;
}
if (separator == null)
{
separator = string.Empty;
}
StringBuilder buff = new StringBuilder(64);
(num - 1).Times(delegate(int i)
{
buff.AppendFormat("{0}{1}", array[i].ToString(), separator);
});
buff.Append(array[num - 1].ToString());
return buff.ToString();
}
public static Uri ToUri(this string value)
{
Uri.TryCreate(value, value.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out Uri result);
return result;
}
public static string UrlDecode(this string value)
{
if (value == null || value.Length <= 0)
{
return value;
}
return HttpUtility.UrlDecode(value);
}
public static string UrlEncode(this string value)
{
if (value == null || value.Length <= 0)
{
return value;
}
return HttpUtility.UrlEncode(value);
}
public static void WriteContent(this WebSocketSharp.Net.HttpListenerResponse response, byte[] content)
{
if (response == null)
{
throw new ArgumentNullException("response");
}
if (content == null)
{
throw new ArgumentNullException("content");
}
long num = content.LongLength;
if (num == 0L)
{
response.Close();
return;
}
response.ContentLength64 = num;
Stream outputStream = response.OutputStream;
if (num <= int.MaxValue)
{
outputStream.Write(content, 0, (int)num);
}
else
{
outputStream.WriteBytes(content, 1024);
}
outputStream.Close();
}
}
internal enum Fin : byte
{
More,
Final
}
internal abstract class HttpBase
{
private NameValueCollection _headers;
private const int _headersMaxLength = 8192;
private Version _version;
internal byte[] EntityBodyData;
protected const string CrLf = "\r\n";
public string EntityBody
{
get
{
if (EntityBodyData == null || EntityBodyData.LongLength == 0L)
{
return string.Empty;
}
Encoding encoding = null;
string text = _headers["Content-Type"];
if (text != null && text.Length > 0)
{
encoding = HttpUtility.GetEncoding(text);
}
return (encoding ?? Encoding.UTF8).GetString(EntityBodyData);
}
}
public NameValueCollection Headers => _headers;
public Version ProtocolVersion => _version;
protected HttpBase(Version version, NameValueCollection headers)
{
_version = version;
_headers = headers;
}
private static byte[] readEntityBody(Stream stream, string length)
{
if (!long.TryParse(length, out var result))
{
throw new ArgumentException("Cannot be parsed.", "length");
}
if (result < 0)
{
throw new ArgumentOutOfRangeException("length", "Less than zero.");
}
if (result <= 1024)
{
if (result <= 0)
{
return null;
}
return stream.ReadBytes((int)result);
}
return stream.ReadBytes(result, 1024);
}
private static string[] readHeaders(Stream stream, int maxLength)
{
List<byte> buff = new List<byte>();
int cnt = 0;
Action<int> action = delegate(int i)
{
if (i == -1)
{
throw new EndOfStreamException("The header cannot be read from the data source.");
}
buff.Add((byte)i);
cnt++;
};
bool flag = false;
while (cnt < maxLength)
{
if (stream.ReadByte().EqualsWith('\r', action) && stream.ReadByte().EqualsWith('\n', action) && stream.ReadByte().EqualsWith('\r', action) && stream.ReadByte().EqualsWith('\n', action))
{
flag = true;
break;
}
}
if (!flag)
{
throw new WebSocketException("The length of header part is greater than the max length.");
}
return Encoding.UTF8.GetString(buff.ToArray()).Replace("\r\n ", " ").Replace("\r\n\t", " ")
.Split(new string[1] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
}
protected static T Read<T>(Stream stream, Func<string[], T> parser, int millisecondsTimeout) where T : HttpBase
{
bool timeout = false;
System.Threading.Timer timer = new System.Threading.Timer(delegate
{
timeout = true;
stream.Close();
}, null, millisecondsTimeout, -1);
T val = null;
Exception ex = null;
try
{
val = parser(readHeaders(stream, 8192));
string text = val.Headers["Content-Length"];
if (text != null && text.Length > 0)
{
val.EntityBodyData = readEntityBody(stream, text);
}
}
catch (Exception ex2)
{
ex = ex2;
}
finally
{
timer.Change(-1, -1);
timer.Dispose();
}
string text2 = (timeout ? "A timeout has occurred while reading an HTTP request/response." : ((ex != null) ? "An exception has occurred while reading an HTTP request/response." : null));
if (text2 != null)
{
throw new WebSocketException(text2, ex);
}
return val;
}
public byte[] ToByteArray()
{
return Encoding.UTF8.GetBytes(ToString());
}
}
internal class HttpRequest : HttpBase
{
private string _method;
private string _uri;
private bool _websocketRequest;
private bool _websocketRequestSet;
public AuthenticationResponse AuthenticationResponse
{
get
{
string text = base.Headers["Authorization"];
if (text == null || text.Length <= 0)
{
return null;
}
return AuthenticationResponse.Parse(text);
}
}
public WebSocketSharp.Net.CookieCollection Cookies => base.Headers.GetCookies(response: false);
public string HttpMethod => _method;
public bool IsWebSocketRequest
{
get
{
if (!_websocketRequestSet)
{
NameValueCollection headers = base.Headers;
_websocketRequest = _method == "GET" && base.ProtocolVersion > WebSocketSharp.Net.HttpVersion.Version10 && headers.Contains("Upgrade", "websocket") && headers.Contains("Connection", "Upgrade");
_websocketRequestSet = true;
}
return _websocketRequest;
}
}
public string RequestUri => _uri;
private HttpRequest(string method, string uri, Version version, NameValueCollection headers)
: base(version, headers)
{
_method = method;
_uri = uri;
}
internal HttpRequest(string method, string uri)
: this(method, uri, WebSocketSharp.Net.HttpVersion.Version11, new NameValueCollection())
{
base.Headers["User-Agent"] = "websocket-sharp/1.0";
}
internal static HttpRequest CreateConnectRequest(Uri uri)
{
string dnsSafeHost = uri.DnsSafeHost;
int port = uri.Port;
string text = $"{dnsSafeHost}:{port}";
HttpRequest httpRequest = new HttpRequest("CONNECT", text);
httpRequest.Headers["Host"] = ((port == 80) ? dnsSafeHost : text);
return httpRequest;
}
internal static HttpRequest CreateWebSocketRequest(Uri uri)
{
HttpRequest httpRequest = new HttpRequest("GET", uri.PathAndQuery);
NameValueCollection headers = httpRequest.Headers;
int port = uri.Port;
string scheme = uri.Scheme;
headers["Host"] = (((port == 80 && scheme == "ws") || (port == 443 && scheme == "wss")) ? uri.DnsSafeHost : uri.Authority);
headers["Upgrade"] = "websocket";
headers["Connection"] = "Upgrade";
return httpRequest;
}
internal HttpResponse GetResponse(Stream stream, int millisecondsTimeout)
{
byte[] array = ToByteArray();
stream.Write(array, 0, array.Length);
return HttpBase.Read(stream, HttpResponse.Parse, millisecondsTimeout);
}
internal static HttpRequest Parse(string[] headerParts)
{
string[] array = headerParts[0].Split(new char[1] { ' ' }, 3);
if (array.Length != 3)
{
throw new ArgumentException("Invalid request line: " + headerParts[0]);
}
WebSocketSharp.Net.WebHeaderCollection webHeaderCollection = new WebSocketSharp.Net.WebHeaderCollection();
for (int i = 1; i < headerParts.Length; i++)
{
webHeaderCollection.InternalSet(headerParts[i], response: false);
}
return new HttpRequest(array[0], array[1], new Version(array[2].Substring(5)), webHeaderCollection);
}
internal static HttpRequest Read(Stream stream, int millisecondsTimeout)
{
return HttpBase.Read(stream, Parse, millisecondsTimeout);
}
public void SetCookies(WebSocketSharp.Net.CookieCollection cookies)
{
if (cookies == null || cookies.Count == 0)
{
return;
}
StringBuilder stringBuilder = new StringBuilder(64);
foreach (WebSocketSharp.Net.Cookie item in cookies.Sorted)
{
if (!item.Expired)
{
stringBuilder.AppendFormat("{0}; ", item.ToString());
}
}
int length = stringBuilder.Length;
if (length > 2)
{
stringBuilder.Length = length - 2;
base.Headers["Cookie"] = stringBuilder.ToString();
}
}
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder(64);
stringBuilder.AppendFormat("{0} {1} HTTP/{2}{3}", _method, _uri, base.ProtocolVersion, "\r\n");
NameValueCollection headers = base.Headers;
string[] allKeys = headers.AllKeys;
foreach (string text in allKeys)
{
stringBuilder.AppendFormat("{0}: {1}{2}", text, headers[text], "\r\n");
}
stringBuilder.Append("\r\n");
string entityBody = base.EntityBody;
if (entityBody.Length > 0)
{
stringBuilder.Append(entityBody);
}
return stringBuilder.ToString();
}
}
internal class HttpResponse : HttpBase
{
private string _code;
private string _reason;
public WebSocketSharp.Net.CookieCollection Cookies => base.Headers.GetCookies(response: true);
public bool HasConnectionClose => base.Headers.Contains("Connection", "close");
public bool IsProxyAuthenticationRequired => _code == "407";
public bool IsRedirect
{
get
{
if (!(_code == "301"))
{
return _code == "302";
}
return true;
}
}
public bool IsUnauthorized => _code == "401";
public bool IsWebSocketResponse
{
get
{
NameValueCollection headers = base.Headers;
if (base.ProtocolVersion > WebSocketSharp.Net.HttpVersion.Version10 && _code == "101" && headers.Contains("Upgrade", "websocket"))
{
return headers.Contains("Connection", "Upgrade");
}
return false;
}
}
public string Reason => _reason;
public string StatusCode => _code;
private HttpResponse(string code, string reason, Version version, NameValueCollection headers)
: base(version, headers)
{
_code = code;
_reason = reason;
}
internal HttpResponse(WebSocketSharp.Net.HttpStatusCode code)
: this(code, code.GetDescription())
{
}
internal HttpResponse(WebSocketSharp.Net.HttpStatusCode code, string reason)
: this(((int)code).ToString(), reason, WebSocketSharp.Net.HttpVersion.Version11, new NameValueCollection())
{
base.Headers["Server"] = "websocket-sharp/1.0";
}
internal static HttpResponse CreateCloseResponse(WebSocketSharp.Net.HttpStatusCode code)
{
HttpResponse httpResponse = new HttpResponse(code);
httpResponse.Headers["Connection"] = "close";
return httpResponse;
}
internal static HttpResponse CreateUnauthorizedResponse(string challenge)
{
HttpResponse httpResponse = new HttpResponse(WebSocketSharp.Net.HttpStatusCode.Unauthorized);
httpResponse.Headers["WWW-Authenticate"] = challenge;
return httpResponse;
}
internal static HttpResponse CreateWebSocketResponse()
{
HttpResponse httpResponse = new HttpResponse(WebSocketSharp.Net.HttpStatusCode.SwitchingProtocols);
NameValueCollection headers = httpResponse.Headers;
headers["Upgrade"] = "websocket";
headers["Connection"] = "Upgrade";
return httpResponse;
}
internal static HttpResponse Parse(string[] headerParts)
{
string[] array = headerParts[0].Split(new char[1] { ' ' }, 3);
if (array.Length != 3)
{
throw new ArgumentException("Invalid status line: " + headerParts[0]);
}
WebSocketSharp.Net.WebHeaderCollection webHeaderCollection = new WebSocketSharp.Net.WebHeaderCollection();
for (int i = 1; i < headerParts.Length; i++)
{
webHeaderCollection.InternalSet(headerParts[i], response: true);
}
return new HttpResponse(array[1], array[2], new Version(array[0].Substring(5)), webHeaderCollection);
}
internal static HttpResponse Read(Stream stream, int millisecondsTimeout)
{
return HttpBase.Read(stream, Parse, millisecondsTimeout);
}
public void SetCookies(WebSocketSharp.Net.CookieCollection cookies)
{
if (cookies == null || cookies.Count == 0)
{
return;
}
NameValueCollection headers = base.Headers;
foreach (WebSocketSharp.Net.Cookie item in cookies.Sorted)
{
headers.Add("Set-Cookie", item.ToResponseString());
}
}
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder(64);
stringBuilder.AppendFormat("HTTP/{0} {1} {2}{3}", base.ProtocolVersion, _code, _reason, "\r\n");
NameValueCollection headers = base.Headers;
string[] allKeys = headers.AllKeys;
foreach (string text in allKeys)
{
stringBuilder.AppendFormat("{0}: {1}{2}", text, headers[text], "\r\n");
}
stringBuilder.Append("\r\n");
string entityBody = base.EntityBody;
if (entityBody.Length > 0)
{
stringBuilder.Append(entityBody);
}
return stringBuilder.ToString();
}
}
public class LogData
{
private StackFrame _caller;
private DateTime _date;
private LogLevel _level;
private string _message;
public StackFrame Caller => _caller;
public DateTime Date => _date;
public LogLevel Level => _level;
public string Message => _message;
internal LogData(LogLevel level, StackFrame caller, string message)
{
_level = level;
_caller = caller;
_message = message ?? string.Empty;
_date = DateTime.Now;
}
public override string ToString()
{
string text = $"{_date}|{_level,-5}|";
MethodBase method = _caller.GetMethod();
Type declaringType = method.DeclaringType;
string arg = $"{text}{declaringType.Name}.{method.Name}|";
string[] array = _message.Replace("\r\n", "\n").TrimEnd(new char[1] { '\n' }).Split(new char[1] { '\n' });
if (array.Length <= 1)
{
return $"{arg}{_message}";
}
StringBuilder stringBuilder = new StringBuilder($"{arg}{array[0]}\n", 64);
string format = $"{{0,{text.Length}}}{{1}}\n";
for (int i = 1; i < array.Length; i++)
{
stringBuilder.AppendFormat(format, "", array[i]);
}
stringBuilder.Length--;
return stringBuilder.ToString();
}
}
public class Logger
{
private volatile string _file;
private volatile LogLevel _level;
private Action<LogData, string> _output;
private object _sync;
public string File
{
get
{
return _file;
}
set
{
lock (_sync)
{
_file = value;
Warn($"The current path to the log file has been changed to {_file}.");
}
}
}
public LogLevel Level
{
get
{
return _level;
}
set
{
lock (_sync)
{
_level = value;
Warn($"The current logging level has been changed to {_level}.");
}
}
}
public Action<LogData, string> Output
{
get
{
return _output;
}
set
{
lock (_sync)
{
_output = value ?? new Action<LogData, string>(defaultOutput);
Warn("The current output action has been changed.");
}
}
}
public Logger()
: this(LogLevel.Error, null, null)
{
}
public Logger(LogLevel level)
: this(level, null, null)
{
}
public Logger(LogLevel level, string file, Action<LogData, string> output)
{
_level = level;
_file = file;
_output = output ?? new Action<LogData, string>(defaultOutput);
_sync = new object();
}
private static void defaultOutput(LogData data, string path)
{
string value = data.ToString();
Console.WriteLine(value);
if (path != null && path.Length > 0)
{
writeToFile(value, path);
}
}
private void output(string message, LogLevel level)
{
lock (_sync)
{
if (_level > level)
{
return;
}
LogData logData = null;
try
{
logData = new LogData(level, new StackFrame(2, needFileInfo: true), message);
_output(logData, _file);
}
catch (Exception ex)
{
logData = new LogData(LogLevel.Fatal, new StackFrame(0, needFileInfo: true), ex.Message);
Console.WriteLine(logData.ToString());
}
}
}
private static void writeToFile(string value, string path)
{
using StreamWriter writer = new StreamWriter(path, append: true);
using TextWriter textWriter = TextWriter.Synchronized(writer);
textWriter.WriteLine(value);
}
public void Debug(string message)
{
if (_level <= LogLevel.Debug)
{
output(message, LogLevel.Debug);
}
}
public void Error(string message)
{
if (_level <= LogLevel.Error)
{
output(message, LogLevel.Error);
}
}
public void Fatal(string message)
{
output(message, LogLevel.Fatal);
}
public void Info(string message)
{
if (_level <= LogLevel.Info)
{
output(message, LogLevel.Info);
}
}
public void Trace(string message)
{
if (_level <= LogLevel.Trace)
{
output(message, LogLevel.Trace);
}
}
public void Warn(string message)
{
if (_level <= LogLevel.Warn)
{
output(message, LogLevel.Warn);
}
}
}
public enum LogLevel
{
Trace,
Debug,
Info,
Warn,
Error,
Fatal
}
internal enum Mask : byte
{
Off,
On
}
public class MessageEventArgs : EventArgs
{
private string _data;
private bool _dataSet;
private Opcode _opcode;
private byte[] _rawData;
internal Opcode Opcode => _opcode;
public string Data
{
get
{
setData();
return _data;
}
}
public bool IsBinary => _opcode == Opcode.Binary;
public bool IsPing => _opcode == Opcode.Ping;
public bool IsText => _opcode == Opcode.Text;
public byte[] RawData
{
get
{
setData();
return _rawData;
}
}
internal MessageEventArgs(WebSocketFrame frame)
{
_opcode = frame.Opcode;
_rawData = frame.PayloadData.ApplicationData;
}
internal MessageEventArgs(Opcode opcode, byte[] rawData)
{
if ((ulong)rawData.LongLength > PayloadData.MaxLength)
{
throw new WebSocketException(CloseStatusCode.TooBig);
}
_opcode = opcode;
_rawData = rawData;
}
private void setData()
{
if (!_dataSet)
{
if (_opcode == Opcode.Binary)
{
_dataSet = true;
return;
}
_data = _rawData.UTF8Decode();
_dataSet = true;
}
}
}
internal enum Opcode : byte
{
Cont = 0,
Text = 1,
Binary = 2,
Close = 8,
Ping = 9,
Pong = 10
}
internal class PayloadData : IEnumerable<byte>, IEnumerable
{
private ushort _code;
private bool _codeSet;
private byte[] _data;
private long _extDataLength;
private long _length;
private string _reason;
private bool _reasonSet;
public static readonly PayloadData Empty;
public static readonly ulong MaxLength;
internal ushort Code
{
get
{
if (!_codeSet)
{
_code = (ushort)((_length > 1) ? _data.SubArray(0, 2).ToUInt16(ByteOrder.Big) : 1005);
_codeSet = true;
}
return _code;
}
}
internal long ExtensionDataLength
{
get
{
return _extDataLength;
}
set
{
_extDataLength = value;
}
}
internal bool HasReservedCode
{
get
{
if (_length > 1)
{
return Code.IsReserved();
}
return false;
}
}
internal string Reason
{
get
{
if (!_reasonSet)
{
_reason = ((_length > 2) ? _data.SubArray(2L, _length - 2).UTF8Decode() : string.Empty);
_reasonSet = true;
}
return _reason;
}
}
public byte[] ApplicationData
{
get
{
if (_extDataLength <= 0)
{
return _data;
}
return _data.SubArray(_extDataLength, _length - _extDataLength);
}
}
public byte[] ExtensionData
{
get
{
if (_extDataLength <= 0)
{
return WebSocket.EmptyBytes;
}
return _data.SubArray(0L, _extDataLength);
}
}
public ulong Length => (ulong)_length;
static PayloadData()
{
Empty = new PayloadData();
MaxLength = 9223372036854775807uL;
}
internal PayloadData()
{
_code = 1005;
_reason = string.Empty;
_data = WebSocket.EmptyBytes;
_codeSet = true;
_reasonSet = true;
}
internal PayloadData(byte[] data)
: this(data, data.LongLength)
{
}
internal PayloadData(byte[] data, long length)
{
_data = data;
_length = length;
}
internal PayloadData(ushort code, string reason)
{
_code = code;
_reason = reason ?? string.Empty;
_data = code.Append(reason);
_length = _data.LongLength;
_codeSet = true;
_reasonSet = true;
}
internal void Mask(byte[] key)
{
for (long num = 0L; num < _length; num++)
{
_data[num] ^= key[num % 4];
}
}
public IEnumerator<byte> GetEnumerator()
{
byte[] data = _data;
for (int i = 0; i < data.Length; i++)
{
yield return data[i];
}
}
public byte[] ToArray()
{
return _data;
}
public override string ToString()
{
return BitConverter.ToString(_data);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
internal enum Rsv : byte
{
Off,
On
}
public class WebSocket : IDisposable
{
private AuthenticationChallenge _authChallenge;
private string _base64Key;
private bool _client;
private Action _closeContext;
private CompressionMethod _compression;
private WebSocketContext _context;
private WebSocketSharp.Net.CookieCollection _cookies;
private WebSocketSharp.Net.NetworkCredential _credentials;
private bool _emitOnPing;
private bool _enableRedirection;
private string _extensions;
private bool _extensionsRequested;
private object _forMessageEventQueue;
private object _forPing;
private object _forSend;
private object _forState;
private MemoryStream _fragmentsBuffer;
private bool _fragmentsCompressed;
private Opcode _fragmentsOpcode;
private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private Func<WebSocketContext, string> _handshakeRequestChecker;
private bool _ignoreExtensions;
private bool _inContinuation;
private volatile bool _inMessage;
private volatile Logger _logger;
private static readonly int _maxRetryCountForConnect;
private Action<MessageEventArgs> _message;
private Queue<MessageEventArgs> _messageEventQueue;
private uint _nonceCount;
private string _origin;
private ManualResetEvent _pongReceived;
private bool _preAuth;
private string _protocol;
private string[] _protocols;
private bool _protocolsRequested;
private WebSocketSharp.Net.NetworkCredential _proxyCredentials;
private Uri _proxyUri;
private volatile WebSocketState _readyState;
private ManualResetEvent _receivingExited;
private int _retryCountForConnect;
private bool _secure;
private ClientSslConfiguration _sslConfig;
private Stream _stream;
private TcpClient _tcpClient;
private Uri _uri;
private const string _version = "13";
private TimeSpan _waitTime;
internal static readonly byte[] EmptyBytes;
public static int FragmentLength;
internal static readonly RandomNumberGenerator RandomNumber;
internal WebSocketSharp.Net.CookieCollection CookieCollection => _cookies;
internal Func<WebSocketContext, string> CustomHandshakeRequestChecker
{
get
{
return _handshakeRequestChecker;
}
set
{
_handshakeRequestChecker = value;
}
}
internal bool HasMessage
{
get
{
lock (_forMessageEventQueue)
{
return _messageEventQueue.Count > 0;
}
}
}
internal bool IgnoreExtensions
{
get
{
return _ignoreExtensions;
}
set
{
_ignoreExtensions = value;
}
}
internal bool IsConnected
{
get
{
if (_readyState != WebSocketState.Open)
{
return _readyState == WebSocketState.Closing;
}
return true;
}
}
public CompressionMethod Compression
{
get
{
return _compression;
}
set
{
string text = null;
if (!_client)
{
text = "The set operation cannot be used by servers.";
throw new InvalidOperationException(text);
}
if (!canSet(out text))
{
_logger.Warn(text);
return;
}
lock (_forState)
{
if (!canSet(out text))
{
_logger.Warn(text);
}
else
{
_compression = value;
}
}
}
}
public IEnumerable<WebSocketSharp.Net.Cookie> Cookies
{
get
{
lock (_cookies.SyncRoot)
{
foreach (WebSocketSharp.Net.Cookie cookie in _cookies)
{
yield return cookie;
}
}
}
}
public WebSocketSharp.Net.NetworkCredential Credentials => _credentials;
public bool EmitOnPing
{
get
{
return _emitOnPing;
}
set
{
_emitOnPing = value;
}
}
public bool EnableRedirection
{
get
{
return _enableRedirection;
}
set
{
string text = null;
if (!_client)
{
text = "The set operation cannot be used by servers.";
throw new InvalidOperationException(text);
}
if (!canSet(out text))
{
_logger.Warn(text);
return;
}
lock (_forState)
{
if (!canSet(out text))
{
_logger.Warn(text);
}
else
{
_enableRedirection = value;
}
}
}
}
public string Extensions => _extensions ?? string.Empty;
public bool IsAlive => ping(EmptyBytes);
public bool IsSecure => _secure;
public Logger Log
{
get
{
return _logger;
}
internal set
{
_logger = value;
}
}
public string Origin
{
get
{
return _origin;
}
set
{
string text = null;
if (!_client)
{
text = "This instance is not a client.";
throw new InvalidOperationException(text);
}
if (!value.IsNullOrEmpty())
{
if (!Uri.TryCreate(value, UriKind.Absolute, out Uri result))
{
text = "Not an absolute URI string.";
throw new ArgumentException(text, value);
}
if (result.Segments.Length > 1)
{
text = "It includes the path segments.";
throw new ArgumentException(text, value);
}
}
if (!canSet(out text))
{
_logger.Warn(text);
return;
}
lock (_forState)
{
if (!canSet(out text))
{
_logger.Warn(text);
return;
}
_origin = ((!value.IsNullOrEmpty()) ? value.TrimEnd(new char[1] { '/' }) : value);
}
}
}
public string Protocol
{
get
{
return _protocol ?? string.Empty;
}
internal set
{
_protocol = value;
}
}
public WebSocketState ReadyState => _readyState;
public ClientSslConfiguration SslConfiguration
{
get
{
if (!_client)
{
throw new InvalidOperationException("This instance is not a client.");
}
if (!_secure)
{
throw new InvalidOperationException("This instance does not use a secure connection.");
}
if (_sslConfig == null)
{
_sslConfig = new ClientSslConfiguration(_uri.DnsSafeHost);
}
return _sslConfig;
}
}
public Uri Url
{
get
{
if (!_client)
{
return _context.RequestUri;
}
return _uri;
}
}
public TimeSpan WaitTime
{
get
{
return _waitTime;
}
set
{
if (value <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("value", "Zero or less.");
}
if (!canSet(out var text))
{
_logger.Warn(text);
return;
}
lock (_forState)
{
if (!canSet(out text))
{
_logger.Warn(text);
}
else
{
_waitTime = value;
}
}
}
}
public event EventHandler<CloseEventArgs> OnClose;
public event EventHandler<ErrorEventArgs> OnError;
public event EventHandler<MessageEventArgs> OnMessage;
public event EventHandler OnOpen;
static WebSocket()
{
_maxRetryCountForConnect = 10;
EmptyBytes = new byte[0];
FragmentLength = 1016;
RandomNumber = new RNGCryptoServiceProvider();
}
internal WebSocket(HttpListenerWebSocketContext context, string protocol)
{
_context = context;
_protocol = protocol;
_closeContext = context.Close;
_logger = context.Log;
_message = messages;
_secure = context.IsSecureConnection;
_stream = context.Stream;
_waitTime = TimeSpan.FromSeconds(1.0);
init();
}
internal WebSocket(TcpListenerWebSocketContext context, string protocol)
{
_context = context;
_protocol = protocol;
_closeContext = context.Close;
_logger = context.Log;
_message = messages;
_secure = context.IsSecureConnection;
_stream = context.Stream;
_waitTime = TimeSpan.FromSeconds(1.0);
init();
}
public WebSocket(string url, params string[] protocols)
{
if (url == null)
{
throw new ArgumentNullException("url");
}
if (url.Length == 0)
{
throw new ArgumentException("An empty string.", "url");
}
if (!url.TryCreateWebSocketUri(out _uri, out var text))
{
throw new ArgumentException(text, "url");
}
if (protocols != null && protocols.Length != 0)
{
if (!checkProtocols(protocols, out text))
{
throw new ArgumentException(text, "protocols");
}
_protocols = protocols;
}
_base64Key = CreateBase64Key();
_client = true;
_logger = new Logger();
_message = messagec;
_secure = _uri.Scheme == "wss";
_waitTime = TimeSpan.FromSeconds(5.0);
init();
}
private bool accept()
{
lock (_forState)
{
if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: false, out var text))
{
_logger.Error(text);
error("An error has occurred in accepting.", null);
return false;
}
try
{
if (!acceptHandshake())
{
return false;
}
_readyState = WebSocketState.Open;
}
catch (Exception ex)
{
_logger.Fatal(ex.ToString());
fatal("An exception has occurred while accepting.", ex);
return false;
}
return true;
}
}
private bool acceptHandshake()
{
_logger.Debug($"A request from {_context.UserEndPoint}:\n{_context}");
if (!checkHandshakeRequest(_context, out var text))
{
sendHttpResponse(createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest));
_logger.Fatal(text);
fatal("An error has occurred while accepting.", CloseStatusCode.ProtocolError);
return false;
}
if (!customCheckHandshakeRequest(_context, out text))
{
sendHttpResponse(createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest));
_logger.Fatal(text);
fatal("An error has occurred while accepting.", CloseStatusCode.PolicyViolation);
return false;
}
_base64Key = _context.Headers["Sec-WebSocket-Key"];
if (_protocol != null)
{
processSecWebSocketProtocolHeader(_context.SecWebSocketProtocols);
}
if (!_ignoreExtensions)
{
processSecWebSocketExtensionsClientHeader(_context.Headers["Sec-WebSocket-Extensions"]);
}
return sendHttpResponse(createHandshakeResponse());
}
private bool canSet(out string message)
{
message = null;
if (_readyState == WebSocketState.Open)
{
message = "The connection has already been established.";
return false;
}
if (_readyState == WebSocketState.Closing)
{
message = "The connection is closing.";
return false;
}
return true;
}
private bool checkHandshakeRequest(WebSocketContext context, out string message)
{
message = null;
if (context.RequestUri == null)
{
message = "Specifies an invalid Request-URI.";
return false;
}
if (!context.IsWebSocketRequest)
{
message = "Not a WebSocket handshake request.";
return false;
}
NameValueCollection headers = context.Headers;
if (!validateSecWebSocketKeyHeader(headers["Sec-WebSocket-Key"]))
{
message = "Includes no Sec-WebSocket-Key header, or it has an invalid value.";
return false;
}
if (!validateSecWebSocketVersionClientHeader(headers["Sec-WebSocket-Version"]))
{
message = "Includes no Sec-WebSocket-Version header, or it has an invalid value.";
return false;
}
if (!validateSecWebSocketProtocolClientHeader(headers["Sec-WebSocket-Protocol"]))
{
message = "Includes an invalid Sec-WebSocket-Protocol header.";
return false;
}
if (!_ignoreExtensions && !validateSecWebSocketExtensionsClientHeader(headers["Sec-WebSocket-Extensions"]))
{
message = "Includes an invalid Sec-WebSocket-Extensions header.";
return false;
}
return true;
}
private bool checkHandshakeResponse(HttpResponse response, out string message)
{
message = null;
if (response.IsRedirect)
{
message = "Indicates the redirection.";
return false;
}
if (response.IsUnauthorized)
{
message = "Requires the authentication.";
return false;
}
if (!response.IsWebSocketResponse)
{
message = "Not a WebSocket handshake response.";
return false;
}
NameValueCollection headers = response.Headers;
if (!validateSecWebSocketAcceptHeader(headers["Sec-WebSocket-Accept"]))
{
message = "Includes no Sec-WebSocket-Accept header, or it has an invalid value.";
return false;
}
if (!validateSecWebSocketProtocolServerHeader(headers["Sec-WebSocket-Protocol"]))
{
message = "Includes no Sec-WebSocket-Protocol header, or it has an invalid value.";
return false;
}
if (!validateSecWebSocketExtensionsServerHeader(headers["Sec-WebSocket-Extensions"]))
{
message = "Includes an invalid Sec-WebSocket-Extensions header.";
return false;
}
if (!validateSecWebSocketVersionServerHeader(headers["Sec-WebSocket-Version"]))
{
message = "Includes an invalid Sec-WebSocket-Version header.";
return false;
}
return true;
}
private bool checkIfAvailable(bool connecting, bool open, bool closing, bool closed, out string message)
{
message = null;
if (!connecting && _readyState == WebSocketState.Connecting)
{
message = "This operation is not available in: connecting";
return false;
}
if (!open && _readyState == WebSocketState.Open)
{
message = "This operation is not available in: open";
return false;
}
if (!closing && _readyState == WebSocketState.Closing)
{
message = "This operation is not available in: closing";
return false;
}
if (!closed && _readyState == WebSocketState.Closed)
{
message = "This operation is not available in: closed";
return false;
}
return true;
}
private bool checkIfAvailable(bool client, bool server, bool connecting, bool open, bool closing, bool closed, out string message)
{
message = null;
if (!client && _client)
{
message = "This operation is not available in: client";
return false;
}
if (!server && !_client)
{
message = "This operation is not available in: server";
return false;
}
return checkIfAvailable(connecting, open, closing, closed, out message);
}
private static bool checkParametersForSetCredentials(string username, string password, out string message)
{
message = null;
if (username.IsNullOrEmpty())
{
return true;
}
if (Ext.Contains(username, ':') || !username.IsText())
{
message = "'username' contains an invalid character.";
return false;
}
if (password.IsNullOrEmpty())
{
return true;
}
if (!password.IsText())
{
message = "'password' contains an invalid character.";
return false;
}
return true;
}
private static bool checkParametersForSetProxy(string url, string username, string password, out string message)
{
message = null;
if (url.IsNullOrEmpty())
{
return true;
}
if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result) || result.Scheme != "http" || result.Segments.Length > 1)
{
message = "'url' is an invalid URL.";
return false;
}
if (username.IsNullOrEmpty())
{
return true;
}
if (Ext.Contains(username, ':') || !username.IsText())
{
message = "'username' contains an invalid character.";
return false;
}
if (password.IsNullOrEmpty())
{
return true;
}
if (!password.IsText())
{
message = "'password' contains an invalid character.";
return false;
}
return true;
}
private static bool checkProtocols(string[] protocols, out string message)
{
message = null;
Func<string, bool> condition = (string protocol) => protocol.IsNullOrEmpty() || !protocol.IsToken();
if (protocols.Contains(condition))
{
message = "It contains a value that is not a token.";
return false;
}
if (protocols.ContainsTwice())
{
message = "It contains a value twice.";
return false;
}
return true;
}
private bool checkReceivedFrame(WebSocketFrame frame, out string message)
{
message = null;
bool isMasked = frame.IsMasked;
if (_client && isMasked)
{
message = "A frame from the server is masked.";
return false;
}
if (!_client && !isMasked)
{
message = "A frame from a client is not masked.";
return false;
}
if (_inContinuation && frame.IsData)
{
message = "A data frame has been received while receiving continuation frames.";
return false;
}
if (frame.IsCompressed && _compression == CompressionMethod.None)
{
message = "A compressed frame has been received without any agreement for it.";
return false;
}
if (frame.Rsv2 == Rsv.On)
{
message = "The RSV2 of a frame is non-zero without any negotiation for it.";
return false;
}
if (frame.Rsv3 == Rsv.On)
{
message = "The RSV3 of a frame is non-zero without any negotiation for it.";
return false;
}
return true;
}
private void close(ushort code, string reason)
{
if (_readyState == WebSocketState.Closing)
{
_logger.Info("The closing is already in progress.");
return;
}
if (_readyState == WebSocketState.Closed)
{
_logger.Info("The connection has already been closed.");
return;
}
if (code == 1005)
{
close(PayloadData.Empty, send: true, receive: true, received: false);
return;
}
bool receive = !code.IsReserved();
close(new PayloadData(code, reason), receive, receive, received: false);
}
private void close(PayloadData payloadData, bool send, bool receive, bool received)
{
lock (_forState)
{
if (_readyState == WebSocketState.Closing)
{
_logger.Info("The closing is already in progress.");
return;
}
if (_readyState == WebSocketState.Closed)
{
_logger.Info("The connection has already been closed.");
return;
}
send = send && _readyState == WebSocketState.Open;
receive = send && receive;
_readyState = WebSocketState.Closing;
}
_logger.Trace("Begin closing the connection.");
bool wasClean = closeHandshake(payloadData, send, receive, received);
releaseResources();
_logger.Trace("End closing the connection.");
_readyState = WebSocketState.Closed;
CloseEventArgs closeEventArgs = new CloseEventArgs(payloadData);
closeEventArgs.WasClean = wasClean;
try
{
this.OnClose.Emit(this, closeEventArgs);
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
error("An error has occurred during the OnClose event.", ex);
}
}
private void closeAsync(ushort code, string reason)
{
if (_readyState == WebSocketState.Closing)
{
_logger.Info("The closing is already in progress.");
return;
}
if (_readyState == WebSocketState.Closed)
{
_logger.Info("The connection has already been closed.");
return;
}
if (code == 1005)
{
closeAsync(PayloadData.Empty, send: true, receive: true, received: false);
return;
}
bool receive = !code.IsReserved();
closeAsync(new PayloadData(code, reason), receive, receive, received: false);
}
private void closeAsync(PayloadData payloadData, bool send, bool receive, bool received)
{
Action<PayloadData, bool, bool, bool> closer = close;
closer.BeginInvoke(payloadData, send, receive, received, delegate(IAsyncResult ar)
{
closer.EndInvoke(ar);
}, null);
}
private bool closeHandshake(byte[] frameAsBytes, bool receive, bool received)
{
bool flag = frameAsBytes != null && sendBytes(frameAsBytes);
if (!received && flag && receive && _receivingExited != null)
{
received = _receivingExited.WaitOne(_waitTime);
}
bool flag2 = flag && received;
_logger.Debug($"Was clean?: {flag2}\n sent: {flag}\n received: {received}");
return flag2;
}
private bool closeHandshake(PayloadData payloadData, bool send, bool receive, bool received)
{
bool flag = false;
if (send)
{
WebSocketFrame webSocketFrame = WebSocketFrame.CreateCloseFrame(payloadData, _client);
flag = sendBytes(webSocketFrame.ToArray());
if (_client)
{
webSocketFrame.Unmask();
}
}
if (!received && flag && receive && _receivingExited != null)
{
received = _receivingExited.WaitOne(_waitTime);
}
bool flag2 = flag && received;
_logger.Debug($"Was clean?: {flag2}\n sent: {flag}\n received: {received}");
return flag2;
}
private bool connect()
{
lock (_forState)
{
if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out var text))
{
_logger.Error(text);
error("An error has occurred in connecting.", null);
return false;
}
if (_retryCountForConnect > _maxRetryCountForConnect)
{
_retryCountForConnect = 0;
_logger.Fatal("A series of reconnecting has failed.");
return false;
}
_readyState = WebSocketState.Connecting;
try
{
doHandshake();
}
catch (Exception ex)
{
_retryCountForConnect++;
_logger.Fatal(ex.ToString());
fatal("An exception has occurred while connecting.", ex);
return false;
}
_retryCountForConnect = 1;
_readyState = WebSocketState.Open;
return true;
}
}
private string createExtensions()
{
StringBuilder stringBuilder = new StringBuilder(80);
if (_compression != 0)
{
string arg = _compression.ToExtensionString("server_no_context_takeover", "client_no_context_takeover");
stringBuilder.AppendFormat("{0}, ", arg);
}
int length = stringBuilder.Length;
if (length > 2)
{
stringBuilder.Length = length - 2;
return stringBuilder.ToString();
}
return null;
}
private HttpResponse createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode code)
{
HttpResponse httpResponse = HttpResponse.CreateCloseResponse(code);
httpResponse.Headers["Sec-WebSocket-Version"] = "13";
return httpResponse;
}
private HttpRequest createHandshakeRequest()
{
HttpRequest httpRequest = HttpRequest.CreateWebSocketRequest(_uri);
NameValueCollection headers = httpRequest.Headers;
if (!_origin.IsNullOrEmpty())
{
headers["Origin"] = _origin;
}
headers["Sec-WebSocket-Key"] = _base64Key;
_protocolsRequested = _protocols != null;
if (_protocolsRequested)
{
headers["Sec-WebSocket-Protocol"] = _protocols.ToString(", ");
}
_extensionsRequested = _compression != CompressionMethod.None;
if (_extensionsRequested)
{
headers["Sec-WebSocket-Extensions"] = createExtensions();
}
headers["Sec-WebSocket-Version"] = "13";
AuthenticationResponse authenticationResponse = null;
if (_authChallenge != null && _credentials != null)
{
authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount);
_nonceCount = authenticationResponse.NonceCount;
}
else if (_preAuth)
{
authenticationResponse = new AuthenticationResponse(_credentials);
}
if (authenticationResponse != null)
{
headers["Authorization"] = authenticationResponse.ToString();
}
if (_cookies.Count > 0)
{
httpRequest.SetCookies(_cookies);
}
return httpRequest;
}
private HttpResponse createHandshakeResponse()
{
HttpResponse httpResponse = HttpResponse.CreateWebSocketResponse();
NameValueCollection headers = httpResponse.Headers;
headers["Sec-WebSocket-Accept"] = CreateResponseKey(_base64Key);
if (_protocol != null)
{
headers["Sec-WebSocket-Protocol"] = _protocol;
}
if (_extensions != null)
{
headers["Sec-WebSocket-Extensions"] = _extensions;
}
if (_cookies.Count > 0)
{
httpResponse.SetCookies(_cookies);
}
return httpResponse;
}
private bool customCheckHandshakeRequest(WebSocketContext context, out string message)
{
message = null;
if (_handshakeRequestChecker != null)
{
return (message = _handshakeRequestChecker(context)) == null;
}
return true;
}
private MessageEventArgs dequeueFromMessageEventQueue()
{
lock (_forMessageEventQueue)
{
return (_messageEventQueue.Count > 0) ? _messageEventQueue.Dequeue() : null;
}
}
private void doHandshake()
{
setClientStream();
HttpResponse httpResponse = sendHandshakeRequest();
if (!checkHandshakeResponse(httpResponse, out var text))
{
throw new WebSocketException(CloseStatusCode.ProtocolError, text);
}
if (_protocolsRequested)
{
_protocol = httpResponse.Headers["Sec-WebSocket-Protocol"];
}
if (_extensionsRequested)
{
processSecWebSocketExtensionsServerHeader(httpResponse.Headers["Sec-WebSocket-Extensions"]);
}
processCookies(httpResponse.Cookies);
}
private void enqueueToMessageEventQueue(MessageEventArgs e)
{
lock (_forMessageEventQueue)
{
_messageEventQueue.Enqueue(e);
}
}
private void error(string message, Exception exception)
{
try
{
this.OnError.Emit(this, new ErrorEventArgs(message, exception));
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
}
}
private void fatal(string message, Exception exception)
{
CloseStatusCode code = ((exception is WebSocketException) ? ((WebSocketException)exception).Code : CloseStatusCode.Abnormal);
fatal(message, (ushort)code);
}
private void fatal(string message, ushort code)
{
PayloadData payloadData = new PayloadData(code, message);
close(payloadData, !code.IsReserved(), receive: false, received: false);
}
private void fatal(string message, CloseStatusCode code)
{
fatal(message, (ushort)code);
}
private void init()
{
_compression = CompressionMethod.None;
_cookies = new WebSocketSharp.Net.CookieCollection();
_forPing = new object();
_forSend = new object();
_forState = new object();
_messageEventQueue = new Queue<MessageEventArgs>();
_forMessageEventQueue = ((ICollection)_messageEventQueue).SyncRoot;
_readyState = WebSocketState.Connecting;
}
private void message()
{
MessageEventArgs obj = null;
lock (_forMessageEventQueue)
{
if (_inMessage || _messageEventQueue.Count == 0 || _readyState != WebSocketState.Open)
{
return;
}
_inMessage = true;
obj = _messageEventQueue.Dequeue();
}
_message(obj);
}
private void messagec(MessageEventArgs e)
{
while (true)
{
try
{
this.OnMessage.Emit(this, e);
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
error("An error has occurred during an OnMessage event.", ex);
}
lock (_forMessageEventQueue)
{
if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open)
{
_inMessage = false;
break;
}
e = _messageEventQueue.Dequeue();
}
}
}
private void messages(MessageEventArgs e)
{
try
{
this.OnMessage.Emit(this, e);
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
error("An error has occurred during an OnMessage event.", ex);
}
lock (_forMessageEventQueue)
{
if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open)
{
_inMessage = false;
return;
}
e = _messageEventQueue.Dequeue();
}
ThreadPool.QueueUserWorkItem(delegate
{
messages(e);
});
}
private void open()
{
_inMessage = true;
startReceiving();
try
{
this.OnOpen.Emit(this, EventArgs.Empty);
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
error("An error has occurred during the OnOpen event.", ex);
}
MessageEventArgs obj = null;
lock (_forMessageEventQueue)
{
if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open)
{
_inMessage = false;
return;
}
obj = _messageEventQueue.Dequeue();
}
_message.BeginInvoke(obj, delegate(IAsyncResult ar)
{
_message.EndInvoke(ar);
}, null);
}
private bool ping(byte[] data)
{
if (_readyState != WebSocketState.Open)
{
return false;
}
ManualResetEvent pongReceived = _pongReceived;
if (pongReceived == null)
{
return false;
}
lock (_forPing)
{
try
{
pongReceived.Reset();
if (!send(Fin.Final, Opcode.Ping, data, compressed: false))
{
return false;
}
return pongReceived.WaitOne(_waitTime);
}
catch (ObjectDisposedException)
{
return false;
}
}
}
private bool processCloseFrame(WebSocketFrame frame)
{
PayloadData payloadData = frame.PayloadData;
close(payloadData, !payloadData.HasReservedCode, receive: false, received: true);
return false;
}
private void processCookies(WebSocketSharp.Net.CookieCollection cookies)
{
if (cookies.Count != 0)
{
_cookies.SetOrRemove(cookies);
}
}
private bool processDataFrame(WebSocketFrame frame)
{
enqueueToMessageEventQueue(frame.IsCompressed ? new MessageEventArgs(frame.Opcode, frame.PayloadData.ApplicationData.Decompress(_compression)) : new MessageEventArgs(frame));
return true;
}
private bool processFragmentFrame(WebSocketFrame frame)
{
if (!_inContinuation)
{
if (frame.IsContinuation)
{
return true;
}
_fragmentsOpcode = frame.Opcode;
_fragmentsCompressed = frame.IsCompressed;
_fragmentsBuffer = new MemoryStream();
_inContinuation = true;
}
_fragmentsBuffer.WriteBytes(frame.PayloadData.ApplicationData, 1024);
if (frame.IsFinal)
{
using (_fragmentsBuffer)
{
byte[] rawData = (_fragmentsCompressed ? _fragmentsBuffer.DecompressToArray(_compression) : _fragmentsBuffer.ToArray());
enqueueToMessageEventQueue(new MessageEventArgs(_fragmentsOpcode, rawData));
}
_fragmentsBuffer = null;
_inContinuation = false;
}
return true;
}
private bool processPingFrame(WebSocketFrame frame)
{
_logger.Trace("A ping was received.");
WebSocketFrame webSocketFrame = WebSocketFrame.CreatePongFrame(frame.PayloadData, _client);
lock (_forState)
{
if (_readyState != WebSocketState.Open)
{
_logger.Error("The connection is closing.");
return true;
}
if (!sendBytes(webSocketFrame.ToArray()))
{
return false;
}
}
_logger.Trace("A pong to this ping has been sent.");
if (_emitOnPing)
{
if (_client)
{
webSocketFrame.Unmask();
}
enqueueToMessageEventQueue(new MessageEventArgs(frame));
}
return true;
}
private bool processPongFrame(WebSocketFrame frame)
{
_logger.Trace("A pong was received.");
try
{
_pongReceived.Set();
}
catch (NullReferenceException ex)
{
_logger.Error(ex.Message);
_logger.Debug(ex.ToString());
return false;
}
catch (ObjectDisposedException ex2)
{
_logger.Error(ex2.Message);
_logger.Debug(ex2.ToString());
return false;
}
_logger.Trace("It has been signaled.");
return true;
}
private bool processReceivedFrame(WebSocketFrame frame)
{
if (!checkReceivedFrame(frame, out var text))
{
throw new WebSocketException(CloseStatusCode.ProtocolError, text);
}
frame.Unmask();
if (!frame.IsFragment)
{
if (!frame.IsData)
{
if (!frame.IsPing)
{
if (!frame.IsPong)
{
if (!frame.IsClose)
{
return processUnsupportedFrame(frame);
}
return processCloseFrame(frame);
}
return processPongFrame(frame);
}
return processPingFrame(frame);
}
return processDataFrame(frame);
}
return processFragmentFrame(frame);
}
private void processSecWebSocketExtensionsClientHeader(string value)
{
if (value == null)
{
return;
}
StringBuilder stringBuilder = new StringBuilder(80);
bool flag = false;
foreach (string item in value.SplitHeaderValue(','))
{
string value2 = item.Trim();
if (!flag && value2.IsCompressionExtension(CompressionMethod.Deflate))
{
_compression = CompressionMethod.Deflate;
stringBuilder.AppendFormat("{0}, ", _compression.ToExtensionString("client_no_context_takeover", "server_no_context_takeover"));
flag = true;
}
}
int length = stringBuilder.Length;
if (length > 2)
{
stringBuilder.Length = length - 2;
_extensions = stringBuilder.ToString();
}
}
private void processSecWebSocketExtensionsServerHeader(string value)
{
if (value == null)
{
_compression = CompressionMethod.None;
}
else
{
_extensions = value;
}
}
private void processSecWebSocketProtocolHeader(IEnumerable<string> values)
{
if (!values.Contains((string p) => p == _protocol))
{
_protocol = null;
}
}
private bool processUnsupportedFrame(WebSocketFrame frame)
{
_logger.Fatal("An unsupported frame:" + frame.PrintToString(dumped: false));
fatal("There is no way to handle it.", CloseStatusCode.PolicyViolation);
return false;
}
private void releaseClientResources()
{
if (_stream != null)
{
_stream.Dispose();
_stream = null;
}
if (_tcpClient != null)
{
_tcpClient.Close();
_tcpClient = null;
}
}
private void releaseCommonResources()
{
if (_fragmentsBuffer != null)
{
_fragmentsBuffer.Dispose();
_fragmentsBuffer = null;
_inContinuation = false;
}
if (_pongReceived != null)
{
_pongReceived.Close();
_pongReceived = null;
}
if (_receivingExited != null)
{
_receivingExited.Close();
_receivingExited = null;
}
}
private void releaseResources()
{
if (_client)
{
releaseClientResources();
}
else
{
releaseServerResources();
}
releaseCommonResources();
}
private void releaseServerResources()
{
if (_closeContext != null)
{
_closeContext();
_closeContext = null;
_stream = null;
_context = null;
}
}
private bool send(Opcode opcode, Stream stream)
{
lock (_forSend)
{
Stream stream2 = stream;
bool flag = false;
bool flag2 = false;
try
{
if (_compression != 0)
{
stream = stream.Compress(_compression);
flag = true;
}
flag2 = send(opcode, stream, flag);
if (!flag2)
{
error("A send has been interrupted.", null);
}
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
error("An error has occurred during a send.", ex);
}
finally
{
if (flag)
{
stream.Dispose();
}
stream2.Dispose();
}
return flag2;
}
}
private bool send(Opcode opcode, Stream stream, bool compressed)
{
long length = stream.Length;
if (length == 0L)
{
return send(Fin.Final, opcode, EmptyBytes, compressed: false);
}
long num = length / FragmentLength;
int num2 = (int)(length % FragmentLength);
byte[] array = null;
switch (num)
{
case 0L:
array = new byte[num2];
if (stream.Read(array, 0, num2) == num2)
{
return send(Fin.Final, opcode, array, compressed);
}
return false;
case 1L:
if (num2 == 0)
{
array = new byte[FragmentLength];
if (stream.Read(array, 0, FragmentLength) == FragmentLength)
{
return send(Fin.Final, opcode, array, compressed);
}
return false;
}
break;
}
array = new byte[FragmentLength];
if (stream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, opcode, array, compressed))
{
return false;
}
long num3 = ((num2 == 0) ? (num - 2) : (num - 1));
for (long num4 = 0L; num4 < num3; num4++)
{
if (stream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, Opcode.Cont, array, compressed: false))
{
return false;
}
}
if (num2 == 0)
{
num2 = FragmentLength;
}
else
{
array = new byte[num2];
}
if (stream.Read(array, 0, num2) == num2)
{
return send(Fin.Final, Opcode.Cont, array, compressed: false);
}
return false;
}
private bool send(Fin fin, Opcode opcode, byte[] data, bool compressed)
{
lock (_forState)
{
if (_readyState != WebSocketState.Open)
{
_logger.Error("The connection is closing.");
return false;
}
WebSocketFrame webSocketFrame = new WebSocketFrame(fin, opcode, data, compressed, _client);
return sendBytes(webSocketFrame.ToArray());
}
}
private void sendAsync(Opcode opcode, Stream stream, Action<bool> completed)
{
Func<Opcode, Stream, bool> sender = send;
sender.BeginInvoke(opcode, stream, delegate(IAsyncResult ar)
{
try
{
bool obj = sender.EndInvoke(ar);
if (completed != null)
{
completed(obj);
}
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
error("An error has occurred during the callback for an async send.", ex);
}
}, null);
}
private bool sendBytes(byte[] bytes)
{
try
{
_stream.Write(bytes, 0, bytes.Length);
}
catch (Exception ex)
{
_logger.Error(ex.Message);
_logger.Debug(ex.ToString());
return false;
}
return true;
}
private HttpResponse sendHandshakeRequest()
{
HttpRequest httpRequest = createHandshakeRequest();
HttpResponse httpResponse = sendHttpRequest(httpRequest, 90000);
if (httpResponse.IsUnauthorized)
{
string text = httpResponse.Headers["WWW-Authenticate"];
_logger.Warn($"Received an authentication requirement for '{text}'.");
if (text.IsNullOrEmpty())
{
_logger.Error("No authentication challenge is specified.");
return httpResponse;
}
_authChallenge = AuthenticationChallenge.Parse(text);
if (_authChallenge == null)
{
_logger.Error("An invalid authentication challenge is specified.");
return httpResponse;
}
if (_credentials != null && (!_preAuth || _authChallenge.Scheme == WebSocketSharp.Net.AuthenticationSchemes.Digest))
{
if (httpResponse.HasConnectionClose)
{
releaseClientResources();
setClientStream();
}
AuthenticationResponse authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount);
_nonceCount = authenticationResponse.NonceCount;
httpRequest.Headers["Authorization"] = authenticationResponse.ToString();
httpResponse = sendHttpRequest(httpRequest, 15000);
}
}
if (httpResponse.IsRedirect)
{
string text2 = httpResponse.Headers["Location"];
_logger.Warn($"Received a redirection to '{text2}'.");
if (_enableRedirection)
{
if (text2.IsNullOrEmpty())
{
_logger.Error("No url to redirect is located.");
return httpResponse;
}
if (!text2.TryCreateWebSocketUri(out var result, out var text3))
{
_logger.Error("An invalid url to redirect is located: " + text3);
return httpResponse;
}
releaseClientResources();
_uri = result;
_secure = result.Scheme == "wss";
setClientStream();
return sendHandshakeRequest();
}
}
return httpResponse;
}
private HttpResponse sendHttpRequest(HttpRequest request, int millisecondsTimeout)
{
_logger.Debug("A request to the server:\n" + request.ToString());
HttpResponse response = request.GetResponse(_stream, millisecondsTimeout);
_logger.Debug("A response to this request:\n" + response.ToString());
return response;
}
private bool sendHttpResponse(HttpResponse response)
{
_logger.Debug("A response to this request:\n" + response.ToString());
return sendBytes(response.ToByteArray());
}
private void sendProxyConnectRequest()
{
HttpRequest httpRequest = HttpRequest.CreateConnectRequest(_uri);
HttpResponse httpResponse = sendHttpRequest(httpRequest, 90000);
if (httpResponse.IsProxyAuthenticationRequired)
{
string text = httpResponse.Headers["Proxy-Authenticate"];
_logger.Warn($"Received a proxy authentication requirement for '{text}'.");
if (text.IsNullOrEmpty())
{
throw new WebSocketException("No proxy authentication challenge is specified.");
}
AuthenticationChallenge authenticationChallenge = AuthenticationChallenge.Parse(text);
if (authenticationChallenge == null)
{
throw new WebSocketException("An invalid proxy authentication challenge is specified.");
}
if (_proxyCredentials != null)
{
if (httpResponse.HasConnectionClose)
{
releaseClientResources();
_tcpClient = new TcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port);
_stream = _tcpClient.GetStream();
}
AuthenticationResponse authenticationResponse = new AuthenticationResponse(authenticationChallenge, _proxyCredentials, 0u);
httpRequest.Headers["Proxy-Authorization"] = authenticationResponse.ToString();
httpResponse = sendHttpRequest(httpRequest, 15000);
}
if (httpResponse.IsProxyAuthenticationRequired)
{
throw new WebSocketException("A proxy authentication is required.");
}
}
if (httpResponse.StatusCode[0] != '2')
{
throw new WebSocketException("The proxy has failed a connection to the requested host and port.");
}
}
private void setClientStream()
{
if (_proxyUri != null)
{
_tcpClient = new TcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port);
_stream = _tcpClient.GetStream();
sendProxyConnectRequest();
}
else
{
_tcpClient = new TcpClient(_uri.DnsSafeHost, _uri.Port);
_stream = _tcpClient.GetStream();
}
if (_secure)
{
ClientSslConfiguration sslConfiguration = SslConfiguration;
string targetHost = sslConfiguration.TargetHost;
if (targetHost != _uri.DnsSafeHost)
{
throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, "An invalid host name is specified.");
}
try
{
SslStream sslStream = new SslStream(_stream, leaveInnerStreamOpen: false, sslConfiguration.ServerCertificateValidationCallback, sslConfiguration.ClientCertificateSelectionCallback);
sslStream.AuthenticateAsClient(targetHost, sslConfiguration.ClientCertificates, sslConfiguration.EnabledSslProtocols, sslConfiguration.CheckCertificateRevocation);
_stream = sslStream;
}
catch (Exception innerException)
{
throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, innerException);
}
}
}
private void startReceiving()
{
if (_messageEventQueue.Count > 0)
{
_messageEventQueue.Clear();
}
_pongReceived = new ManualResetEvent(initialState: false);
_receivingExited = new ManualResetEvent(initialState: false);
Action receive = null;
receive = delegate
{
WebSocketFrame.ReadFrameAsync(_stream, unmask: false, delegate(WebSocketFrame frame)
{
if (!processReceivedFrame(frame) || _readyState == WebSocketState.Closed)
{
_receivingExited?.Set();
}
else
{
receive();
if (!_inMessage && HasMessage && _readyState == WebSocketState.Open)
{
message();
}
}
}, delegate(Exception ex)
{
_logger.Fatal(ex.ToString());
fatal("An exception has occurred while receiving.", ex);
});
};
receive();
}
private bool validateSecWebSocketAcceptHeader(string value)
{
if (value != null)
{
return value == CreateResponseKey(_base64Key);
}
return false;
}
private bool validateSecWebSocketExtensionsClientHeader(string value)
{
if (value != null)
{
return value.Length > 0;
}
return true;
}
private bool validateSecWebSocketExtensionsServerHeader(string value)
{
if (value == null)
{
return true;
}
if (value.Length == 0)
{
return false;
}
if (!_extensionsRequested)
{
return false;
}
bool flag = _compression != CompressionMethod.None;
foreach (string item in value.SplitHeaderValue(','))
{
string text = item.Trim();
if (flag && text.IsCompressionExtension(_compression))
{
if (!text.Contains("server_no_context_takeover"))
{
_logger.Error("The server hasn't sent back 'server_no_context_takeover'.");
return false;
}
if (!text.Contains("client_no_context_takeover"))
{
_logger.Warn("The server hasn't sent back 'client_no_context_takeover'.");
}
string method = _compression.ToExtensionString();
if (text.SplitHeaderValue(';').Contains(delegate(string t)
{
t = t.Trim();
return t != method && t != "server_no_context_takeover" && t != "client_no_context_takeover";
}))
{
return false;
}
continue;
}
return false;
}
return true;
}
private bool validateSecWebSocketKeyHeader(string value)
{
if (value != null)
{
return value.Length > 0;
}
return false;
}
private bool validateSecWebSocketProtocolClientHeader(string value)
{
if (value != null)
{
return value.Length > 0;
}
return true;
}
private bool validateSecWebSocketProtocolServerHeader(string value)
{
if (value == null)
{
return !_protocolsRequested;
}
if (value.Length == 0)
{
return false;
}
if (_protocolsRequested)
{
return _protocols.Contains((string p) => p == value);
}
return false;
}
private bool validateSecWebSocketVersionClientHeader(string value)
{
if (value != null)
{
return value == "13";
}
return false;
}
private bool validateSecWebSocketVersionServerHeader(string value)
{
if (value != null)
{
return value == "13";
}
return true;
}
internal void Close(HttpResponse response)
{
_readyState = WebSocketState.Closing