Esempio n. 1
0
        /// <summary>
        /// Read a WebSocket frame from the stream
        /// </summary>
        /// <param name="fromStream">The stream to read from</param>
        /// <param name="intoBuffer">The buffer to read into</param>
        /// <param name="cancellationToken">the cancellation token</param>
        /// <returns>A websocket frame</returns>
        public static WebSocketFrame Read(Stream fromStream, ArraySegment <byte> intoBuffer)
        {
            // allocate a small buffer to read small chunks of data from the stream
            var smallBuffer = new ArraySegment <byte>(new byte[8]);

            BinaryReaderWriter.ReadExactly(2, fromStream, smallBuffer);
            byte byte1 = smallBuffer.Array[0];
            byte byte2 = smallBuffer.Array[1];

            // process first byte
            byte            finBitFlag  = 0x80;
            byte            opCodeFlag  = 0x0F;
            bool            isFinBitSet = (byte1 & finBitFlag) == finBitFlag;
            WebSocketOpCode opCode      = (WebSocketOpCode)(byte1 & opCodeFlag);

            // read and process second byte
            byte maskFlag     = 0x80;
            bool isMaskBitSet = (byte2 & maskFlag) == maskFlag;
            uint len          = ReadLength(byte2, smallBuffer, fromStream);
            int  count        = (int)len;

            try
            {
                // use the masking key to decode the data if needed
                if (isMaskBitSet)
                {
                    ArraySegment <byte> maskKey = new ArraySegment <byte>(smallBuffer.Array, 0, WebSocketFrameExtensions.MaskKeyLength);
                    BinaryReaderWriter.ReadExactly(maskKey.Count, fromStream, maskKey);
                    BinaryReaderWriter.ReadExactly(count, fromStream, intoBuffer);
                    ArraySegment <byte> payloadToMask = new ArraySegment <byte>(intoBuffer.Array, intoBuffer.Offset, count);
                    WebSocketFrameExtensions.ToggleMask(maskKey, payloadToMask);
                }
                else
                {
                    BinaryReaderWriter.ReadExactly(count, fromStream, intoBuffer);
                }
            }
            catch (InternalBufferOverflowException e)
            {
                throw new InternalBufferOverflowException($"Supplied buffer too small to read {0} bytes from {Enum.GetName(typeof(WebSocketOpCode), opCode)} frame", e);
            }

            if (opCode == WebSocketOpCode.ConnectionClose)
            {
                return(DecodeCloseFrame(isFinBitSet, opCode, count, intoBuffer));
            }
            else
            {
                // note that by this point the payload will be populated
                return(new WebSocketFrame(isFinBitSet, opCode, count));
            }
        }
Esempio n. 2
0
        /// <summary>
        /// No async await stuff here because we are dealing with a memory stream
        /// </summary>
        /// <param name="opCode">The web socket opcode</param>
        /// <param name="fromPayload">Array segment to get payload data from</param>
        /// <param name="toStream">Stream to write to</param>
        /// <param name="isLastFrame">True is this is the last frame in this message (usually true)</param>
        public static void Write(WebSocketOpCode opCode, ArraySegment <byte> fromPayload, MemoryStream toStream, bool isLastFrame, bool isClient)
        {
            MemoryStream memoryStream    = toStream;
            byte         finBitSetAsByte = isLastFrame ? (byte)0x80 : (byte)0x00;
            byte         byte1           = (byte)(finBitSetAsByte | (byte)opCode);

            memoryStream.WriteByte(byte1);

            // NB, set the mask flag if we are constructing a client frame
            byte maskBitSetAsByte = isClient ? (byte)0x80 : (byte)0x00;

            // depending on the size of the length we want to write it as a byte, ushort or ulong
            if (fromPayload.Count < 126)
            {
                byte byte2 = (byte)(maskBitSetAsByte | (byte)fromPayload.Count);
                memoryStream.WriteByte(byte2);
            }
            else if (fromPayload.Count <= ushort.MaxValue)
            {
                byte byte2 = (byte)(maskBitSetAsByte | 126);
                memoryStream.WriteByte(byte2);
                BinaryReaderWriter.WriteUShort((ushort)fromPayload.Count, memoryStream, false);
            }
            else
            {
                byte byte2 = (byte)(maskBitSetAsByte | 127);
                memoryStream.WriteByte(byte2);
                BinaryReaderWriter.WriteULong((ulong)fromPayload.Count, memoryStream, false);
            }

            // if we are creating a client frame then we MUST mack the payload as per the spec
            if (isClient)
            {
                byte[] maskKey = new byte[WebSocketFrameExtensions.MaskKeyLength];
                _random.NextBytes(maskKey);
                memoryStream.Write(maskKey, 0, maskKey.Length);

                // mask the payload
                ArraySegment <byte> maskKeyArraySegment = new ArraySegment <byte>(maskKey, 0, maskKey.Length);
                WebSocketFrameExtensions.ToggleMask(maskKeyArraySegment, fromPayload);
            }

            memoryStream.Write(fromPayload.Array, fromPayload.Offset, fromPayload.Count);
        }
Esempio n. 3
0
        /// <summary>
        /// Reads the length of the payload according to the contents of byte2
        /// </summary>
        private static uint ReadLength(byte byte2, ArraySegment <byte> smallBuffer, Stream fromStream)
        {
            byte payloadLenFlag = 0x7F;
            uint len            = (uint)(byte2 & payloadLenFlag);

            // read a short length or a long length depending on the value of len
            if (len == 126)
            {
                len = BinaryReaderWriter.ReadUShortExactly(fromStream, false, smallBuffer);
            }
            else if (len == 127)
            {
                len = (uint)BinaryReaderWriter.ReadULongExactly(fromStream, false, smallBuffer);
                const uint maxLen = 2147483648; // 2GB - not part of the spec but just a precaution. Send large volumes of data in smaller frames.

                // protect ourselves against bad data
                if (len > maxLen || len < 0)
                {
                    throw new ArgumentOutOfRangeException($"Payload length out of range. Min 0 max 2GB. Actual {len:#,##0} bytes.");
                }
            }

            return(len);
        }