private async Task <StreamReadInfo> GetStreamReadInfo(WebSocketFrameHeader header, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); /* Extended Payload Length */ var size = header.PayloadLength < 126 ? 0 : header.PayloadLength == 126 ? 2 : 8; var extPayloadLen = size > 0 ? await _innerStream.ReadBytes(size).ConfigureAwait(false) : new byte[0]; if (size > 0 && extPayloadLen.Length != size) { throw new WebSocketException("The 'Extended Payload Length' of a frame cannot be read from the data source."); } /* Masking Key */ var masked = header.Mask == Mask.Mask; var maskingKey = masked ? await _innerStream.ReadBytes(4).ConfigureAwait(false) : new byte[0]; if (masked && maskingKey.Length != 4) { throw new WebSocketException("The 'Masking Key' of a frame cannot be read from the data source."); } /* Payload Data */ var len = header.PayloadLength < 126 ? header.PayloadLength : header.PayloadLength == 126 ? extPayloadLen.ToUInt16(ByteOrder.Big) : extPayloadLen.ToUInt64(ByteOrder.Big); return(new StreamReadInfo(header.Fin == Fin.Final, len, maskingKey)); }
private async Task <WebSocketFrameHeader> ReadHeader(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); byte[] header; try { header = await _innerStream.ReadBytes(2).ConfigureAwait(false); } catch (IOException) { return(null); } if (header.Length == 0) { return(null); } if (header.Length != 2) { throw new WebSocketException("The header part of a frame cannot be read from the data source."); } var frameHeader = new WebSocketFrameHeader(header); var validation = WebSocketFrameHeader.Validate(frameHeader); if (validation != null) { throw new WebSocketException(CloseStatusCode.ProtocolError, validation); } return(frameHeader); }
private WebSocketMessage CreateMessage(WebSocketFrameHeader header, StreamReadInfo readInfo, SemaphoreSlim waitHandle) { switch (header.Opcode) { case Opcode.Cont: throw new WebSocketException(CloseStatusCode.InconsistentData, "Did not expect continuation frame."); default: case Opcode.Close: case Opcode.Text: case Opcode.Binary: return(new FragmentedMessage(header.Opcode, _innerStream, readInfo, GetStreamReadInfo, waitHandle, _fragmentLength)); } }
public static string Validate(WebSocketFrameHeader header) { // Check if valid header var err = IsControl(header.Opcode) && header.PayloadLength > 125 ? "A control frame has a payload data which is greater than the allowable max size." : IsControl(header.Opcode) && header.Fin == Fin.More ? "A control frame is fragmented." : !IsData(header.Opcode) && header.Rsv1 == Rsv.On ? "A non data frame (" + header.Opcode + ") is compressed." : null; if (!string.IsNullOrWhiteSpace(err)) { Trace.TraceError(err); } return(err); }