WebSocketFrame.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Threading.Tasks;
  6. namespace SocketHttpListener
  7. {
  8. internal class WebSocketFrame : IEnumerable<byte>
  9. {
  10. #region Private Fields
  11. private byte[] _extPayloadLength;
  12. private Fin _fin;
  13. private Mask _mask;
  14. private byte[] _maskingKey;
  15. private Opcode _opcode;
  16. private PayloadData _payloadData;
  17. private byte _payloadLength;
  18. private Rsv _rsv1;
  19. private Rsv _rsv2;
  20. private Rsv _rsv3;
  21. #endregion
  22. #region Internal Fields
  23. internal static readonly byte[] EmptyUnmaskPingData;
  24. #endregion
  25. #region Static Constructor
  26. static WebSocketFrame()
  27. {
  28. EmptyUnmaskPingData = CreatePingFrame(Mask.Unmask).ToByteArray();
  29. }
  30. #endregion
  31. #region Private Constructors
  32. private WebSocketFrame()
  33. {
  34. }
  35. #endregion
  36. #region Internal Constructors
  37. internal WebSocketFrame(Opcode opcode, PayloadData payload)
  38. : this(Fin.Final, opcode, Mask.Mask, payload, false)
  39. {
  40. }
  41. internal WebSocketFrame(Opcode opcode, Mask mask, PayloadData payload)
  42. : this(Fin.Final, opcode, mask, payload, false)
  43. {
  44. }
  45. internal WebSocketFrame(Fin fin, Opcode opcode, Mask mask, PayloadData payload)
  46. : this(fin, opcode, mask, payload, false)
  47. {
  48. }
  49. internal WebSocketFrame(
  50. Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed)
  51. {
  52. _fin = fin;
  53. _rsv1 = isData(opcode) && compressed ? Rsv.On : Rsv.Off;
  54. _rsv2 = Rsv.Off;
  55. _rsv3 = Rsv.Off;
  56. _opcode = opcode;
  57. _mask = mask;
  58. var len = payload.Length;
  59. if (len < 126)
  60. {
  61. _payloadLength = (byte)len;
  62. _extPayloadLength = new byte[0];
  63. }
  64. else if (len < 0x010000)
  65. {
  66. _payloadLength = (byte)126;
  67. _extPayloadLength = ((ushort)len).ToByteArrayInternally(ByteOrder.Big);
  68. }
  69. else
  70. {
  71. _payloadLength = (byte)127;
  72. _extPayloadLength = len.ToByteArrayInternally(ByteOrder.Big);
  73. }
  74. if (mask == Mask.Mask)
  75. {
  76. _maskingKey = createMaskingKey();
  77. payload.Mask(_maskingKey);
  78. }
  79. else
  80. {
  81. _maskingKey = new byte[0];
  82. }
  83. _payloadData = payload;
  84. }
  85. #endregion
  86. #region Public Properties
  87. public byte[] ExtendedPayloadLength => _extPayloadLength;
  88. public Fin Fin => _fin;
  89. public bool IsBinary => _opcode == Opcode.Binary;
  90. public bool IsClose => _opcode == Opcode.Close;
  91. public bool IsCompressed => _rsv1 == Rsv.On;
  92. public bool IsContinuation => _opcode == Opcode.Cont;
  93. public bool IsControl => _opcode == Opcode.Close || _opcode == Opcode.Ping || _opcode == Opcode.Pong;
  94. public bool IsData => _opcode == Opcode.Binary || _opcode == Opcode.Text;
  95. public bool IsFinal => _fin == Fin.Final;
  96. public bool IsFragmented => _fin == Fin.More || _opcode == Opcode.Cont;
  97. public bool IsMasked => _mask == Mask.Mask;
  98. public bool IsPerMessageCompressed => (_opcode == Opcode.Binary || _opcode == Opcode.Text) && _rsv1 == Rsv.On;
  99. public bool IsPing => _opcode == Opcode.Ping;
  100. public bool IsPong => _opcode == Opcode.Pong;
  101. public bool IsText => _opcode == Opcode.Text;
  102. public ulong Length => 2 + (ulong)(_extPayloadLength.Length + _maskingKey.Length) + _payloadData.Length;
  103. public Mask Mask => _mask;
  104. public byte[] MaskingKey => _maskingKey;
  105. public Opcode Opcode => _opcode;
  106. public PayloadData PayloadData => _payloadData;
  107. public byte PayloadLength => _payloadLength;
  108. public Rsv Rsv1 => _rsv1;
  109. public Rsv Rsv2 => _rsv2;
  110. public Rsv Rsv3 => _rsv3;
  111. #endregion
  112. #region Private Methods
  113. private byte[] createMaskingKey()
  114. {
  115. var key = new byte[4];
  116. var rand = new Random();
  117. rand.NextBytes(key);
  118. return key;
  119. }
  120. private static bool isControl(Opcode opcode)
  121. {
  122. return opcode == Opcode.Close || opcode == Opcode.Ping || opcode == Opcode.Pong;
  123. }
  124. private static bool isData(Opcode opcode)
  125. {
  126. return opcode == Opcode.Text || opcode == Opcode.Binary;
  127. }
  128. private static async Task<WebSocketFrame> ReadAsync(byte[] header, Stream stream, bool unmask)
  129. {
  130. /* Header */
  131. // FIN
  132. var fin = (header[0] & 0x80) == 0x80 ? Fin.Final : Fin.More;
  133. // RSV1
  134. var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.On : Rsv.Off;
  135. // RSV2
  136. var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.On : Rsv.Off;
  137. // RSV3
  138. var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.On : Rsv.Off;
  139. // Opcode
  140. var opcode = (Opcode)(header[0] & 0x0f);
  141. // MASK
  142. var mask = (header[1] & 0x80) == 0x80 ? Mask.Mask : Mask.Unmask;
  143. // Payload Length
  144. var payloadLen = (byte)(header[1] & 0x7f);
  145. // Check if correct frame.
  146. var incorrect = isControl(opcode) && fin == Fin.More
  147. ? "A control frame is fragmented."
  148. : !isData(opcode) && rsv1 == Rsv.On
  149. ? "A non data frame is compressed."
  150. : null;
  151. if (incorrect != null)
  152. throw new WebSocketException(CloseStatusCode.IncorrectData, incorrect);
  153. // Check if consistent frame.
  154. if (isControl(opcode) && payloadLen > 125)
  155. throw new WebSocketException(
  156. CloseStatusCode.InconsistentData,
  157. "The length of payload data of a control frame is greater than 125 bytes.");
  158. var frame = new WebSocketFrame();
  159. frame._fin = fin;
  160. frame._rsv1 = rsv1;
  161. frame._rsv2 = rsv2;
  162. frame._rsv3 = rsv3;
  163. frame._opcode = opcode;
  164. frame._mask = mask;
  165. frame._payloadLength = payloadLen;
  166. /* Extended Payload Length */
  167. var size = payloadLen < 126
  168. ? 0
  169. : payloadLen == 126
  170. ? 2
  171. : 8;
  172. var extPayloadLen = size > 0 ? await stream.ReadBytesAsync(size).ConfigureAwait(false) : Array.Empty<byte>();
  173. if (size > 0 && extPayloadLen.Length != size)
  174. throw new WebSocketException(
  175. "The 'Extended Payload Length' of a frame cannot be read from the data source.");
  176. frame._extPayloadLength = extPayloadLen;
  177. /* Masking Key */
  178. var masked = mask == Mask.Mask;
  179. var maskingKey = masked ? await stream.ReadBytesAsync(4).ConfigureAwait(false) : Array.Empty<byte>();
  180. if (masked && maskingKey.Length != 4)
  181. throw new WebSocketException(
  182. "The 'Masking Key' of a frame cannot be read from the data source.");
  183. frame._maskingKey = maskingKey;
  184. /* Payload Data */
  185. ulong len = payloadLen < 126
  186. ? payloadLen
  187. : payloadLen == 126
  188. ? extPayloadLen.ToUInt16(ByteOrder.Big)
  189. : extPayloadLen.ToUInt64(ByteOrder.Big);
  190. byte[] data = null;
  191. if (len > 0)
  192. {
  193. // Check if allowable payload data length.
  194. if (payloadLen > 126 && len > PayloadData.MaxLength)
  195. throw new WebSocketException(
  196. CloseStatusCode.TooBig,
  197. "The length of 'Payload Data' of a frame is greater than the allowable length.");
  198. data = payloadLen > 126
  199. ? await stream.ReadBytesAsync((long)len, 1024).ConfigureAwait(false)
  200. : await stream.ReadBytesAsync((int)len).ConfigureAwait(false);
  201. //if (data.LongLength != (long)len)
  202. // throw new WebSocketException(
  203. // "The 'Payload Data' of a frame cannot be read from the data source.");
  204. }
  205. else
  206. {
  207. data = Array.Empty<byte>();
  208. }
  209. var payload = new PayloadData(data, masked);
  210. if (masked && unmask)
  211. {
  212. payload.Mask(maskingKey);
  213. frame._mask = Mask.Unmask;
  214. frame._maskingKey = Array.Empty<byte>();
  215. }
  216. frame._payloadData = payload;
  217. return frame;
  218. }
  219. #endregion
  220. #region Internal Methods
  221. internal static WebSocketFrame CreateCloseFrame(Mask mask, byte[] data)
  222. {
  223. return new WebSocketFrame(Opcode.Close, mask, new PayloadData(data));
  224. }
  225. internal static WebSocketFrame CreateCloseFrame(Mask mask, PayloadData payload)
  226. {
  227. return new WebSocketFrame(Opcode.Close, mask, payload);
  228. }
  229. internal static WebSocketFrame CreateCloseFrame(Mask mask, CloseStatusCode code, string reason)
  230. {
  231. return new WebSocketFrame(
  232. Opcode.Close, mask, new PayloadData(((ushort)code).Append(reason)));
  233. }
  234. internal static WebSocketFrame CreatePingFrame(Mask mask)
  235. {
  236. return new WebSocketFrame(Opcode.Ping, mask, new PayloadData());
  237. }
  238. internal static WebSocketFrame CreatePingFrame(Mask mask, byte[] data)
  239. {
  240. return new WebSocketFrame(Opcode.Ping, mask, new PayloadData(data));
  241. }
  242. internal static WebSocketFrame CreatePongFrame(Mask mask, PayloadData payload)
  243. {
  244. return new WebSocketFrame(Opcode.Pong, mask, payload);
  245. }
  246. internal static WebSocketFrame CreateWebSocketFrame(
  247. Fin fin, Opcode opcode, Mask mask, byte[] data, bool compressed)
  248. {
  249. return new WebSocketFrame(fin, opcode, mask, new PayloadData(data), compressed);
  250. }
  251. internal static Task<WebSocketFrame> ReadAsync(Stream stream)
  252. => ReadAsync(stream, true);
  253. internal static async Task<WebSocketFrame> ReadAsync(Stream stream, bool unmask)
  254. {
  255. var header = await stream.ReadBytesAsync(2).ConfigureAwait(false);
  256. if (header.Length != 2)
  257. {
  258. throw new WebSocketException(
  259. "The header part of a frame cannot be read from the data source.");
  260. }
  261. return await ReadAsync(header, stream, unmask).ConfigureAwait(false);
  262. }
  263. internal static async Task ReadAsync(
  264. Stream stream, bool unmask, Action<WebSocketFrame> completed, Action<Exception> error)
  265. {
  266. try
  267. {
  268. var header = await stream.ReadBytesAsync(2).ConfigureAwait(false);
  269. if (header.Length != 2)
  270. {
  271. throw new WebSocketException(
  272. "The header part of a frame cannot be read from the data source.");
  273. }
  274. var frame = await ReadAsync(header, stream, unmask).ConfigureAwait(false);
  275. completed?.Invoke(frame);
  276. }
  277. catch (Exception ex)
  278. {
  279. error.Invoke(ex);
  280. }
  281. }
  282. #endregion
  283. #region Public Methods
  284. public IEnumerator<byte> GetEnumerator()
  285. {
  286. foreach (var b in ToByteArray())
  287. yield return b;
  288. }
  289. public void Print(bool dumped)
  290. {
  291. //Console.WriteLine(dumped ? dump(this) : print(this));
  292. }
  293. public byte[] ToByteArray()
  294. {
  295. using (var buff = new MemoryStream())
  296. {
  297. var header = (int)_fin;
  298. header = (header << 1) + (int)_rsv1;
  299. header = (header << 1) + (int)_rsv2;
  300. header = (header << 1) + (int)_rsv3;
  301. header = (header << 4) + (int)_opcode;
  302. header = (header << 1) + (int)_mask;
  303. header = (header << 7) + (int)_payloadLength;
  304. buff.Write(((ushort)header).ToByteArrayInternally(ByteOrder.Big), 0, 2);
  305. if (_payloadLength > 125)
  306. buff.Write(_extPayloadLength, 0, _extPayloadLength.Length);
  307. if (_mask == Mask.Mask)
  308. buff.Write(_maskingKey, 0, _maskingKey.Length);
  309. if (_payloadLength > 0)
  310. {
  311. var payload = _payloadData.ToByteArray();
  312. if (_payloadLength < 127)
  313. buff.Write(payload, 0, payload.Length);
  314. else
  315. buff.WriteBytes(payload);
  316. }
  317. return buff.ToArray();
  318. }
  319. }
  320. public override string ToString()
  321. {
  322. return BitConverter.ToString(ToByteArray());
  323. }
  324. #endregion
  325. #region Explicitly Implemented Interface Members
  326. IEnumerator IEnumerable.GetEnumerator()
  327. {
  328. return GetEnumerator();
  329. }
  330. #endregion
  331. }
  332. }