protected override void PreProcessRaw(ArraySegment <byte> data) { if (mode == Modes.WebSocket) { if (wsWaitHeader == false) { if (wsHeader.Mask) { wsHeader.UnmaskData(data.Array, data.Offset, Math.Min(data.Count, wsHeader.PayloadLength - wsMaskIndex), ref wsMaskIndex); } } } }
// Receive frames, unmask them. // Should handle pings/pongs internally. // Should parse out Close frames. public async Task <WebSocketReceiveTuple> ReceiveAsync(ArraySegment <byte> buffer, CancellationToken cancel) { if (currentHeader == null) { var header = new WebSocketHeader(); byte headerReadState = 1; // skip initialization byte[] headerBuffer = new byte[14]; int headerBytesRead = 0; int headerLength = 2; while (true) { if (headerReadState == 0) // re-initialize { // create buffer big enough to hold the complete header headerBuffer = new byte[14]; headerBytesRead = 0; headerLength = 2; headerReadState = 1; } var count = await stream.ReadAsync(headerBuffer, headerBytesRead, headerLength - headerBytesRead, cancel); headerBytesRead += count; if (headerBytesRead < headerLength) { continue; } if (headerReadState == 1) // read first 2 bytes { header.Fin = ((headerBuffer[0] >> 7) & 0x01) == 1; header.OpCode = (MessageType)((headerBuffer[0] >> 0) & 0x0f); header.Mask = ((headerBuffer[1] >> 7) & 0x01) == 1; headerReadState = 2; } if (headerReadState == 2) // read length { ulong len = (ulong)(headerBuffer[1] >> 0) & 0x7f; if (header.PayloadLength == 126) { headerLength = 4; if (headerBytesRead < headerLength) { continue; } len = (ulong)(headerBuffer[2] * 0x100) + headerBuffer[3]; } else if (len == 127) { headerLength = 10; if (headerBytesRead < headerLength) { continue; } len = (ulong)(headerBuffer[6] * 0x1000000) + (ulong)(headerBuffer[7] * 0x10000) + (ulong)(headerBuffer[8] * 0x100) + (ulong)headerBuffer[9]; } header.PayloadLength = len; headerReadState = 3; // length received } if (header.Mask && headerReadState >= 3) // read masking-key { if (headerReadState == 3) { headerLength += 4; headerReadState = 4; } if (headerBytesRead < headerLength) { continue; } header.MaskingKey[0] = headerBuffer[headerLength - 4]; header.MaskingKey[1] = headerBuffer[headerLength - 3]; header.MaskingKey[2] = headerBuffer[headerLength - 2]; header.MaskingKey[3] = headerBuffer[headerLength - 1]; } // received header Console.WriteLine("fin:{0} opcode:{1} mask:{2} len:{3} controlframe:{4}", header.Fin, header.OpCode, header.Mask, header.PayloadLength, header.IsControlFrame); if (header.IsControlFrame) { // See RFC 6455 section 5.5 // can safely cast to int because control frames have max payload length of 125 int controlFrameLength = (int)header.PayloadLength; var controlFrameBuffer = new byte[controlFrameLength]; var controlFrameBytesRead = 0; while (controlFrameBytesRead < controlFrameLength) { controlFrameBytesRead += await stream.ReadAsync(controlFrameBuffer, controlFrameBytesRead, controlFrameLength - controlFrameBytesRead, cancel); } header.UnmaskData(new ArraySegment <byte>(controlFrameBuffer, 0, controlFrameLength)); // TODO: read data (ping/pong-content) switch (header.OpCode) { case MessageType.Close: if (controlFrameLength >= 2) { this.Environment[OwinConstants.WebSocket.ClientCloseStatus] = (controlFrameBuffer[0] * 0x100) + controlFrameBuffer[1]; if (controlFrameLength > 2) { this.Environment[OwinConstants.WebSocket.ClientCloseDescription] = Encoding.UTF8.GetString(controlFrameBuffer, 2, controlFrameLength - 2); } } return(new WebSocketReceiveTuple((int)MessageType.Close, true, 0)); case MessageType.Ping: case MessageType.Pong: throw new NotImplementedException(); // TODO } headerReadState = 0; // receive next header } else { currentHeader = header; break; } } } // now receive payload int maxBytes; if (currentHeader.PayloadLength > int.MaxValue) { maxBytes = int.MaxValue; } else { maxBytes = (int)currentHeader.PayloadLength; } if (buffer.Count < maxBytes) { maxBytes = buffer.Count; } int bytes = await stream.ReadAsync(buffer.Array, buffer.Offset, maxBytes, cancel); // unmask it if (currentHeader.Mask) { // TODO: handle unaligned offset? currentHeader.UnmaskData(buffer); } currentHeader.PayloadReceived += (ulong)bytes; bool endOfFrame = currentHeader.PayloadReceived >= currentHeader.PayloadLength; bool endOfMessage = endOfFrame && currentHeader.Fin; int messageType = (int)currentHeader.OpCode; if (endOfFrame) { currentHeader = null; // forget last header } return(new WebSocketReceiveTuple(messageType, endOfMessage, bytes)); }
// Receive frames, unmask them. // Should handle pings/pongs internally. // Should parse out Close frames. public async Task<WebSocketReceiveTuple> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancel) { if (currentHeader == null) { var header = new WebSocketHeader(); byte headerReadState = 1;// skip initialization byte[] headerBuffer = new byte[14]; int headerBytesRead = 0; int headerLength = 2; while (true) { if (headerReadState == 0) // re-initialize { // create buffer big enough to hold the complete header headerBuffer = new byte[14]; headerBytesRead = 0; headerLength = 2; headerReadState = 1; } var count = await stream.ReadAsync(headerBuffer, headerBytesRead, headerLength - headerBytesRead, cancel); headerBytesRead += count; if (headerBytesRead < headerLength) { continue; } if (headerReadState == 1) // read first 2 bytes { header.Fin = ((headerBuffer[0] >> 7) & 0x01) == 1; header.OpCode = (MessageType)((headerBuffer[0] >> 0) & 0x0f); header.Mask = ((headerBuffer[1] >> 7) & 0x01) == 1; headerReadState = 2; } if (headerReadState == 2) // read length { ulong len = (ulong)(headerBuffer[1] >> 0) & 0x7f; if (header.PayloadLength == 126) { headerLength = 4; if (headerBytesRead < headerLength) { continue; } len = (ulong)(headerBuffer[2] * 0x100) + headerBuffer[3]; } else if (len == 127) { headerLength = 10; if (headerBytesRead < headerLength) { continue; } len = (ulong)(headerBuffer[6] * 0x1000000) + (ulong)(headerBuffer[7] * 0x10000) + (ulong)(headerBuffer[8] * 0x100) + (ulong)headerBuffer[9]; } header.PayloadLength = len; headerReadState = 3; // length received } if (header.Mask && headerReadState >= 3) // read masking-key { if (headerReadState == 3) { headerLength += 4; headerReadState = 4; } if (headerBytesRead < headerLength) { continue; } header.MaskingKey[0] = headerBuffer[headerLength - 4]; header.MaskingKey[1] = headerBuffer[headerLength - 3]; header.MaskingKey[2] = headerBuffer[headerLength - 2]; header.MaskingKey[3] = headerBuffer[headerLength - 1]; } // received header Console.WriteLine("fin:{0} opcode:{1} mask:{2} len:{3} controlframe:{4}", header.Fin, header.OpCode, header.Mask, header.PayloadLength, header.IsControlFrame); if (header.IsControlFrame) { // See RFC 6455 section 5.5 // can safely cast to int because control frames have max payload length of 125 int controlFrameLength = (int)header.PayloadLength; var controlFrameBuffer = new byte[controlFrameLength]; var controlFrameBytesRead = 0; while (controlFrameBytesRead < controlFrameLength) { controlFrameBytesRead += await stream.ReadAsync(controlFrameBuffer, controlFrameBytesRead, controlFrameLength - controlFrameBytesRead, cancel); } header.UnmaskData(new ArraySegment<byte>(controlFrameBuffer, 0, controlFrameLength)); // TODO: read data (ping/pong-content) switch (header.OpCode) { case MessageType.Close: if (controlFrameLength >= 2) { this.Environment[OwinConstants.WebSocket.ClientCloseStatus] = (controlFrameBuffer[0] * 0x100) + controlFrameBuffer[1]; if (controlFrameLength > 2) { this.Environment[OwinConstants.WebSocket.ClientCloseDescription] = Encoding.UTF8.GetString(controlFrameBuffer, 2, controlFrameLength - 2); } } return new WebSocketReceiveTuple((int)MessageType.Close, true, 0); case MessageType.Ping: case MessageType.Pong: throw new NotImplementedException(); // TODO } headerReadState = 0; // receive next header } else { currentHeader = header; break; } } } // now receive payload int maxBytes; if (currentHeader.PayloadLength > int.MaxValue) maxBytes = int.MaxValue; else maxBytes = (int)currentHeader.PayloadLength; if (buffer.Count < maxBytes) maxBytes = buffer.Count; int bytes = await stream.ReadAsync(buffer.Array, buffer.Offset, maxBytes, cancel); // unmask it if (currentHeader.Mask) { // TODO: handle unaligned offset? currentHeader.UnmaskData(buffer); } currentHeader.PayloadReceived += (ulong)bytes; bool endOfFrame = currentHeader.PayloadReceived >= currentHeader.PayloadLength; bool endOfMessage = endOfFrame && currentHeader.Fin; int messageType = (int)currentHeader.OpCode; if (endOfFrame) currentHeader = null; // forget last header return new WebSocketReceiveTuple(messageType, endOfMessage, bytes); }