/// <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 async Task<WebSocketFrame> ReadAsync(System.IO.Stream fromStream, ArraySegment<byte> intoBuffer, CancellationToken cancellationToken)
        {
            // allocate a small buffer to read small chunks of data from the stream
            var smallBuffer = new ArraySegment<byte>(new byte[8]);

            await BinaryReaderWriter.ReadExactly(2, fromStream, smallBuffer, cancellationToken);
            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 = await ReadLength(byte2, smallBuffer, fromStream, cancellationToken);
            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, WebSocketFrameCommon.MaskKeyLength);
                    await BinaryReaderWriter.ReadExactly(maskKey.Count, fromStream, maskKey, cancellationToken);
                    await BinaryReaderWriter.ReadExactly(count, fromStream, intoBuffer, cancellationToken);
                    ArraySegment<byte> payloadToMask = new ArraySegment<byte>(intoBuffer.Array, intoBuffer.Offset, count);
                    WebSocketFrameCommon.ToggleMask(maskKey, payloadToMask);
                }
                else
                {
                    await BinaryReaderWriter.ReadExactly(count, fromStream, intoBuffer, cancellationToken);
                }
            } 
            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);
            }
        }
Exemple #2
0
        /// <summary>
        /// The last read could not be completed because the read buffer was too small.
        /// We need to continue reading bytes off the stream.
        /// Not to be confused with a continuation frame
        /// </summary>
        /// <param name="fromStream">The stream to read from</param>
        /// <param name="intoBuffer">The buffer to read into</param>
        /// <param name="readCursor">The previous partial websocket frame read plus cursor information</param>
        /// <param name="cancellationToken">the cancellation token</param>
        /// <returns>A websocket frame</returns>
        public static async Task <WebSocketReadCursor> ReadFromCursorAsync(System.IO.Stream fromStream,
                                                                           ArraySegment <byte> intoBuffer, WebSocketReadCursor readCursor, CancellationToken cancellationToken)
        {
            var remainingFrame = readCursor.WebSocketFrame;
            var minCount       = CalculateNumBytesToRead(readCursor.NumBytesLeftToRead, intoBuffer.Count);
            await BinaryReaderWriter.ReadExactly(minCount, fromStream, intoBuffer, cancellationToken);

            if (remainingFrame.MaskKey.Count > 0)
            {
                ArraySegment <byte> payloadToMask =
                    new ArraySegment <byte>(intoBuffer.Array, intoBuffer.Offset, minCount);
                WebSocketFrameCommon.ToggleMask(remainingFrame.MaskKey, payloadToMask);
            }

            return(new WebSocketReadCursor(remainingFrame, minCount, readCursor.NumBytesLeftToRead - minCount));
        }