private async void Consume(IReadableChannel channel) { while (true) { var result = await channel.ReadAsync(); var buffer = result.Buffer; try { if (buffer.IsEmpty && result.IsCompleted) { break; } await WriteAsync(buffer); } finally { channel.Advance(buffer.End); } } channel.Complete(); }
public static async Task CopyToAsync(this IReadableChannel input, Stream stream, int bufferSize, CancellationToken cancellationToken) { // TODO: Use bufferSize argument while (!cancellationToken.IsCancellationRequested) { var inputBuffer = await input.ReadAsync(); try { if (inputBuffer.IsEmpty && input.Reading.IsCompleted) { return; } foreach (var memory in inputBuffer) { ArraySegment <byte> buffer; if (!memory.TryGetArray(out buffer)) { // Fall back to copies if this was native memory and we were unable to get // something we could write buffer = new ArraySegment <byte>(memory.Span.CreateArray()); } await stream.WriteAsync(buffer.Array, buffer.Offset, buffer.Count); } } finally { input.Advance(inputBuffer.End); } } }
public static ValueTask <int> ReadAsync(this IReadableChannel input, Span <byte> destination) { while (true) { var awaiter = input.ReadAsync(); if (!awaiter.IsCompleted) { break; } var result = awaiter.GetResult(); var inputBuffer = result.Buffer; var fin = result.IsCompleted; var sliced = inputBuffer.Slice(0, destination.Length); sliced.CopyTo(destination); int actual = sliced.Length; input.Advance(sliced.End); if (actual != 0) { return(new ValueTask <int>(actual)); } else if (fin) { return(new ValueTask <int>(0)); } } return(new ValueTask <int>(input.ReadAsyncAwaited(destination))); }
private static async Task <int> ReadAsyncAwaited(this IReadableChannel input, Span <byte> destination) { while (true) { var result = await input.ReadAsync(); var inputBuffer = result.Buffer; var fin = result.IsCompleted; var sliced = inputBuffer.Slice(0, destination.Length); sliced.CopyTo(destination); int actual = sliced.Length; input.Advance(sliced.End); if (actual != 0) { return(actual); } else if (fin) { return(0); } } }
private static async Task CopyCompletedAsync(IReadableChannel input, IWritableChannel channel) { var inputBuffer = await input.ReadAsync(); while (true) { try { if (inputBuffer.IsEmpty && input.Reading.IsCompleted) { return; } var buffer = channel.Alloc(); buffer.Append(ref inputBuffer); await buffer.FlushAsync(); } finally { input.Advance(inputBuffer.End); } var awaiter = input.ReadAsync(); if (!awaiter.IsCompleted) { // No more data break; } inputBuffer = await awaiter; } }
public static async Task CopyToAsync(this IReadableChannel input, IWritableChannel output) { while (true) { var result = await input.ReadAsync(); var inputBuffer = result.Buffer; var fin = result.IsCompleted; try { if (inputBuffer.IsEmpty && fin) { return; } var buffer = output.Alloc(); buffer.Append(inputBuffer); await buffer.FlushAsync(); } finally { input.Advance(inputBuffer.End); } } }
private static async Task <ChannelReadResult> ReadAtLeastSlowAsync(ReadableChannelAwaitable awaitable, IReadableChannel input, int minimumRequiredBytes, CancellationToken cancellationToken) { var result = await awaitable; while (!result.IsCompleted && result.Buffer.Length < minimumRequiredBytes) { cancellationToken.ThrowIfCancellationRequested(); input.Advance( consumed: result.Buffer.Start, examined: result.Buffer.End); result = await input.ReadAsync(/* cancelToken */); } return(result); }
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context) { int remaining = ContentLength; while (remaining > 0) { var result = await _output.ReadAsync(); var inputBuffer = result.Buffer; var fin = result.IsCompleted; var consumed = inputBuffer.Start; try { if (inputBuffer.IsEmpty && fin) { return; } var data = inputBuffer.Slice(0, remaining); foreach (var memory in data) { ArraySegment <byte> buffer; unsafe { if (!memory.TryGetArray(out buffer)) { // Fall back to copies if this was native memory and we were unable to get // something we could write buffer = new ArraySegment <byte>(memory.Span.ToArray()); } } await stream.WriteAsync(buffer.Array, buffer.Offset, buffer.Count); } consumed = data.End; remaining -= data.Length; } finally { _output.Advance(consumed); } } }
public static async Task <ReadableBuffer> ReadToEndAsync(this IReadableChannel input) { while (true) { // Wait for more data var result = await input.ReadAsync(); if (result.IsCompleted) { // Read all the data, return it return(result.Buffer); } // Don't advance the buffer so remains in buffer input.Advance(result.Buffer.Start, result.Buffer.End); } }
public async Task Execute(IReadableChannel input, IWritableChannel output) { while (true) { var inputBuffer = await input.ReadAsync(); if (inputBuffer.IsEmpty && input.Reading.IsCompleted) { break; } var writerBuffer = output.Alloc(2048); var memory = inputBuffer.First; if (memory.Length > 0) { unsafe { _inflater.SetInput((IntPtr)memory.UnsafePointer, memory.Length); int written = _inflater.Inflate((IntPtr)memory.UnsafePointer, memory.Length); writerBuffer.Advance(written); var consumed = memory.Length - _inflater.AvailableInput; inputBuffer = inputBuffer.Slice(0, consumed); } } input.Advance(inputBuffer.End); await writerBuffer.FlushAsync(); } input.Complete(); output.Complete(); _inflater.Dispose(); }
// TODO: Pull this up to Channels. We should be able to do it there without allocating a Task<T> in any case (rather than here where we can avoid allocation // only if the buffer is already ready and has enough data) public static ValueTask <ChannelReadResult> ReadAtLeastAsync(this IReadableChannel input, int minimumRequiredBytes, CancellationToken cancellationToken) { var awaiter = input.ReadAsync(/* cancellationToken */); // Short-cut path! if (awaiter.IsCompleted) { // We have a buffer, is it big enough? var result = awaiter.GetResult(); if (result.IsCompleted || result.Buffer.Length >= minimumRequiredBytes) { return(new ValueTask <ChannelReadResult>(result)); } // Buffer wasn't big enough, mark it as examined and continue to the "slow" path below input.Advance( consumed: result.Buffer.Start, examined: result.Buffer.End); } return(new ValueTask <ChannelReadResult>(ReadAtLeastSlowAsync(awaiter, input, minimumRequiredBytes, cancellationToken))); }
public static async Task CopyToAsync(this IReadableChannel input, Stream stream, int bufferSize, CancellationToken cancellationToken) { // TODO: Use bufferSize argument while (!cancellationToken.IsCancellationRequested) { var result = await input.ReadAsync(); var inputBuffer = result.Buffer; try { if (inputBuffer.IsEmpty && result.IsCompleted) { return; } await inputBuffer.CopyToAsync(stream); } finally { input.Advance(inputBuffer.End); } } }
public async Task ProcessAllRequests() { Reset(); while (true) { var buffer = await _input.ReadAsync(); try { if (buffer.IsEmpty && _input.Reading.IsCompleted) { // We're done with this connection return; } Console.WriteLine($"Read: {buffer.Length} bytes"); Console.WriteLine(BitConverter.ToString(buffer.ToArray())); Console.WriteLine(buffer.GetAsciiString()); var result = _parser.ParseRequest(ref buffer); Console.WriteLine($"Result: {result}"); switch (result) { case HttpRequestParser.ParseResult.Incomplete: if (_input.Reading.IsCompleted) { // Didn't get the whole request and the connection ended throw new EndOfStreamException(); } // Need more data continue; case HttpRequestParser.ParseResult.Complete: // Done break; case HttpRequestParser.ParseResult.BadRequest: // TODO: Don't throw here; throw new Exception(); default: break; } } catch (Exception) { StatusCode = 400; await EndResponse(); return; } finally { _input.Advance(buffer.Start, buffer.End); } var context = _application.CreateContext(this); try { if (!_isHttp2 && RequestHeaders.ContainsKey("Upgrade") && TryUpgradeToHttp2()) { _outputFormatter.Write(_http2SwitchBytes); _isHttp2 = true; /* The first HTTP/2 frame sent by the server MUST be a server connection preface (Section 3.5) consisting of a SETTINGS frame (Section 6.5). */ _outputFormatter.Write(_emptySettingsFrame); await _outputFormatter.FlushAsync(); } await _application.ProcessRequestAsync(context); } catch (Exception ex) { StatusCode = 500; _application.DisposeContext(context, ex); } finally { await EndResponse(); } if (!KeepAlive) { break; } Reset(); } }
internal static async Task <HttpRequest> ParseHttpRequest(IReadableChannel _input) { ReadableBuffer Method = default(ReadableBuffer), Path = default(ReadableBuffer), HttpVersion = default(ReadableBuffer); Dictionary <string, ReadableBuffer> Headers = new Dictionary <string, ReadableBuffer>(); try { ParsingState _state = ParsingState.StartLine; bool needMoreData = true; while (needMoreData) { var buffer = await _input.ReadAsync(); var consumed = buffer.Start; needMoreData = true; try { if (buffer.IsEmpty && _input.Reading.IsCompleted) { throw new EndOfStreamException(); } if (_state == ParsingState.StartLine) { // Find \n ReadCursor delim; ReadableBuffer startLine; if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out startLine, out delim)) { continue; } // Move the buffer to the rest buffer = buffer.Slice(delim).Slice(2); ReadableBuffer method; if (!startLine.TrySliceTo((byte)' ', out method, out delim)) { throw new Exception(); } Method = method.Preserve(); // Skip ' ' startLine = startLine.Slice(delim).Slice(1); ReadableBuffer path; if (!startLine.TrySliceTo((byte)' ', out path, out delim)) { throw new Exception(); } Path = path.Preserve(); // Skip ' ' startLine = startLine.Slice(delim).Slice(1); var httpVersion = startLine; if (httpVersion.IsEmpty) { throw new Exception(); } HttpVersion = httpVersion.Preserve(); _state = ParsingState.Headers; consumed = buffer.Start; } // Parse headers // key: value\r\n while (!buffer.IsEmpty) { var ch = buffer.Peek(); if (ch == -1) { break; } if (ch == '\r') { // Check for final CRLF. buffer = buffer.Slice(1); ch = buffer.Peek(); buffer = buffer.Slice(1); if (ch == -1) { break; } else if (ch == '\n') { consumed = buffer.Start; needMoreData = false; break; } // Headers don't end in CRLF line. throw new Exception(); } var headerName = default(ReadableBuffer); var headerValue = default(ReadableBuffer); // End of the header // \n ReadCursor delim; ReadableBuffer headerPair; if (!buffer.TrySliceTo((byte)'\n', out headerPair, out delim)) { break; } buffer = buffer.Slice(delim).Slice(1); // : if (!headerPair.TrySliceTo((byte)':', out headerName, out delim)) { throw new Exception(); } headerName = headerName.TrimStart(); headerPair = headerPair.Slice(delim).Slice(1); // \r if (!headerPair.TrySliceTo((byte)'\r', out headerValue, out delim)) { // Bad request throw new Exception(); } headerValue = headerValue.TrimStart(); Headers[ToHeaderKey(ref headerName)] = headerValue.Preserve(); // Move the consumed consumed = buffer.Start; } } finally { _input.Advance(consumed); } } var result = new HttpRequest(Method, Path, HttpVersion, Headers); Method = Path = HttpVersion = default(ReadableBuffer); Headers = null; return(result); } finally { Method.Dispose(); Path.Dispose(); HttpVersion.Dispose(); if (Headers != null) { foreach (var pair in Headers) { pair.Value.Dispose(); } } } }
public async Task Execute(IReadableChannel input, IWritableChannel output) { while (true) { var result = await input.ReadAsync(); var inputBuffer = result.Buffer; if (inputBuffer.IsEmpty) { if (result.IsCompleted) { break; } input.Advance(inputBuffer.End); continue; } var writerBuffer = output.Alloc(); var memory = inputBuffer.First; unsafe { // TODO: Pin pointer if not pinned void *inPointer; if (memory.TryGetPointer(out inPointer)) { _deflater.SetInput((IntPtr)inPointer, memory.Length); } else { throw new InvalidOperationException("Pointer needs to be pinned"); } } while (!_deflater.NeedsInput()) { unsafe { void *outPointer; writerBuffer.Ensure(); if (writerBuffer.Memory.TryGetPointer(out outPointer)) { int written = _deflater.ReadDeflateOutput((IntPtr)outPointer, writerBuffer.Memory.Length); writerBuffer.Advance(written); } else { throw new InvalidOperationException("Pointer needs to be pinned"); } } } var consumed = memory.Length - _deflater.AvailableInput; inputBuffer = inputBuffer.Slice(0, consumed); input.Advance(inputBuffer.End); await writerBuffer.FlushAsync(); } bool flushed = false; do { // Need to do more stuff here var writerBuffer = output.Alloc(); unsafe { void *pointer; writerBuffer.Ensure(); var memory = writerBuffer.Memory; if (memory.TryGetPointer(out pointer)) { int compressedBytes; flushed = _deflater.Flush((IntPtr)pointer, memory.Length, out compressedBytes); writerBuffer.Advance(compressedBytes); } else { throw new InvalidOperationException("Pointer needs to be pinned"); } } await writerBuffer.FlushAsync(); }while (flushed); bool finished = false; do { // Need to do more stuff here var writerBuffer = output.Alloc(); unsafe { void *pointer; writerBuffer.Ensure(); var memory = writerBuffer.Memory; if (memory.TryGetPointer(out pointer)) { int compressedBytes; finished = _deflater.Finish((IntPtr)pointer, memory.Length, out compressedBytes); writerBuffer.Advance(compressedBytes); } } await writerBuffer.FlushAsync(); }while (!finished); input.Complete(); output.Complete(); _deflater.Dispose(); }
public async Task Execute(IReadableChannel input, IWritableChannel output) { while (true) { var result = await input.ReadAsync(); var inputBuffer = result.Buffer; if (inputBuffer.IsEmpty) { if (result.IsCompleted) { break; } input.Advance(inputBuffer.End); continue; } var writerBuffer = output.Alloc(); var memory = inputBuffer.First; if (memory.Length > 0) { unsafe { void *pointer; if (memory.TryGetPointer(out pointer)) { _inflater.SetInput((IntPtr)pointer, memory.Length); void *writePointer; writerBuffer.Ensure(); if (writerBuffer.Memory.TryGetPointer(out writePointer)) { int written = _inflater.Inflate((IntPtr)writePointer, writerBuffer.Memory.Length); writerBuffer.Advance(written); } else { throw new InvalidOperationException("Pointer needs to be pinned"); } } else { throw new InvalidOperationException("Pointer needs to be pinned"); } var consumed = memory.Length - _inflater.AvailableInput; inputBuffer = inputBuffer.Slice(0, consumed); } } input.Advance(inputBuffer.End); await writerBuffer.FlushAsync(); } input.Complete(); output.Complete(); _inflater.Dispose(); }
public async Task ProcessAllRequests() { Reset(); while (true) { var result = await _input.ReadAsync(); var buffer = result.Buffer; try { if (buffer.IsEmpty && result.IsCompleted) { // We're done with this connection return; } var parserResult = _parser.ParseRequest(ref buffer); switch (parserResult) { case HttpRequestParser.ParseResult.Incomplete: if (result.IsCompleted) { // Didn't get the whole request and the connection ended throw new EndOfStreamException(); } // Need more data continue; case HttpRequestParser.ParseResult.Complete: // Done break; case HttpRequestParser.ParseResult.BadRequest: // TODO: Don't throw here; throw new Exception(); default: break; } } catch (Exception) { StatusCode = 400; await EndResponse(); return; } finally { _input.Advance(buffer.Start, buffer.End); } var context = _application.CreateContext(this); try { await _application.ProcessRequestAsync(context); } catch (Exception ex) { StatusCode = 500; _application.DisposeContext(context, ex); } finally { await EndResponse(); } if (!KeepAlive) { break; } Reset(); } }
public static void Advance(this IReadableChannel input, ReadCursor cursor) { input.Advance(cursor, cursor); }
public async Task Execute(IReadableChannel input, IWritableChannel output) { while (true) { var inputBuffer = await input.ReadAsync(); if (inputBuffer.IsEmpty && input.Reading.IsCompleted) { break; } var writerBuffer = output.Alloc(2048); var memory = inputBuffer.First; unsafe { _deflater.SetInput((IntPtr)memory.UnsafePointer, memory.Length); } while (!_deflater.NeedsInput()) { unsafe { int written = _deflater.ReadDeflateOutput((IntPtr)writerBuffer.Memory.UnsafePointer, writerBuffer.Memory.Length); writerBuffer.Advance(written); } } var consumed = memory.Length - _deflater.AvailableInput; inputBuffer = inputBuffer.Slice(0, consumed); input.Advance(inputBuffer.End); await writerBuffer.FlushAsync(); } bool flushed; do { // Need to do more stuff here var writerBuffer = output.Alloc(2048); var memory = writerBuffer.Memory; unsafe { int compressedBytes; flushed = _deflater.Flush((IntPtr)memory.UnsafePointer, memory.Length, out compressedBytes); writerBuffer.Advance(compressedBytes); } await writerBuffer.FlushAsync(); }while (flushed); bool finished; do { // Need to do more stuff here var writerBuffer = output.Alloc(2048); var memory = writerBuffer.Memory; unsafe { int compressedBytes; finished = _deflater.Finish((IntPtr)memory.UnsafePointer, memory.Length, out compressedBytes); writerBuffer.Advance(compressedBytes); } await writerBuffer.FlushAsync(); }while (!finished); input.Complete(); output.Complete(); _deflater.Dispose(); }
private async Task <WebSocketCloseResult> ReceiveLoop(Func <WebSocketFrame, object, Task> messageHandler, object state, CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { // WebSocket Frame layout (https://tools.ietf.org/html/rfc6455#section-5.2): // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-------+-+-------------+-------------------------------+ // |F|R|R|R| opcode|M| Payload len | Extended payload length | // |I|S|S|S| (4) |A| (7) | (16/64) | // |N|V|V|V| |S| | (if payload len==126/127) | // | |1|2|3| |K| | | // +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + // | Extended payload length continued, if payload len == 127 | // + - - - - - - - - - - - - - - - +-------------------------------+ // | |Masking-key, if MASK set to 1 | // +-------------------------------+-------------------------------+ // | Masking-key (continued) | Payload Data | // +-------------------------------- - - - - - - - - - - - - - - - + // : Payload Data continued ... : // + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // | Payload Data continued ... | // +---------------------------------------------------------------+ // Read at least 2 bytes var result = await _inbound.ReadAtLeastAsync(2, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); if (result.IsCompleted && result.Buffer.Length < 2) { return(WebSocketCloseResult.AbnormalClosure); } var buffer = result.Buffer; // Read the opcode var opcodeByte = buffer.ReadBigEndian <byte>(); buffer = buffer.Slice(1); var fin = (opcodeByte & 0x80) != 0; var opcodeNum = opcodeByte & 0x0F; var opcode = (WebSocketOpcode)opcodeNum; if ((opcodeByte & 0x70) != 0) { // Reserved bits set, this frame is invalid, close our side and terminate immediately return(await CloseFromProtocolError(cancellationToken, 0, default(ReadableBuffer), "Reserved bits, which are required to be zero, were set.")); } else if ((opcodeNum >= 0x03 && opcodeNum <= 0x07) || (opcodeNum >= 0x0B && opcodeNum <= 0x0F)) { // Reserved opcode return(await CloseFromProtocolError(cancellationToken, 0, default(ReadableBuffer), $"Received frame using reserved opcode: 0x{opcodeNum:X}")); } // Read the first byte of the payload length var lenByte = buffer.ReadBigEndian <byte>(); buffer = buffer.Slice(1); var masked = (lenByte & 0x80) != 0; var payloadLen = (lenByte & 0x7F); // Mark what we've got so far as consumed _inbound.Advance(buffer.Start); // Calculate the rest of the header length var headerLength = masked ? 4 : 0; if (payloadLen == 126) { headerLength += 2; } else if (payloadLen == 127) { headerLength += 8; } uint maskingKey = 0; if (headerLength > 0) { result = await _inbound.ReadAtLeastAsync(headerLength, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); if (result.IsCompleted && result.Buffer.Length < headerLength) { return(WebSocketCloseResult.AbnormalClosure); } buffer = result.Buffer; // Read extended payload length (if any) if (payloadLen == 126) { payloadLen = buffer.ReadBigEndian <ushort>(); buffer = buffer.Slice(sizeof(ushort)); } else if (payloadLen == 127) { var longLen = buffer.ReadBigEndian <ulong>(); buffer = buffer.Slice(sizeof(ulong)); if (longLen > int.MaxValue) { throw new WebSocketException($"Frame is too large. Maximum frame size is {int.MaxValue} bytes"); } payloadLen = (int)longLen; } // Read masking key if (masked) { var maskingKeyStart = buffer.Start; maskingKey = buffer.Slice(0, 4).ReadBigEndian <uint>(); buffer = buffer.Slice(4); } // Mark the length and masking key consumed _inbound.Advance(buffer.Start); } var payload = default(ReadableBuffer); if (payloadLen > 0) { result = await _inbound.ReadAtLeastAsync(payloadLen, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); if (result.IsCompleted && result.Buffer.Length < payloadLen) { return(WebSocketCloseResult.AbnormalClosure); } buffer = result.Buffer; payload = buffer.Slice(0, payloadLen); if (masked) { // Unmask MaskingUtilities.ApplyMask(ref payload, maskingKey); } } // Run the callback, if we're not cancelled. cancellationToken.ThrowIfCancellationRequested(); var frame = new WebSocketFrame(fin, opcode, payload); if (frame.Opcode.IsControl() && !frame.EndOfMessage) { // Control frames cannot be fragmented. return(await CloseFromProtocolError(cancellationToken, payloadLen, payload, "Control frames may not be fragmented")); } else if (_currentMessageType != WebSocketOpcode.Continuation && opcode.IsMessage() && opcode != 0) { return(await CloseFromProtocolError(cancellationToken, payloadLen, payload, "Received non-continuation frame during a fragmented message")); } else if (_currentMessageType == WebSocketOpcode.Continuation && frame.Opcode == WebSocketOpcode.Continuation) { return(await CloseFromProtocolError(cancellationToken, payloadLen, payload, "Continuation Frame was received when expecting a new message")); } if (frame.Opcode == WebSocketOpcode.Close) { // Allowed frame lengths: // 0 - No body // 2 - Code with no reason phrase // >2 - Code and reason phrase (must be valid UTF-8) if (frame.Payload.Length > 125) { return(await CloseFromProtocolError(cancellationToken, payloadLen, payload, "Close frame payload too long. Maximum size is 125 bytes")); } else if ((frame.Payload.Length == 1) || (frame.Payload.Length > 2 && !Utf8Validator.ValidateUtf8(payload.Slice(2)))) { return(await CloseFromProtocolError(cancellationToken, payloadLen, payload, "Close frame payload invalid")); } ushort?actualStatusCode; var closeResult = HandleCloseFrame(payload, frame, out actualStatusCode); // Verify the close result if (actualStatusCode != null) { var statusCode = actualStatusCode.Value; if (statusCode < 1000 || statusCode == 1004 || statusCode == 1005 || statusCode == 1006 || (statusCode > 1011 && statusCode < 3000)) { return(await CloseFromProtocolError(cancellationToken, payloadLen, payload, $"Invalid close status: {statusCode}.")); } } // Make the payload as consumed if (payloadLen > 0) { _inbound.Advance(payload.End); } return(closeResult); } else { if (frame.Opcode == WebSocketOpcode.Ping) { // Check the ping payload length if (frame.Payload.Length > 125) { // Payload too long return(await CloseFromProtocolError(cancellationToken, payloadLen, payload, "Ping frame exceeded maximum size of 125 bytes")); } await SendCoreAsync( frame.EndOfMessage, WebSocketOpcode.Pong, payloadAllocLength : 0, payloadLength : payload.Length, payloadWriter : AppendPayloadWriter, payload : payload, cancellationToken : cancellationToken); } var effectiveOpcode = opcode == WebSocketOpcode.Continuation ? _currentMessageType : opcode; if (effectiveOpcode == WebSocketOpcode.Text && !_validator.ValidateUtf8Frame(frame.Payload, frame.EndOfMessage)) { // Drop the frame and immediately close with InvalidPayload return(await CloseFromProtocolError(cancellationToken, payloadLen, payload, "An invalid Text frame payload was received", statusCode : WebSocketCloseStatus.InvalidPayloadData)); } else if (_options.PassAllFramesThrough || (frame.Opcode != WebSocketOpcode.Ping && frame.Opcode != WebSocketOpcode.Pong)) { await messageHandler(frame, state); } } if (fin) { // Reset the UTF8 validator _validator.Reset(); // If it's a non-control frame, reset the message type tracker if (opcode.IsMessage()) { _currentMessageType = WebSocketOpcode.Continuation; } } // If there isn't a current message type, and this was a fragmented message frame, set the current message type else if (!fin && _currentMessageType == WebSocketOpcode.Continuation && opcode.IsMessage()) { _currentMessageType = opcode; } // Mark the payload as consumed if (payloadLen > 0) { _inbound.Advance(payload.End); } } return(WebSocketCloseResult.AbnormalClosure); }