123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- #if !BESTHTTP_DISABLE_WEBSOCKET && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using System.IO;
- namespace BestHTTP.WebSocket.Frames
- {
-
-
-
-
- public sealed class WebSocketFrame
- {
- public static readonly byte[] NoData = new byte[0];
- public WebSocketFrameTypes Type { get; private set; }
- public bool IsFinal { get; private set; }
- public byte Header { get; private set; }
- public byte[] Data { get; private set; }
- public bool UseExtensions { get; private set; }
- #region Constructors
- public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, byte[] data)
- :this(webSocket, type, data, true)
- { }
- public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, byte[] data, bool useExtensions)
- : this(webSocket, type, data, 0, data != null ? (UInt64)data.Length : 0, true, useExtensions)
- {
- }
- public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, byte[] data, bool isFinal, bool useExtensions)
- : this(webSocket, type, data, 0, data != null ? (UInt64)data.Length : 0, isFinal, useExtensions)
- {
- }
- public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, byte[] data, UInt64 pos, UInt64 length, bool isFinal, bool useExtensions)
- {
- this.Type = type;
- this.IsFinal = isFinal;
- this.UseExtensions = useExtensions;
- if (data != null)
- {
- this.Data = new byte[length];
- Array.Copy(data, (int)pos, this.Data, 0, (int)length);
- }
- else
- data = NoData;
-
- byte finalBit = (byte)(IsFinal ? 0x80 : 0x0);
- this.Header = (byte)(finalBit | (byte)Type);
- if (this.UseExtensions && webSocket != null && webSocket.Extensions != null)
- {
- for (int i = 0; i < webSocket.Extensions.Length; ++i)
- {
- var ext = webSocket.Extensions[i];
- if (ext != null)
- {
- this.Header |= ext.GetFrameHeader(this, this.Header);
- this.Data = ext.Encode(this);
- }
- }
- }
- }
- #endregion
- #region Public Functions
- public byte[] Get()
- {
- if (Data == null)
- Data = NoData;
- using (var ms = new MemoryStream(this.Data.Length + 9))
- {
-
-
-
- ms.WriteByte(this.Header);
-
-
-
- if (this.Data.Length < 126)
- ms.WriteByte((byte)(0x80 | (byte)this.Data.Length));
- else if (this.Data.Length < UInt16.MaxValue)
- {
- ms.WriteByte((byte)(0x80 | 126));
- byte[] len = BitConverter.GetBytes((UInt16)this.Data.Length);
- if (BitConverter.IsLittleEndian)
- Array.Reverse(len, 0, len.Length);
- ms.Write(len, 0, len.Length);
- }
- else
- {
- ms.WriteByte((byte)(0x80 | 127));
- byte[] len = BitConverter.GetBytes((UInt64)this.Data.Length);
- if (BitConverter.IsLittleEndian)
- Array.Reverse(len, 0, len.Length);
- ms.Write(len, 0, len.Length);
- }
-
-
-
- byte[] mask = BitConverter.GetBytes((Int32)this.GetHashCode());
- ms.Write(mask, 0, mask.Length);
-
- for (int i = 0; i < this.Data.Length; ++i)
- ms.WriteByte((byte)(Data[i] ^ mask[i % 4]));
- return ms.ToArray();
- }
- }
- public WebSocketFrame[] Fragment(ushort maxFragmentSize)
- {
- if (this.Data == null)
- return null;
-
- if (this.Type != WebSocketFrameTypes.Binary && this.Type != WebSocketFrameTypes.Text)
- return null;
- if (this.Data.Length <= maxFragmentSize)
- return null;
- this.IsFinal = false;
-
- this.Header &= 0x7F;
-
- int count = (this.Data.Length / maxFragmentSize) + (this.Data.Length % maxFragmentSize == 0 ? -1 : 0);
- WebSocketFrame[] fragments = new WebSocketFrame[count];
-
- UInt64 pos = maxFragmentSize;
- while (pos < (UInt64)this.Data.Length)
- {
- UInt64 chunkLength = Math.Min(maxFragmentSize, (UInt64)this.Data.Length - pos);
- fragments[fragments.Length - count--] = new WebSocketFrame(null, WebSocketFrameTypes.Continuation, this.Data, pos, chunkLength, pos + chunkLength >= (UInt64)this.Data.Length, false);
- pos += chunkLength;
- }
- byte[] newData = new byte[maxFragmentSize];
- Array.Copy(this.Data, 0, newData, 0, maxFragmentSize);
- this.Data = newData;
- return fragments;
- }
- #endregion
- }
- }
- #endif
|