websocket-sharp/websocket-sharp/WebSocketFrame.cs

798 lines
20 KiB
C#
Raw Normal View History

2013-04-08 14:11:57 +08:00
#region License
2013-01-11 19:32:38 +08:00
/*
* WebSocketFrame.cs
2012-07-31 09:36:52 +08:00
*
* The MIT License
*
* Copyright (c) 2012-2015 sta.blockhead
2014-06-11 15:46:07 +08:00
*
2012-07-31 09:36:52 +08:00
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
2014-06-11 15:46:07 +08:00
*
2012-07-31 09:36:52 +08:00
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Contributors
/*
* Contributors:
* - Chris Swiedler
*/
#endregion
2012-07-31 09:36:52 +08:00
using System;
2012-10-04 14:04:21 +08:00
using System.Collections;
2012-07-31 09:36:52 +08:00
using System.Collections.Generic;
2014-06-11 15:46:07 +08:00
using System.IO;
2012-07-31 09:36:52 +08:00
using System.Text;
2013-10-01 13:52:39 +08:00
namespace WebSocketSharp
{
internal class WebSocketFrame : IEnumerable<byte>
2012-07-31 09:36:52 +08:00
{
2014-06-11 15:46:07 +08:00
#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;
2014-06-11 15:46:07 +08:00
#endregion
2014-07-26 21:01:13 +08:00
#region Internal Fields
2015-10-07 10:08:34 +08:00
/// <summary>
2015-12-20 15:02:47 +08:00
/// Represents the ping frame without the payload data as an array of <see cref="byte"/>.
2015-10-07 10:08:34 +08:00
/// </summary>
/// <remarks>
2015-10-23 11:00:15 +08:00
/// The value of this field is created from a non masked frame, so it can only be used to
2015-12-20 15:02:47 +08:00
/// send a ping from a server.
2015-10-07 10:08:34 +08:00
/// </remarks>
internal static readonly byte[] EmptyPingBytes;
#endregion
#region Static Constructor
static WebSocketFrame ()
{
2015-10-07 10:08:34 +08:00
EmptyPingBytes = CreatePingFrame (false).ToArray ();
}
#endregion
2013-04-08 14:11:57 +08:00
#region Private Constructors
2012-07-31 09:36:52 +08:00
private WebSocketFrame ()
2012-07-31 09:36:52 +08:00
{
}
#endregion
2014-07-26 21:01:13 +08:00
#region Internal Constructors
2012-07-31 09:36:52 +08:00
2014-09-24 13:37:11 +08:00
internal WebSocketFrame (Opcode opcode, PayloadData payloadData, bool mask)
: this (Fin.Final, opcode, payloadData, false, mask)
2012-07-31 09:36:52 +08:00
{
}
2014-09-24 13:37:11 +08:00
internal WebSocketFrame (Fin fin, Opcode opcode, byte[] data, bool compressed, bool mask)
: this (fin, opcode, new PayloadData (data), compressed, mask)
2013-04-23 17:08:42 +08:00
{
}
2014-07-26 21:01:13 +08:00
internal WebSocketFrame (
2014-09-24 13:37:11 +08:00
Fin fin, Opcode opcode, PayloadData payloadData, bool compressed, bool mask)
2012-07-31 09:36:52 +08:00
{
2014-06-11 15:46:07 +08:00
_fin = fin;
_rsv1 = opcode.IsData () && compressed ? Rsv.On : Rsv.Off;
2014-06-11 15:46:07 +08:00
_rsv2 = Rsv.Off;
_rsv3 = Rsv.Off;
_opcode = opcode;
2014-09-24 13:37:11 +08:00
var len = payloadData.Length;
if (len < 126) {
_payloadLength = (byte) len;
_extPayloadLength = WebSocket.EmptyBytes;
}
else if (len < 0x010000) {
_payloadLength = (byte) 126;
2014-08-19 13:14:59 +08:00
_extPayloadLength = ((ushort) len).InternalToByteArray (ByteOrder.Big);
}
else {
_payloadLength = (byte) 127;
2014-08-19 13:14:59 +08:00
_extPayloadLength = len.InternalToByteArray (ByteOrder.Big);
}
2014-09-24 13:37:11 +08:00
if (mask) {
2015-10-27 13:47:44 +08:00
_mask = Mask.On;
2014-06-11 15:46:07 +08:00
_maskingKey = createMaskingKey ();
2014-09-24 13:37:11 +08:00
payloadData.Mask (_maskingKey);
2014-06-11 15:46:07 +08:00
}
else {
2015-10-27 13:47:44 +08:00
_mask = Mask.Off;
_maskingKey = WebSocket.EmptyBytes;
2014-06-11 15:46:07 +08:00
}
2014-09-24 13:37:11 +08:00
_payloadData = payloadData;
2012-07-31 09:36:52 +08:00
}
#endregion
2015-10-05 13:31:00 +08:00
#region Internal Properties
2013-04-12 13:42:25 +08:00
2015-10-05 13:31:00 +08:00
internal int ExtendedPayloadLengthCount {
2013-04-23 17:08:42 +08:00
get {
2015-10-05 13:31:00 +08:00
return _payloadLength < 126 ? 0 : (_payloadLength == 126 ? 2 : 8);
2013-04-23 17:08:42 +08:00
}
}
2015-10-06 13:43:36 +08:00
internal ulong FullPayloadLength {
get {
return _payloadLength < 126
? _payloadLength
: _payloadLength == 126
? _extPayloadLength.ToUInt16 (ByteOrder.Big)
: _extPayloadLength.ToUInt64 (ByteOrder.Big);
}
}
2015-10-05 13:31:00 +08:00
#endregion
#region Public Properties
public byte[] ExtendedPayloadLength {
2015-09-27 14:08:51 +08:00
get {
2015-10-05 13:31:00 +08:00
return _extPayloadLength;
2015-09-27 14:08:51 +08:00
}
}
2014-06-11 15:46:07 +08:00
public Fin Fin {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _fin;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsBinary {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Binary;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsClose {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Close;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsCompressed {
2013-04-12 13:42:25 +08:00
get {
2014-06-11 15:46:07 +08:00
return _rsv1 == Rsv.On;
2013-04-12 13:42:25 +08:00
}
}
2012-10-09 11:14:55 +08:00
2014-06-11 15:46:07 +08:00
public bool IsContinuation {
2013-04-12 13:42:25 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Cont;
2013-04-12 13:42:25 +08:00
}
}
2012-10-09 11:14:55 +08:00
2014-06-11 15:46:07 +08:00
public bool IsControl {
2013-03-25 14:17:31 +08:00
get {
2015-12-18 14:36:52 +08:00
return _opcode >= Opcode.Close;
2013-03-25 14:17:31 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsData {
2013-04-23 17:08:42 +08:00
get {
2015-12-18 14:36:52 +08:00
return _opcode == Opcode.Text || _opcode == Opcode.Binary;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsFinal {
2012-11-13 15:38:48 +08:00
get {
2014-06-11 15:46:07 +08:00
return _fin == Fin.Final;
}
}
2015-12-12 14:26:05 +08:00
public bool IsFragment {
get {
2014-06-11 15:46:07 +08:00
return _fin == Fin.More || _opcode == Opcode.Cont;
2012-10-09 11:14:55 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsMasked {
2013-04-23 17:08:42 +08:00
get {
2015-10-27 13:47:44 +08:00
return _mask == Mask.On;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsPing {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Ping;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsPong {
2012-11-13 15:38:48 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Pong;
2012-10-09 11:14:55 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsText {
get {
return _opcode == Opcode.Text;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public ulong Length {
get {
return 2 + (ulong) (_extPayloadLength.Length + _maskingKey.Length) + _payloadData.Length;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Mask Mask {
get {
return _mask;
}
}
2013-04-12 13:42:25 +08:00
2014-07-26 21:01:13 +08:00
public byte[] MaskingKey {
2014-06-11 15:46:07 +08:00
get {
return _maskingKey;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Opcode Opcode {
get {
return _opcode;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public PayloadData PayloadData {
get {
return _payloadData;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public byte PayloadLength {
get {
return _payloadLength;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Rsv Rsv1 {
get {
return _rsv1;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Rsv Rsv2 {
get {
return _rsv2;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Rsv Rsv3 {
get {
return _rsv3;
}
}
2013-04-12 13:42:25 +08:00
#endregion
2012-10-04 14:04:21 +08:00
#region Private Methods
2012-07-31 09:36:52 +08:00
2014-07-26 21:01:13 +08:00
private static byte[] createMaskingKey ()
{
2014-07-26 21:01:13 +08:00
var key = new byte[4];
2015-08-04 14:50:36 +08:00
WebSocket.RandomNumber.GetBytes (key);
return key;
}
private static string dump (WebSocketFrame frame)
2012-07-31 09:36:52 +08:00
{
2013-04-12 13:42:25 +08:00
var len = frame.Length;
2014-06-11 15:46:07 +08:00
var cnt = (long) (len / 4);
2013-11-05 20:42:59 +08:00
var rem = (int) (len % 4);
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
int cntDigit;
string cntFmt;
if (cnt < 10000) {
cntDigit = 4;
cntFmt = "{0,4}";
2013-04-12 13:42:25 +08:00
}
2014-06-11 15:46:07 +08:00
else if (cnt < 0x010000) {
cntDigit = 4;
cntFmt = "{0,4:X}";
2013-04-12 13:42:25 +08:00
}
2014-06-11 15:46:07 +08:00
else if (cnt < 0x0100000000) {
cntDigit = 8;
cntFmt = "{0,8:X}";
2013-04-12 13:42:25 +08:00
}
2014-06-11 15:46:07 +08:00
else {
cntDigit = 16;
cntFmt = "{0,16:X}";
2013-04-12 13:42:25 +08:00
}
2014-06-11 15:46:07 +08:00
var spFmt = String.Format ("{{0,{0}}}", cntDigit);
2014-09-10 12:50:28 +08:00
var headerFmt = String.Format (@"
{0} 01234567 89ABCDEF 01234567 89ABCDEF
2013-11-05 20:42:59 +08:00
{0}+--------+--------+--------+--------+\n", spFmt);
var lineFmt = String.Format ("{0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|\n", cntFmt);
2013-11-05 20:42:59 +08:00
var footerFmt = String.Format ("{0}+--------+--------+--------+--------+", spFmt);
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
var output = new StringBuilder (64);
Func<Action<string, string, string, string>> linePrinter = () => {
long lineCnt = 0;
2013-04-12 13:42:25 +08:00
return (arg1, arg2, arg3, arg4) =>
2014-06-11 15:46:07 +08:00
output.AppendFormat (lineFmt, ++lineCnt, arg1, arg2, arg3, arg4);
2013-04-12 13:42:25 +08:00
};
2015-05-16 16:08:45 +08:00
var printLine = linePrinter ();
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
output.AppendFormat (headerFmt, String.Empty);
2013-04-12 13:42:25 +08:00
2015-10-02 10:32:36 +08:00
var bytes = frame.ToArray ();
for (long i = 0; i <= cnt; i++) {
2014-06-11 15:46:07 +08:00
var j = i * 4;
2015-05-16 16:08:45 +08:00
if (i < cnt) {
2013-10-01 13:52:39 +08:00
printLine (
2015-05-16 16:08:45 +08:00
Convert.ToString (bytes[j], 2).PadLeft (8, '0'),
2014-09-10 12:50:28 +08:00
Convert.ToString (bytes[j + 1], 2).PadLeft (8, '0'),
Convert.ToString (bytes[j + 2], 2).PadLeft (8, '0'),
Convert.ToString (bytes[j + 3], 2).PadLeft (8, '0'));
2015-05-16 16:08:45 +08:00
continue;
}
if (rem > 0)
2013-10-01 13:52:39 +08:00
printLine (
2014-09-10 12:50:28 +08:00
Convert.ToString (bytes[j], 2).PadLeft (8, '0'),
rem >= 2 ? Convert.ToString (bytes[j + 1], 2).PadLeft (8, '0') : String.Empty,
rem == 3 ? Convert.ToString (bytes[j + 2], 2).PadLeft (8, '0') : String.Empty,
2013-04-12 13:42:25 +08:00
String.Empty);
}
2014-06-11 15:46:07 +08:00
output.AppendFormat (footerFmt, String.Empty);
return output.ToString ();
2013-04-23 17:08:42 +08:00
}
2014-07-26 21:01:13 +08:00
private static string print (WebSocketFrame frame)
{
2015-10-08 13:38:33 +08:00
// Payload Length
2014-07-26 21:01:13 +08:00
var payloadLen = frame._payloadLength;
2015-10-08 13:38:33 +08:00
// Extended Payload Length
var extPayloadLen = payloadLen > 125 ? frame.FullPayloadLength.ToString () : String.Empty;
2014-07-26 21:01:13 +08:00
2015-10-08 13:38:33 +08:00
// Masking Key
var maskingKey = BitConverter.ToString (frame._maskingKey);
2014-07-26 21:01:13 +08:00
2015-10-08 13:38:33 +08:00
// Payload Data
2014-07-26 21:01:13 +08:00
var payload = payloadLen == 0
? String.Empty
2014-09-10 12:50:28 +08:00
: payloadLen > 125
2015-10-08 13:38:33 +08:00
? "---"
2015-12-12 14:26:05 +08:00
: frame.IsText && !(frame.IsFragment || frame.IsMasked || frame.IsCompressed)
2015-10-08 13:38:33 +08:00
? frame._payloadData.ApplicationData.UTF8Decode ()
2014-07-26 21:01:13 +08:00
: frame._payloadData.ToString ();
2014-09-10 12:50:28 +08:00
var fmt = @"
FIN: {0}
2014-07-26 21:01:13 +08:00
RSV1: {1}
RSV2: {2}
RSV3: {3}
Opcode: {4}
MASK: {5}
Payload Length: {6}
Extended Payload Length: {7}
Masking Key: {8}
Payload Data: {9}";
return String.Format (
fmt,
frame._fin,
frame._rsv1,
frame._rsv2,
frame._rsv3,
2015-10-08 13:38:33 +08:00
frame._opcode,
2014-07-26 21:01:13 +08:00
frame._mask,
payloadLen,
extPayloadLen,
maskingKey,
payload);
}
2015-09-19 14:35:15 +08:00
private static WebSocketFrame processHeader (byte[] header)
{
if (header.Length != 2)
2015-12-19 15:08:04 +08:00
throw new WebSocketException ("The header of a frame cannot be read from the stream.");
2015-09-19 14:35:15 +08:00
// 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
2015-12-13 16:54:39 +08:00
var opcode = (byte) (header[0] & 0x0f);
2015-09-19 14:35:15 +08:00
// MASK
2015-10-27 13:47:44 +08:00
var mask = (header[1] & 0x80) == 0x80 ? Mask.On : Mask.Off;
2015-09-19 14:35:15 +08:00
// Payload Length
var payloadLen = (byte) (header[1] & 0x7f);
var err = !opcode.IsSupported ()
2015-12-13 16:54:39 +08:00
? "An unsupported opcode."
2015-12-16 14:57:10 +08:00
: !opcode.IsData () && rsv1 == Rsv.On
? "A non data frame is compressed."
: opcode.IsControl () && fin == Fin.More
? "A control frame is fragmented."
: opcode.IsControl () && payloadLen > 125
? "A control frame has a long payload length."
2015-12-13 16:54:39 +08:00
: null;
2015-09-19 14:35:15 +08:00
if (err != null)
throw new WebSocketException (CloseStatusCode.ProtocolError, err);
var frame = new WebSocketFrame ();
frame._fin = fin;
frame._rsv1 = rsv1;
frame._rsv2 = rsv2;
frame._rsv3 = rsv3;
2015-12-13 16:54:39 +08:00
frame._opcode = (Opcode) opcode;
2015-09-19 14:35:15 +08:00
frame._mask = mask;
frame._payloadLength = payloadLen;
return frame;
}
2015-09-20 15:39:19 +08:00
private static WebSocketFrame readExtendedPayloadLength (Stream stream, WebSocketFrame frame)
{
2015-09-27 14:08:51 +08:00
var len = frame.ExtendedPayloadLengthCount;
2015-09-20 15:39:19 +08:00
if (len == 0) {
frame._extPayloadLength = WebSocket.EmptyBytes;
return frame;
}
var bytes = stream.ReadBytes (len);
if (bytes.Length != len)
throw new WebSocketException (
2015-12-19 15:08:04 +08:00
"The extended payload length of a frame cannot be read from the stream.");
2015-09-20 15:39:19 +08:00
frame._extPayloadLength = bytes;
return frame;
}
private static void readExtendedPayloadLengthAsync (
Stream stream,
WebSocketFrame frame,
Action<WebSocketFrame> completed,
Action<Exception> error)
{
2015-09-27 14:08:51 +08:00
var len = frame.ExtendedPayloadLengthCount;
2015-09-22 11:23:43 +08:00
if (len == 0) {
frame._extPayloadLength = WebSocket.EmptyBytes;
completed (frame);
return;
}
stream.ReadBytesAsync (
2015-09-22 11:23:43 +08:00
len,
bytes => {
if (bytes.Length != len)
throw new WebSocketException (
2015-12-19 15:08:04 +08:00
"The extended payload length of a frame cannot be read from the stream.");
2015-09-22 11:23:43 +08:00
frame._extPayloadLength = bytes;
completed (frame);
},
error);
}
2015-09-20 15:39:19 +08:00
private static WebSocketFrame readHeader (Stream stream)
{
return processHeader (stream.ReadBytes (2));
}
private static void readHeaderAsync (
Stream stream, Action<WebSocketFrame> completed, Action<Exception> error)
{
2015-09-22 11:23:43 +08:00
stream.ReadBytesAsync (2, bytes => completed (processHeader (bytes)), error);
}
2015-09-20 15:39:19 +08:00
private static WebSocketFrame readMaskingKey (Stream stream, WebSocketFrame frame)
{
var len = frame.IsMasked ? 4 : 0;
if (len == 0) {
frame._maskingKey = WebSocket.EmptyBytes;
return frame;
}
var bytes = stream.ReadBytes (len);
if (bytes.Length != len)
2015-12-19 15:08:04 +08:00
throw new WebSocketException ("The masking key of a frame cannot be read from the stream.");
2015-09-20 15:39:19 +08:00
frame._maskingKey = bytes;
return frame;
}
private static void readMaskingKeyAsync (
Stream stream,
WebSocketFrame frame,
Action<WebSocketFrame> completed,
Action<Exception> error)
{
2015-09-22 11:23:43 +08:00
var len = frame.IsMasked ? 4 : 0;
if (len == 0) {
frame._maskingKey = WebSocket.EmptyBytes;
completed (frame);
return;
}
stream.ReadBytesAsync (
2015-09-22 11:23:43 +08:00
len,
bytes => {
if (bytes.Length != len)
throw new WebSocketException (
2015-12-19 15:08:04 +08:00
"The masking key of a frame cannot be read from the stream.");
2015-09-22 11:23:43 +08:00
frame._maskingKey = bytes;
completed (frame);
},
error);
}
2015-09-20 15:39:19 +08:00
private static WebSocketFrame readPayloadData (Stream stream, WebSocketFrame frame)
{
2015-09-26 10:57:34 +08:00
var len = frame.FullPayloadLength;
2015-09-20 15:39:19 +08:00
if (len == 0) {
2015-10-03 14:12:21 +08:00
frame._payloadData = PayloadData.Empty;
2015-09-20 15:39:19 +08:00
return frame;
}
if (len > PayloadData.MaxLength)
2015-12-19 15:08:04 +08:00
throw new WebSocketException (CloseStatusCode.TooBig, "A frame has a long payload length.");
2015-09-20 15:39:19 +08:00
2015-10-02 14:03:10 +08:00
var llen = (long) len;
2015-09-20 15:39:19 +08:00
var bytes = frame._payloadLength < 127
? stream.ReadBytes ((int) len)
2015-10-02 14:03:10 +08:00
: stream.ReadBytes (llen, 1024);
2015-09-20 15:39:19 +08:00
2015-10-02 14:03:10 +08:00
if (bytes.LongLength != llen)
2015-09-20 15:39:19 +08:00
throw new WebSocketException (
2015-12-19 15:08:04 +08:00
"The payload data of a frame cannot be read from the stream.");
2015-09-20 15:39:19 +08:00
2015-10-02 14:03:10 +08:00
frame._payloadData = new PayloadData (bytes, llen);
2015-09-20 15:39:19 +08:00
return frame;
}
private static void readPayloadDataAsync (
Stream stream,
WebSocketFrame frame,
Action<WebSocketFrame> completed,
Action<Exception> error)
{
2015-09-26 10:57:34 +08:00
var len = frame.FullPayloadLength;
2015-09-22 11:23:43 +08:00
if (len == 0) {
2015-10-03 14:12:21 +08:00
frame._payloadData = PayloadData.Empty;
completed (frame);
return;
}
2015-09-22 11:23:43 +08:00
if (len > PayloadData.MaxLength)
2015-12-19 15:08:04 +08:00
throw new WebSocketException (CloseStatusCode.TooBig, "A frame has a long payload length.");
2015-09-22 11:23:43 +08:00
2015-10-02 14:03:10 +08:00
var llen = (long) len;
2015-09-25 14:00:58 +08:00
Action<byte[]> compl = bytes => {
2015-10-02 14:03:10 +08:00
if (bytes.LongLength != llen)
2015-09-25 14:00:58 +08:00
throw new WebSocketException (
2015-12-19 15:08:04 +08:00
"The payload data of a frame cannot be read from the stream.");
2015-09-25 14:00:58 +08:00
2015-10-02 14:03:10 +08:00
frame._payloadData = new PayloadData (bytes, llen);
2015-09-25 14:00:58 +08:00
completed (frame);
};
2015-09-25 14:00:58 +08:00
if (frame._payloadLength < 127) {
stream.ReadBytesAsync ((int) len, compl, error);
return;
}
2015-10-02 14:03:10 +08:00
stream.ReadBytesAsync (llen, 1024, compl, error);
}
2013-04-23 17:08:42 +08:00
#endregion
2013-10-01 13:52:39 +08:00
#region Internal Methods
2017-01-07 16:05:48 +08:00
internal static WebSocketFrame CreateCloseFrame (
PayloadData payloadData, bool mask
)
2013-10-01 13:52:39 +08:00
{
2017-01-07 16:05:48 +08:00
return new WebSocketFrame (
Fin.Final, Opcode.Close, payloadData, false, mask
);
2013-10-01 13:52:39 +08:00
}
internal static WebSocketFrame CreatePingFrame (bool mask)
2013-10-01 13:52:39 +08:00
{
2017-01-07 16:08:08 +08:00
return new WebSocketFrame (
Fin.Final, Opcode.Ping, PayloadData.Empty, false, mask
);
2013-10-01 13:52:39 +08:00
}
internal static WebSocketFrame CreatePingFrame (byte[] data, bool mask)
2013-10-01 13:52:39 +08:00
{
2017-01-07 16:10:40 +08:00
return new WebSocketFrame (
Fin.Final, Opcode.Ping, new PayloadData (data), false, mask
);
2012-07-31 09:36:52 +08:00
}
2017-01-07 16:15:00 +08:00
internal static WebSocketFrame CreatePongFrame (
PayloadData payloadData, bool mask
)
{
return new WebSocketFrame (
Fin.Final, Opcode.Pong, payloadData, false, mask
);
}
2015-10-03 14:33:45 +08:00
internal static WebSocketFrame ReadFrame (Stream stream, bool unmask)
2012-10-04 14:04:21 +08:00
{
2015-09-20 15:39:19 +08:00
var frame = readHeader (stream);
readExtendedPayloadLength (stream, frame);
readMaskingKey (stream, frame);
readPayloadData (stream, frame);
2013-04-12 13:42:25 +08:00
2015-09-23 13:51:32 +08:00
if (unmask)
2015-09-20 15:39:19 +08:00
frame.Unmask ();
return frame;
2012-11-13 15:38:48 +08:00
}
2012-10-04 14:04:21 +08:00
2015-10-04 14:36:11 +08:00
internal static void ReadFrameAsync (
2017-01-10 16:28:29 +08:00
Stream stream,
bool unmask,
Action<WebSocketFrame> completed,
Action<Exception> error
)
{
readHeaderAsync (
stream,
2015-09-22 11:23:43 +08:00
frame =>
readExtendedPayloadLengthAsync (
stream,
frame,
2015-09-22 11:23:43 +08:00
frame1 =>
readMaskingKeyAsync (
stream,
frame1,
2015-09-22 11:23:43 +08:00
frame2 =>
readPayloadDataAsync (
stream,
frame2,
frame3 => {
2015-09-23 13:51:32 +08:00
if (unmask)
frame3.Unmask ();
completed (frame3);
},
2017-01-10 16:28:29 +08:00
error
),
error
),
error
),
error
);
}
internal void Unmask ()
{
2015-10-27 13:47:44 +08:00
if (_mask == Mask.Off)
return;
2015-10-27 13:47:44 +08:00
_mask = Mask.Off;
_payloadData.Mask (_maskingKey);
_maskingKey = WebSocket.EmptyBytes;
}
2014-07-26 21:01:13 +08:00
#endregion
#region Public Methods
public IEnumerator<byte> GetEnumerator ()
{
2015-10-02 10:32:36 +08:00
foreach (var b in ToArray ())
2014-07-26 21:01:13 +08:00
yield return b;
}
2013-10-01 13:52:39 +08:00
public void Print (bool dumped)
2012-07-31 09:36:52 +08:00
{
2013-11-05 20:42:59 +08:00
Console.WriteLine (dumped ? dump (this) : print (this));
}
public string PrintToString (bool dumped)
{
2015-05-16 16:08:45 +08:00
return dumped ? dump (this) : print (this);
2012-07-31 09:36:52 +08:00
}
2015-10-02 10:32:36 +08:00
public byte[] ToArray ()
2012-07-31 09:36:52 +08:00
{
2014-06-11 15:46:07 +08:00
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;
2014-08-19 13:14:59 +08:00
buff.Write (((ushort) header).InternalToByteArray (ByteOrder.Big), 0, 2);
2014-06-11 15:46:07 +08:00
if (_payloadLength > 125)
2015-05-17 16:49:21 +08:00
buff.Write (_extPayloadLength, 0, _payloadLength == 126 ? 2 : 8);
2015-10-27 13:47:44 +08:00
if (_mask == Mask.On)
2015-05-17 16:49:21 +08:00
buff.Write (_maskingKey, 0, 4);
2014-06-11 15:46:07 +08:00
if (_payloadLength > 0) {
2015-09-29 14:20:19 +08:00
var bytes = _payloadData.ToArray ();
2014-06-11 15:46:07 +08:00
if (_payloadLength < 127)
2015-05-17 16:49:21 +08:00
buff.Write (bytes, 0, bytes.Length);
else
2015-10-15 14:49:08 +08:00
buff.WriteBytes (bytes, 1024);
}
2012-07-31 09:36:52 +08:00
2014-06-11 15:46:07 +08:00
buff.Close ();
return buff.ToArray ();
}
2012-07-31 09:36:52 +08:00
}
2013-10-01 13:52:39 +08:00
public override string ToString ()
2012-07-31 09:36:52 +08:00
{
2015-10-02 10:32:36 +08:00
return BitConverter.ToString (ToArray ());
2013-04-12 13:42:25 +08:00
}
#endregion
2014-09-13 14:55:29 +08:00
#region Explicit Interface Implementations
2013-04-12 13:42:25 +08:00
2013-10-01 13:52:39 +08:00
IEnumerator IEnumerable.GetEnumerator ()
2013-04-12 13:42:25 +08:00
{
2013-10-01 13:52:39 +08:00
return GetEnumerator ();
2012-07-31 09:36:52 +08:00
}
#endregion
}
}