public override async Task <WebSocketReceiveResult> ReceiveAsync(ArraySegment <byte> buffer, CancellationToken cancellationToken) { try { await _input.WaitToReadAsync(); if (_input.TryRead(out var message)) { if (message.MessageType == WebSocketMessageType.Close) { _state = WebSocketState.CloseReceived; _closeStatus = message.CloseStatus; _closeStatusDescription = message.CloseStatusDescription; return(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, message.CloseStatus, message.CloseStatusDescription)); } // REVIEW: This assumes the buffer passed in is > the buffer received Buffer.BlockCopy(message.Buffer, 0, buffer.Array, buffer.Offset, message.Buffer.Length); return(new WebSocketReceiveResult(message.Buffer.Length, message.MessageType, message.EndOfMessage)); } } catch (WebSocketException ex) { switch (ex.WebSocketErrorCode) { case WebSocketError.ConnectionClosedPrematurely: _state = WebSocketState.Aborted; break; } throw; } throw new InvalidOperationException("Unexpected close"); }
public async Task ProcessRequestAsync(HttpContext context, CancellationToken token) { context.Response.ContentType = "text/event-stream"; context.Response.Headers["Cache-Control"] = "no-cache"; // Make sure we disable all response buffering for SSE var bufferingFeature = context.Features.Get <IHttpBufferingFeature>(); bufferingFeature?.DisableResponseBuffering(); context.Response.Headers["Content-Encoding"] = "identity"; // Workaround for a Firefox bug where EventSource won't fire the open event // until it receives some data await context.Response.WriteAsync(":\r\n"); await context.Response.Body.FlushAsync(); try { while (await _application.WaitToReadAsync(token)) { var ms = new MemoryStream(); while (_application.TryRead(out var buffer)) { _logger.SSEWritingMessage(_connectionId, buffer.Length); ServerSentEventsMessageFormatter.WriteMessage(buffer, ms); } ms.Seek(0, SeekOrigin.Begin); await ms.CopyToAsync(context.Response.Body); } await _application.Completion; } catch (OperationCanceledException) { // Closed connection } }
public async Task ProcessRequestAsync(HttpContext context, CancellationToken token) { try { if (!await _application.WaitToReadAsync(token)) { await _application.Completion; _logger.LongPolling204(_connectionId, context.TraceIdentifier); context.Response.StatusCode = StatusCodes.Status204NoContent; return; } // REVIEW: What should the content type be? var contentLength = 0; var buffers = new List <byte[]>(); // We're intentionally not checking cancellation here because we need to drain messages we've got so far, // but it's too late to emit the 204 required by being cancelled. while (_application.TryRead(out var buffer)) { contentLength += buffer.Length; buffers.Add(buffer); _logger.LongPollingWritingMessage(_connectionId, context.TraceIdentifier, buffer.Length); } context.Response.ContentLength = contentLength; foreach (var buffer in buffers) { await context.Response.Body.WriteAsync(buffer, 0, buffer.Length); } } catch (OperationCanceledException) { // 3 cases: // 1 - Request aborted, the client disconnected (no response) // 2 - The poll timeout is hit (204) // 3 - A new request comes in and cancels this request (204) // Case 1 if (context.RequestAborted.IsCancellationRequested) { // Don't count this as cancellation, this is normal as the poll can end due to the browser closing. // The background thread will eventually dispose this connection if it's inactive _logger.LongPollingDisconnected(_connectionId, context.TraceIdentifier); } // Case 2 else if (_timeoutToken.IsCancellationRequested) { _logger.PollTimedOut(_connectionId, context.TraceIdentifier); context.Response.ContentLength = 0; context.Response.StatusCode = StatusCodes.Status200OK; } else { // Case 3 _logger.LongPolling204(_connectionId, context.TraceIdentifier); context.Response.StatusCode = StatusCodes.Status204NoContent; } } catch (Exception ex) { _logger.LongPollingTerminated(_connectionId, context.TraceIdentifier, ex); throw; } }