| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 | 
							- using System;
 
- using System.Collections;
 
- using System.Collections.Generic;
 
- using System.IO;
 
- using System.Text;
 
- namespace SocketHttpListener
 
- {
 
-     internal class WebSocketFrame : IEnumerable<byte>
 
-     {
 
-         #region Private Fields
 
-         private byte[] _extPayloadLength;
 
-         private Fin _fin;
 
-         private Mask _mask;
 
-         private byte[] _maskingKey;
 
-         private Opcode _opcode;
 
-         private PayloadData _payloadData;
 
-         private byte _payloadLength;
 
-         private Rsv _rsv1;
 
-         private Rsv _rsv2;
 
-         private Rsv _rsv3;
 
-         #endregion
 
-         #region Internal Fields
 
-         internal static readonly byte[] EmptyUnmaskPingData;
 
-         #endregion
 
-         #region Static Constructor
 
-         static WebSocketFrame()
 
-         {
 
-             EmptyUnmaskPingData = CreatePingFrame(Mask.Unmask).ToByteArray();
 
-         }
 
-         #endregion
 
-         #region Private Constructors
 
-         private WebSocketFrame()
 
-         {
 
-         }
 
-         #endregion
 
-         #region Internal Constructors
 
-         internal WebSocketFrame(Opcode opcode, PayloadData payload)
 
-             : this(Fin.Final, opcode, Mask.Mask, payload, false)
 
-         {
 
-         }
 
-         internal WebSocketFrame(Opcode opcode, Mask mask, PayloadData payload)
 
-             : this(Fin.Final, opcode, mask, payload, false)
 
-         {
 
-         }
 
-         internal WebSocketFrame(Fin fin, Opcode opcode, Mask mask, PayloadData payload)
 
-             : this(fin, opcode, mask, payload, false)
 
-         {
 
-         }
 
-         internal WebSocketFrame(
 
-           Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed)
 
-         {
 
-             _fin = fin;
 
-             _rsv1 = isData(opcode) && compressed ? Rsv.On : Rsv.Off;
 
-             _rsv2 = Rsv.Off;
 
-             _rsv3 = Rsv.Off;
 
-             _opcode = opcode;
 
-             _mask = mask;
 
-             var len = payload.Length;
 
-             if (len < 126)
 
-             {
 
-                 _payloadLength = (byte)len;
 
-                 _extPayloadLength = new byte[0];
 
-             }
 
-             else if (len < 0x010000)
 
-             {
 
-                 _payloadLength = (byte)126;
 
-                 _extPayloadLength = ((ushort)len).ToByteArrayInternally(ByteOrder.Big);
 
-             }
 
-             else
 
-             {
 
-                 _payloadLength = (byte)127;
 
-                 _extPayloadLength = len.ToByteArrayInternally(ByteOrder.Big);
 
-             }
 
-             if (mask == Mask.Mask)
 
-             {
 
-                 _maskingKey = createMaskingKey();
 
-                 payload.Mask(_maskingKey);
 
-             }
 
-             else
 
-             {
 
-                 _maskingKey = new byte[0];
 
-             }
 
-             _payloadData = payload;
 
-         }
 
-         #endregion
 
-         #region Public Properties
 
-         public byte[] ExtendedPayloadLength
 
-         {
 
-             get
 
-             {
 
-                 return _extPayloadLength;
 
-             }
 
-         }
 
-         public Fin Fin
 
-         {
 
-             get
 
-             {
 
-                 return _fin;
 
-             }
 
-         }
 
-         public bool IsBinary
 
-         {
 
-             get
 
-             {
 
-                 return _opcode == Opcode.Binary;
 
-             }
 
-         }
 
-         public bool IsClose
 
-         {
 
-             get
 
-             {
 
-                 return _opcode == Opcode.Close;
 
-             }
 
-         }
 
-         public bool IsCompressed
 
-         {
 
-             get
 
-             {
 
-                 return _rsv1 == Rsv.On;
 
-             }
 
-         }
 
-         public bool IsContinuation
 
-         {
 
-             get
 
-             {
 
-                 return _opcode == Opcode.Cont;
 
-             }
 
-         }
 
-         public bool IsControl
 
-         {
 
-             get
 
-             {
 
-                 return _opcode == Opcode.Close || _opcode == Opcode.Ping || _opcode == Opcode.Pong;
 
-             }
 
-         }
 
-         public bool IsData
 
-         {
 
-             get
 
-             {
 
-                 return _opcode == Opcode.Binary || _opcode == Opcode.Text;
 
-             }
 
-         }
 
-         public bool IsFinal
 
-         {
 
-             get
 
-             {
 
-                 return _fin == Fin.Final;
 
-             }
 
-         }
 
-         public bool IsFragmented
 
-         {
 
-             get
 
-             {
 
-                 return _fin == Fin.More || _opcode == Opcode.Cont;
 
-             }
 
-         }
 
-         public bool IsMasked
 
-         {
 
-             get
 
-             {
 
-                 return _mask == Mask.Mask;
 
-             }
 
-         }
 
-         public bool IsPerMessageCompressed
 
-         {
 
-             get
 
-             {
 
-                 return (_opcode == Opcode.Binary || _opcode == Opcode.Text) && _rsv1 == Rsv.On;
 
-             }
 
-         }
 
-         public bool IsPing
 
-         {
 
-             get
 
-             {
 
-                 return _opcode == Opcode.Ping;
 
-             }
 
-         }
 
-         public bool IsPong
 
-         {
 
-             get
 
-             {
 
-                 return _opcode == Opcode.Pong;
 
-             }
 
-         }
 
-         public bool IsText
 
-         {
 
-             get
 
-             {
 
-                 return _opcode == Opcode.Text;
 
-             }
 
-         }
 
-         public ulong Length
 
-         {
 
-             get
 
-             {
 
-                 return 2 + (ulong)(_extPayloadLength.Length + _maskingKey.Length) + _payloadData.Length;
 
-             }
 
-         }
 
-         public Mask Mask
 
-         {
 
-             get
 
-             {
 
-                 return _mask;
 
-             }
 
-         }
 
-         public byte[] MaskingKey
 
-         {
 
-             get
 
-             {
 
-                 return _maskingKey;
 
-             }
 
-         }
 
-         public Opcode Opcode
 
-         {
 
-             get
 
-             {
 
-                 return _opcode;
 
-             }
 
-         }
 
-         public PayloadData PayloadData
 
-         {
 
-             get
 
-             {
 
-                 return _payloadData;
 
-             }
 
-         }
 
-         public byte PayloadLength
 
-         {
 
-             get
 
-             {
 
-                 return _payloadLength;
 
-             }
 
-         }
 
-         public Rsv Rsv1
 
-         {
 
-             get
 
-             {
 
-                 return _rsv1;
 
-             }
 
-         }
 
-         public Rsv Rsv2
 
-         {
 
-             get
 
-             {
 
-                 return _rsv2;
 
-             }
 
-         }
 
-         public Rsv Rsv3
 
-         {
 
-             get
 
-             {
 
-                 return _rsv3;
 
-             }
 
-         }
 
-         #endregion
 
-         #region Private Methods
 
-         private byte[] createMaskingKey()
 
-         {
 
-             var key = new byte[4];
 
-             var rand = new Random();
 
-             rand.NextBytes(key);
 
-             return key;
 
-         }
 
-         private static bool isControl(Opcode opcode)
 
-         {
 
-             return opcode == Opcode.Close || opcode == Opcode.Ping || opcode == Opcode.Pong;
 
-         }
 
-         private static bool isData(Opcode opcode)
 
-         {
 
-             return opcode == Opcode.Text || opcode == Opcode.Binary;
 
-         }
 
-         private static WebSocketFrame read(byte[] header, Stream stream, bool unmask)
 
-         {
 
-             /* Header */
 
-             // FIN
 
-             var fin = (header[0] & 0x80) == 0x80 ? Fin.Final : Fin.More;
 
-             // RSV1
 
-             var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.On : Rsv.Off;
 
-             // RSV2
 
-             var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.On : Rsv.Off;
 
-             // RSV3
 
-             var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.On : Rsv.Off;
 
-             // Opcode
 
-             var opcode = (Opcode)(header[0] & 0x0f);
 
-             // MASK
 
-             var mask = (header[1] & 0x80) == 0x80 ? Mask.Mask : Mask.Unmask;
 
-             // Payload Length
 
-             var payloadLen = (byte)(header[1] & 0x7f);
 
-             // Check if correct frame.
 
-             var incorrect = isControl(opcode) && fin == Fin.More
 
-                             ? "A control frame is fragmented."
 
-                             : !isData(opcode) && rsv1 == Rsv.On
 
-                               ? "A non data frame is compressed."
 
-                               : null;
 
-             if (incorrect != null)
 
-                 throw new WebSocketException(CloseStatusCode.IncorrectData, incorrect);
 
-             // Check if consistent frame.
 
-             if (isControl(opcode) && payloadLen > 125)
 
-                 throw new WebSocketException(
 
-                   CloseStatusCode.InconsistentData,
 
-                   "The length of payload data of a control frame is greater than 125 bytes.");
 
-             var frame = new WebSocketFrame();
 
-             frame._fin = fin;
 
-             frame._rsv1 = rsv1;
 
-             frame._rsv2 = rsv2;
 
-             frame._rsv3 = rsv3;
 
-             frame._opcode = opcode;
 
-             frame._mask = mask;
 
-             frame._payloadLength = payloadLen;
 
-             /* Extended Payload Length */
 
-             var size = payloadLen < 126
 
-                        ? 0
 
-                        : payloadLen == 126
 
-                          ? 2
 
-                          : 8;
 
-             var extPayloadLen = size > 0 ? stream.ReadBytes(size) : new byte[0];
 
-             if (size > 0 && extPayloadLen.Length != size)
 
-                 throw new WebSocketException(
 
-                   "The 'Extended Payload Length' of a frame cannot be read from the data source.");
 
-             frame._extPayloadLength = extPayloadLen;
 
-             /* Masking Key */
 
-             var masked = mask == Mask.Mask;
 
-             var maskingKey = masked ? stream.ReadBytes(4) : new byte[0];
 
-             if (masked && maskingKey.Length != 4)
 
-                 throw new WebSocketException(
 
-                   "The 'Masking Key' of a frame cannot be read from the data source.");
 
-             frame._maskingKey = maskingKey;
 
-             /* Payload Data */
 
-             ulong len = payloadLen < 126
 
-                         ? payloadLen
 
-                         : payloadLen == 126
 
-                           ? extPayloadLen.ToUInt16(ByteOrder.Big)
 
-                           : extPayloadLen.ToUInt64(ByteOrder.Big);
 
-             byte[] data = null;
 
-             if (len > 0)
 
-             {
 
-                 // Check if allowable payload data length.
 
-                 if (payloadLen > 126 && len > PayloadData.MaxLength)
 
-                     throw new WebSocketException(
 
-                       CloseStatusCode.TooBig,
 
-                       "The length of 'Payload Data' of a frame is greater than the allowable length.");
 
-                 data = payloadLen > 126
 
-                        ? stream.ReadBytes((long)len, 1024)
 
-                        : stream.ReadBytes((int)len);
 
-                 //if (data.LongLength != (long)len)
 
-                 //    throw new WebSocketException(
 
-                 //      "The 'Payload Data' of a frame cannot be read from the data source.");
 
-             }
 
-             else
 
-             {
 
-                 data = new byte[0];
 
-             }
 
-             var payload = new PayloadData(data, masked);
 
-             if (masked && unmask)
 
-             {
 
-                 payload.Mask(maskingKey);
 
-                 frame._mask = Mask.Unmask;
 
-                 frame._maskingKey = new byte[0];
 
-             }
 
-             frame._payloadData = payload;
 
-             return frame;
 
-         }
 
-         #endregion
 
-         #region Internal Methods
 
-         internal static WebSocketFrame CreateCloseFrame(Mask mask, byte[] data)
 
-         {
 
-             return new WebSocketFrame(Opcode.Close, mask, new PayloadData(data));
 
-         }
 
-         internal static WebSocketFrame CreateCloseFrame(Mask mask, PayloadData payload)
 
-         {
 
-             return new WebSocketFrame(Opcode.Close, mask, payload);
 
-         }
 
-         internal static WebSocketFrame CreateCloseFrame(Mask mask, CloseStatusCode code, string reason)
 
-         {
 
-             return new WebSocketFrame(
 
-               Opcode.Close, mask, new PayloadData(((ushort)code).Append(reason)));
 
-         }
 
-         internal static WebSocketFrame CreatePingFrame(Mask mask)
 
-         {
 
-             return new WebSocketFrame(Opcode.Ping, mask, new PayloadData());
 
-         }
 
-         internal static WebSocketFrame CreatePingFrame(Mask mask, byte[] data)
 
-         {
 
-             return new WebSocketFrame(Opcode.Ping, mask, new PayloadData(data));
 
-         }
 
-         internal static WebSocketFrame CreatePongFrame(Mask mask, PayloadData payload)
 
-         {
 
-             return new WebSocketFrame(Opcode.Pong, mask, payload);
 
-         }
 
-         internal static WebSocketFrame CreateWebSocketFrame(
 
-           Fin fin, Opcode opcode, Mask mask, byte[] data, bool compressed)
 
-         {
 
-             return new WebSocketFrame(fin, opcode, mask, new PayloadData(data), compressed);
 
-         }
 
-         internal static WebSocketFrame Read(Stream stream)
 
-         {
 
-             return Read(stream, true);
 
-         }
 
-         internal static WebSocketFrame Read(Stream stream, bool unmask)
 
-         {
 
-             var header = stream.ReadBytes(2);
 
-             if (header.Length != 2)
 
-                 throw new WebSocketException(
 
-                   "The header part of a frame cannot be read from the data source.");
 
-             return read(header, stream, unmask);
 
-         }
 
-         internal static async void ReadAsync(
 
-           Stream stream, bool unmask, Action<WebSocketFrame> completed, Action<Exception> error)
 
-         {
 
-             try
 
-             {
 
-                 var header = await stream.ReadBytesAsync(2).ConfigureAwait(false);
 
-                 if (header.Length != 2)
 
-                     throw new WebSocketException(
 
-                       "The header part of a frame cannot be read from the data source.");
 
-                 var frame = read(header, stream, unmask);
 
-                 if (completed != null)
 
-                     completed(frame);
 
-             }
 
-             catch (Exception ex)
 
-             {
 
-                 if (error != null)
 
-                 {
 
-                     error(ex);
 
-                 }
 
-             }
 
-         }
 
-         #endregion
 
-         #region Public Methods
 
-         public IEnumerator<byte> GetEnumerator()
 
-         {
 
-             foreach (var b in ToByteArray())
 
-                 yield return b;
 
-         }
 
-         public void Print(bool dumped)
 
-         {
 
-             //Console.WriteLine(dumped ? dump(this) : print(this));
 
-         }
 
-         public byte[] ToByteArray()
 
-         {
 
-             using (var buff = new MemoryStream())
 
-             {
 
-                 var header = (int)_fin;
 
-                 header = (header << 1) + (int)_rsv1;
 
-                 header = (header << 1) + (int)_rsv2;
 
-                 header = (header << 1) + (int)_rsv3;
 
-                 header = (header << 4) + (int)_opcode;
 
-                 header = (header << 1) + (int)_mask;
 
-                 header = (header << 7) + (int)_payloadLength;
 
-                 buff.Write(((ushort)header).ToByteArrayInternally(ByteOrder.Big), 0, 2);
 
-                 if (_payloadLength > 125)
 
-                     buff.Write(_extPayloadLength, 0, _extPayloadLength.Length);
 
-                 if (_mask == Mask.Mask)
 
-                     buff.Write(_maskingKey, 0, _maskingKey.Length);
 
-                 if (_payloadLength > 0)
 
-                 {
 
-                     var payload = _payloadData.ToByteArray();
 
-                     if (_payloadLength < 127)
 
-                         buff.Write(payload, 0, payload.Length);
 
-                     else
 
-                         buff.WriteBytes(payload);
 
-                 }
 
-                 return buff.ToArray();
 
-             }
 
-         }
 
-         public override string ToString()
 
-         {
 
-             return BitConverter.ToString(ToByteArray());
 
-         }
 
-         #endregion
 
-         #region Explicitly Implemented Interface Members
 
-         IEnumerator IEnumerable.GetEnumerator()
 
-         {
 
-             return GetEnumerator();
 
-         }
 
-         #endregion
 
-     }
 
- }
 
 
  |