public async Task DisposeAndRemoveAsync(DefaultConnectionContext connection) { try { await connection.DisposeAsync(); } catch (IOException ex) { _logger.ConnectionReset(connection.ConnectionId, ex); } catch (WebSocketException ex) when(ex.InnerException is IOException) { _logger.ConnectionReset(connection.ConnectionId, ex); } catch (Exception ex) { _logger.FailedDispose(connection.ConnectionId, ex); } finally { // Remove it from the list after disposal so that's it's easy to see // connections that might be in a hung state via the connections list RemoveConnection(connection.ConnectionId); } }
private void EnsureConnectionStateInternal(DefaultConnectionContext connection, HttpSocketOptions options) { // If the connection doesn't have a pipe yet then create one, we lazily create the pipe to save on allocations until the client actually connects if (connection.Transport == null) { var transportPipeOptions = new PipeOptions(pauseWriterThreshold: options.TransportMaxBufferSize, resumeWriterThreshold: options.TransportMaxBufferSize / 2, readerScheduler: PipeScheduler.ThreadPool, useSynchronizationContext: false); var appPipeOptions = new PipeOptions(pauseWriterThreshold: options.ApplicationMaxBufferSize, resumeWriterThreshold: options.ApplicationMaxBufferSize / 2, readerScheduler: PipeScheduler.ThreadPool, useSynchronizationContext: false); var pair = DuplexPipe.CreateConnectionPair(transportPipeOptions, appPipeOptions); connection.Transport = pair.Application; connection.Application = pair.Transport; } }
private async Task <bool> EnsureConnectionStateAsync(DefaultConnectionContext connection, HttpContext context, TransportType transportType, TransportType supportedTransports, ConnectionLogScope logScope, HttpSocketOptions options) { if ((supportedTransports & transportType) == 0) { context.Response.ContentType = "text/plain"; context.Response.StatusCode = StatusCodes.Status404NotFound; _logger.TransportNotSupported(transportType); await context.Response.WriteAsync($"{transportType} transport not supported by this end point type"); return(false); } // Set the IHttpConnectionFeature now that we can access it. connection.Features.Set(context.Features.Get <IHttpConnectionFeature>()); var transport = (TransportType?)connection.Metadata[ConnectionMetadataNames.Transport]; if (transport == null) { connection.Metadata[ConnectionMetadataNames.Transport] = transportType; } else if (transport != transportType) { context.Response.ContentType = "text/plain"; context.Response.StatusCode = StatusCodes.Status400BadRequest; _logger.CannotChangeTransport(transport.Value, transportType); await context.Response.WriteAsync("Cannot change transports mid-connection"); return(false); } // Configure transport-specific features. if (transportType == TransportType.LongPolling) { connection.Features.Set <IConnectionInherentKeepAliveFeature>(new ConnectionInherentKeepAliveFeature(options.LongPolling.PollTimeout)); } // Setup the connection state from the http context connection.User = context.User; connection.SetHttpContext(context); // this is the default setting which should be overwritten by transports that have different capabilities (e.g. SSE) connection.TransportCapabilities = TransferMode.Binary | TransferMode.Text; // Set the Connection ID on the logging scope so that logs from now on will have the // Connection ID metadata set. logScope.ConnectionId = connection.ConnectionId; return(true); }
public DefaultConnectionContext CreateConnection(PipeOptions transportPipeOptions, PipeOptions appPipeOptions) { var id = MakeNewConnectionId(); _logger.CreatedNewConnection(id); var connectionTimer = SocketEventSource.Log.ConnectionStart(id); var pair = DuplexPipe.CreateConnectionPair(transportPipeOptions, appPipeOptions); var connection = new DefaultConnectionContext(id, pair.Application, pair.Transport); connection.ConnectionTimer = connectionTimer; _connections.TryAdd(id, connection); return(connection); }
private async Task DoPersistentConnection(ConnectionDelegate ConnectionDelegate, IHttpTransport transport, HttpContext context, DefaultConnectionContext connection) { try { await connection.Lock.WaitAsync(); if (connection.Status == DefaultConnectionContext.ConnectionStatus.Disposed) { Log.ConnectionDisposed(_logger, connection.ConnectionId); // Connection was disposed context.Response.StatusCode = StatusCodes.Status404NotFound; return; } // There's already an active request if (connection.Status == DefaultConnectionContext.ConnectionStatus.Active) { Log.ConnectionAlreadyActive(_logger, connection.ConnectionId, connection.GetHttpContext().TraceIdentifier); // Reject the request with a 409 conflict context.Response.StatusCode = StatusCodes.Status409Conflict; return; } // Mark the connection as active connection.Status = DefaultConnectionContext.ConnectionStatus.Active; // Call into the end point passing the connection connection.ApplicationTask = ExecuteApplication(ConnectionDelegate, connection); // Start the transport connection.TransportTask = transport.ProcessRequestAsync(context, context.RequestAborted); } finally { connection.Lock.Release(); } // Wait for any of them to end await Task.WhenAny(connection.ApplicationTask, connection.TransportTask); await _manager.DisposeAndRemoveAsync(connection); }
public DefaultConnectionContext CreateConnection() { var id = MakeNewConnectionId(); _logger.CreatedNewConnection(id); var transportToApplication = Channel.CreateUnbounded <byte[]>(); var applicationToTransport = Channel.CreateUnbounded <byte[]>(); var transportSide = ChannelConnection.Create <byte[]>(applicationToTransport, transportToApplication); var applicationSide = ChannelConnection.Create <byte[]>(transportToApplication, applicationToTransport); var connection = new DefaultConnectionContext(id, applicationSide, transportSide); _connections.TryAdd(id, connection); return(connection); }
private async Task <bool> EnsureConnectionStateAsync(DefaultConnectionContext connection, HttpContext context, TransportType transportType, TransportType supportedTransports, ConnectionLogScope logScope) { if ((supportedTransports & transportType) == 0) { context.Response.StatusCode = StatusCodes.Status404NotFound; _logger.TransportNotSupported(connection.ConnectionId, transportType); await context.Response.WriteAsync($"{transportType} transport not supported by this end point type"); return(false); } var transport = (TransportType?)connection.Metadata[ConnectionMetadataNames.Transport]; if (transport == null) { connection.Metadata[ConnectionMetadataNames.Transport] = transportType; } else if (transport != transportType) { context.Response.StatusCode = StatusCodes.Status400BadRequest; _logger.CannotChangeTransport(connection.ConnectionId, transport.Value, transportType); await context.Response.WriteAsync("Cannot change transports mid-connection"); return(false); } // Setup the connection state from the http context connection.User = context.User; connection.SetHttpContext(context); // this is the default setting which should be overwritten by transports that have different capabilities (e.g. SSE) connection.TransportCapabilities = TransferMode.Binary | TransferMode.Text; // Set the Connection ID on the logging scope so that logs from now on will have the // Connection ID metadata set. logScope.ConnectionId = connection.ConnectionId; return(true); }
public void GlobalSetup() { var serviceCollection = new ServiceCollection(); serviceCollection.AddSignalRCore(); var provider = serviceCollection.BuildServiceProvider(); var serviceScopeFactory = provider.GetService <IServiceScopeFactory>(); _dispatcher = new DefaultHubDispatcher <TestHub>( serviceScopeFactory, new HubContext <TestHub>(new DefaultHubLifetimeManager <TestHub>()), new Logger <DefaultHubDispatcher <TestHub> >(NullLoggerFactory.Instance)); var options = new PipeOptions(); var pair = DuplexPipe.CreateConnectionPair(options, options); var connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), pair.Transport, pair.Application); _connectionContext = new NoErrorHubConnectionContext(connection, TimeSpan.Zero, NullLoggerFactory.Instance); _connectionContext.Protocol = new FakeHubProtocol(); }
public bool TryGetConnection(string id, out DefaultConnectionContext connection) { return(_connections.TryGetValue(id, out connection)); }