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");
            }
Beispiel #2
0
        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
            }
        }
Beispiel #3
0
        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;
            }
        }