private void ServersManager_BeforeSend(ServersManager <Connection> s, Connection c, ServerAsyncEventArgs e) { if (c != null && c.Mode == Connection.Modes.WebSocket) { //c.BeforeSend(e); var header = new WebSocketHeader() { Fin = true, Opcode = websocketOpcode.HasValue ? websocketOpcode.Value : c.WebSocketHeader.Opcode, PayloadLength = e.Count, }; int headerLength = header.GetHeaderLength(); if (e.OffsetOffset < headerLength) { throw new InvalidProgramException(@"TransportLayer.ServersManager_BeforeSend no reserved space for WebSocket header"); } e.OffsetOffset -= headerLength; e.Count += headerLength; header.GenerateHeader(e.OutgoingData); } }
public void MaskingWorksAcrossMultipleParseCalls() { var maskingKey = WebSocketHeader.GenerateMaskingKey(); var payloadString = String.Join(String.Empty, Enumerable.Repeat("This is a test payload.", 250)); var sequence = SegmentArray(GenerateMaskedPayload(payloadString, maskingKey), 4); var encoder = new WebSocketPayloadReader(new WebSocketHeader(true, WebSocketOpcode.Binary, true, (ulong)sequence.Length, maskingKey)); var resultData = new byte[0]; SequencePosition pos = default; foreach (var memory in sequence) { var localSequence = new ReadOnlySequence <byte>(memory); encoder.TryParseMessage(in localSequence, ref pos, ref pos, out var outputSequence); var toAppend = new byte[resultData.Length + outputSequence.Length]; Array.Copy(resultData, 0, toAppend, 0, resultData.Length); Array.Copy(outputSequence.ToArray(), 0, toAppend, resultData.Length, outputSequence.Length); resultData = toAppend; } Assert.Equal(payloadString, Encoding.UTF8.GetString(resultData)); }
private static byte[] PrepareForWebsocket(byte[] message, Opcodes opcode) { var wsHeader = new WebSocketHeader() { Fin = true, Opcode = opcode, PayloadLength = message.Length, Mask = true, MaskingKey0 = 0x12, MaskingKey1 = 0x34, MaskingKey2 = 0x56, MaskingKey3 = 0x78, }; var extra = new byte[wsHeader.GetHeaderLength()]; wsHeader.GenerateHeader(new ArraySegment <byte>(extra)); if (wsHeader.Mask) { wsHeader.MaskData(message, 0, message.Length); } return(extra); }
public virtual void RemoveHeader(WebSocketHeader header) { if (headers.ContainsKey(header)) { headers.Remove(header); } }
public virtual string GetHeader(WebSocketHeader header) { if (headers.ContainsKey(header)) { return(headers[header]); } return(null); }
public static void Validate(this WebSocketHeader header) { if (header.mask == false) { throw new ArgumentException("request packet must be masked"); } if (header.opcode > (int)OpCode.Pong) { throw new ArgumentException("unknown opcode"); } }
public virtual void SetHeader(WebSocketHeader header, string value) { if (headers.ContainsKey(header)) { headers[header] = value; } else { headers.Add(header, value); } }
private static void Unmask(byte[] message) { var wsHeader = new WebSocketHeader() { Mask = true, MaskingKey0 = 0x12, MaskingKey1 = 0x34, MaskingKey2 = 0x56, MaskingKey3 = 0x78, }; wsHeader.MaskData(message, 0, message.Length); }
public void HugeSequenceWorks() { var maskingKey = WebSocketHeader.GenerateMaskingKey(); var payloadString = String.Join(String.Empty, Enumerable.Repeat("This is a test payload.", 25000)); var sequence = SegmentArray(GenerateMaskedPayload(payloadString, maskingKey), 4); SequencePosition pos = default; var encoder = new WebSocketPayloadReader(new WebSocketHeader(true, WebSocketOpcode.Binary, true, (ulong)sequence.Length, maskingKey)); encoder.TryParseMessage(in sequence, ref pos, ref pos, out var outputSequence); Assert.Equal(payloadString, Encoding.UTF8.GetString(outputSequence.ToArray())); }
public void SingleSegmentSequenceWorks() { var maskingKey = WebSocketHeader.GenerateMaskingKey(); var payloadString = "This is a test payload."; var payload = GenerateMaskedPayload(payloadString, maskingKey); var encoder = new WebSocketPayloadReader(new WebSocketHeader(true, WebSocketOpcode.Binary, true, (ulong)payload.Length, maskingKey)); var sequence = new ReadOnlySequence <byte>(payload); SequencePosition pos = default; encoder.TryParseMessage(in sequence, ref pos, ref pos, out var outputSequence); Assert.Equal(payloadString, Encoding.UTF8.GetString(outputSequence.First.ToArray())); }
private void SendWebsocket(WebSocketHeader header, ArraySegment <byte> content) { int headerLength = header.GetHeaderLength(); var r = EventArgsManager.Get(); r.CopyAddressesFrom(connection); r.Count = headerLength + content.Count; r.AllocateBuffer(); header.GenerateHeader(r.OutgoingData); Buffer.BlockCopy(content.Array, content.Offset, r.Buffer, r.Offset + headerLength, content.Count); SendAsyncSip(r); }
public static WebSocketHeader ConverterToHeader(string hString) { WebSocketHeader header = WebSocketHeader.Unknown; switch (hString) { case "Connection": header = WebSocketHeader.Connection; break; case "Cookie": header = WebSocketHeader.Cookie; break; case "Host": header = WebSocketHeader.Host; break; case "Sec-WebSocket-Key": header = WebSocketHeader.SecWebSocketKey; break; case "Sec-WebSocket-Origin": header = WebSocketHeader.SecWebSocketOrigin; break; case "Sec-WebSocket-Version": header = WebSocketHeader.SecWebSocketVersion; break; case "Sec-WebSocket-Accept": header = WebSocketHeader.SecWebSocketAccept; break; case "Sec-WebSocket-Protocol": header = WebSocketHeader.SecWebSocketProtocol; break; case "Upgrade": header = WebSocketHeader.Upgrade; break; case "Url": header = WebSocketHeader.Url; break; } return(header); }
public bool Parse(string header) { Regex regex = new Regex("\r\n"); string[] headers = regex.Split(header); if (headers == null || headers.Length == 0) { return(false); } string curHead = ""; for (int i = 0; i < headers.Length; i++) { curHead = headers[i]; if (i == 0) { string[] rs = curHead.Split(' '); if (rs == null || rs.Length == 0) { return(false); } SetHeader(WebSocketHeader.Method, rs[0]); if (rs.Length > 1) { SetHeader(WebSocketHeader.Url, rs[1]); } if (rs.Length > 2) { SetHeader(WebSocketHeader.HttpVersion, rs[2]); } continue; } string[] hf = curHead.Split(':'); if (hf.Length == 2) { WebSocketHeader h = WebSocketHeaderConverter.ConverterToHeader(hf[0]); if (h != WebSocketHeader.Unknown) { SetHeader(h, hf[1].TrimStart(' ')); } } } logger.Info("接收到的WebSocket请求:\r\n{0}", header); return(true); }
public void MultiSegmentWithZeroLengthSegmentsSequenceWorks() { var maskingKey = WebSocketHeader.GenerateMaskingKey(); var payloadString = "This is a test payload."; var masked = GenerateMaskedPayload(payloadString, maskingKey); var left = new TestSequenceSegment(masked.AsSpan(0..10).ToArray()); var middle = left.AddSegment(new byte[0]); var right = middle.AddSegment(masked.AsSpan(10..masked.Length).ToArray()); var sequence = new ReadOnlySequence <byte>(left, 0, right, right.Memory.Length); SequencePosition pos = default; var encoder = new WebSocketPayloadReader(new WebSocketHeader(true, WebSocketOpcode.Binary, true, (ulong)sequence.Length, maskingKey)); encoder.TryParseMessage(in sequence, ref pos, ref pos, out var outputSequence); Assert.Equal(payloadString, Encoding.UTF8.GetString(outputSequence.ToArray())); }
public void SequenceLongerThanPayloadLengthWorks() { var maskingKey = WebSocketHeader.GenerateMaskingKey(); var payloadString = "This is a test payload."; var payload = GenerateMaskedPayload(payloadString, maskingKey); var encoder = new WebSocketPayloadReader(new WebSocketHeader(true, WebSocketOpcode.Binary, true, (ulong)payload.Length, maskingKey)); var first = new TestSequenceSegment(payload); var last = first.AddSegment(new byte[64]); var sequence = new ReadOnlySequence <byte>(first, 0, last, last.Memory.Length); SequencePosition pos = default; encoder.TryParseMessage(in sequence, ref pos, ref pos, out var outputSequence); Assert.Equal(pos, sequence.GetPosition(payload.Length)); Assert.Equal(payloadString, Encoding.UTF8.GetString(outputSequence.First.ToArray())); }
public async Task ShortLengthMaskedWorksViaManagedWebSocket() { var options = new PipeOptions(useSynchronizationContext: false); var duplexPipe = DuplexPipe.CreateConnectionPair(options, options); var webSocket = WebSocket.CreateFromStream(new DuplexPipeStream(duplexPipe.Application.Input, duplexPipe.Application.Output), true, null, TimeSpan.FromSeconds(30)); var writer = new WebSocketFrameWriter(); var payloadString = String.Join(String.Empty, Enumerable.Repeat("This is a test payload.", 25)); var payloadBuffer = new ReadOnlySequence <byte>(Encoding.UTF8.GetBytes(payloadString)); var header = WebSocketHeader.CreateMasked(true, WebSocketOpcode.Binary, (ulong)payloadBuffer.Length); var protocolWriter = new ProtocolWriter(duplexPipe.Transport.Output); await protocolWriter.WriteAsync(writer, new WebSocketWriteFrame(header, payloadBuffer)); var receiveBuffer = new Memory <byte>(new byte[payloadBuffer.Length]); await webSocket.ReceiveAsync(receiveBuffer, default); Assert.Equal(payloadString, Encoding.UTF8.GetString(receiveBuffer.ToArray())); }
async Task SendFrame(FrameType type, byte[] data, int offset, int length) { using (var l = await _sendLock.LockAsync()) { var header = new WebSocketHeader(); int headerLength; if (data.Length <= 125) { headerLength = WebsocketInitialHeaderLength; header.Length8 = (byte)length; } else if (length <= 0xffff) { headerLength = WebsocketLen16Length; header.Length8 = WebsocketLen16Code; header.Length16 = (ushort)IPAddress.HostToNetworkOrder((short)(ushort)length); } else { headerLength = WebsocketLen64Length; header.Length8 = WebsocketLen64Code; header.Length64 = (ulong)IPAddress.HostToNetworkOrder((long)length); } var endOfMessage = true; header.Mask = (byte)(((endOfMessage ? 1u : 0u) << 7) | ((byte)(type) & 0xf)); unsafe { Marshal.Copy(new IntPtr(&header), _sendHeaderBuffer, 0, headerLength); } await _stream.WriteAsync(_sendHeaderBuffer, 0, headerLength); await _stream.WriteAsync(data, offset, length); } }
// 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); }
public void SequenceLessThanMinimumPlusMaskReturnsFalse() { var reader = new WebSocketFrameReader(); var headerBytes = GetHeaderBytes(WebSocketHeader.CreateMasked(true, default, 64));
// 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)); }
public static string ConverterToString(WebSocketHeader header) { string hString = ""; switch (header) { case WebSocketHeader.Connection: hString = "Connection"; break; case WebSocketHeader.Cookie: hString = "Cookie"; break; case WebSocketHeader.Host: hString = "Host"; break; case WebSocketHeader.HttpCode: hString = "HttpCode"; break; case WebSocketHeader.HttpVersion: hString = "HttpVersion"; break; case WebSocketHeader.Method: hString = "Method"; break; case WebSocketHeader.SecWebSocketKey: hString = "Sec-WebSocket-Key"; break; case WebSocketHeader.SecWebSocketOrigin: hString = "Sec-WebSocket-Origin"; break; case WebSocketHeader.SecWebSocketVersion: hString = "Sec-WebSocket-Version"; break; case WebSocketHeader.SecWebSocketAccept: hString = "Sec-WebSocket-Accept"; break; case WebSocketHeader.SecWebSocketProtocol: hString = "Sec-WebSocket-Protocol"; break; case WebSocketHeader.Upgrade: hString = "Upgrade"; break; case WebSocketHeader.Url: hString = "Url"; break; case WebSocketHeader.SwitchingProtocols: hString = "SwitchingProtocols"; break; } return(hString); }