public async Task OnConnectionOnCompletedExceptionCaught()
        {
            var serviceContext = new TestServiceContext();
            var logger = ((TestKestrelTrace)serviceContext.Log).Logger;
            var connection = new Mock <DefaultConnectionContext> {
                CallBase = true
            }.Object;

            connection.ConnectionClosed = new CancellationToken(canceled: true);
            var kestrelConnection = new KestrelConnection(0, serviceContext, _ => Task.CompletedTask, connection, serviceContext.Log);

            serviceContext.ConnectionManager.AddConnection(0, kestrelConnection);
            var completeFeature = kestrelConnection.TransportConnection.Features.Get <IConnectionCompleteFeature>();

            Assert.NotNull(completeFeature);
            object stateObject   = new object();
            object callbackState = null;

            completeFeature.OnCompleted(state => { callbackState = state; throw new InvalidTimeZoneException(); }, stateObject);

            await kestrelConnection.ExecuteAsync();

            Assert.Equal(stateObject, callbackState);
            var errors = logger.Messages.Where(e => e.LogLevel >= LogLevel.Error).ToArray();

            Assert.Single(errors);
            Assert.Equal("An error occured running an IConnectionCompleteFeature.OnCompleted callback.", errors[0].Message);
        }
        private void StartAcceptingConnectionsCore(IConnectionListener listener)
        {
            // REVIEW: Multiple accept loops in parallel?
            _ = AcceptConnectionsAsync();

            async Task AcceptConnectionsAsync()
            {
                try
                {
                    while (true)
                    {
                        var connection = await listener.AcceptAsync();

                        if (connection == null)
                        {
                            // We're done listening
                            break;
                        }

                        var id = Interlocked.Increment(ref _lastConnectionId);
                        var kestrelConnection = new KestrelConnection(id, _serviceContext, _connectionDelegate, connection, _serviceContext.Log);
                        ThreadPool.UnsafeQueueUserWorkItem(kestrelConnection, preferLocal: false);
                    }
                }
                catch (Exception ex)
                {
                    // REVIEW: If the accept loop ends should this trigger a server shutdown? It will manifest as a hang
                    Log.LogCritical(0, ex, "The connection listener failed to accept any new connections.");
                }
                finally
                {
                    _acceptLoopTcs.TrySetResult(null);
                }
            }
        }
        public async Task OnConnectionFiresOnCompleted()
        {
            var serviceContext = new TestServiceContext();

            var connection = new Mock <DefaultConnectionContext> {
                CallBase = true
            }.Object;

            connection.ConnectionClosed = new CancellationToken(canceled: true);
            var transportConnectionManager = new TransportConnectionManager(serviceContext.ConnectionManager);
            var kestrelConnection          = new KestrelConnection <ConnectionContext>(0, serviceContext, transportConnectionManager, _ => Task.CompletedTask, connection, serviceContext.Log);

            transportConnectionManager.AddConnection(0, kestrelConnection);
            var completeFeature = kestrelConnection.TransportConnection.Features.Get <IConnectionCompleteFeature>();

            Assert.NotNull(completeFeature);
            object stateObject   = new object();
            object callbackState = null;

            completeFeature.OnCompleted(state => { callbackState = state; return(Task.CompletedTask); }, stateObject);

            await kestrelConnection.ExecuteAsync();

            Assert.Equal(stateObject, callbackState);
        }
        private void UnrootedConnectionsGetRemovedFromHeartbeatInnerScope(
            string connectionId,
            ConnectionManager httpConnectionManager,
            KestrelTrace trace)
        {
            var serviceContext = new TestServiceContext();
            var mock           = new Mock <DefaultConnectionContext>()
            {
                CallBase = true
            };

            mock.Setup(m => m.ConnectionId).Returns(connectionId);
            var transportConnectionManager = new TransportConnectionManager(httpConnectionManager);
            var httpConnection             = new KestrelConnection <ConnectionContext>(0, serviceContext, transportConnectionManager, _ => Task.CompletedTask, mock.Object, trace);

            transportConnectionManager.AddConnection(0, httpConnection);

            var connectionCount = 0;

            httpConnectionManager.Walk(_ => connectionCount++);

            Assert.Equal(1, connectionCount);
            Assert.Empty(TestSink.Writes.Where(c => c.EventId.Name == "ApplicationNeverCompleted"));

            // Ensure httpConnection doesn't get GC'd before this point.
            GC.KeepAlive(httpConnection);
        }
Beispiel #5
0
        public async Task OnConnectionOnCompletedExceptionCaught()
        {
            var serviceContext = new TestServiceContext();
            var dispatcher     = new ConnectionDispatcher(serviceContext, _ => Task.CompletedTask);

            var connection = new Mock <DefaultConnectionContext> {
                CallBase = true
            }.Object;

            connection.ConnectionClosed = new CancellationToken(canceled: true);
            var mockLogger        = new Mock <ILogger>();
            var kestrelConnection = new KestrelConnection(connection, mockLogger.Object);
            var completeFeature   = kestrelConnection.TransportConnection.Features.Get <IConnectionCompleteFeature>();

            Assert.NotNull(completeFeature);
            object stateObject   = new object();
            object callbackState = null;

            completeFeature.OnCompleted(state => { callbackState = state; throw new InvalidTimeZoneException(); }, stateObject);

            await dispatcher.Execute(kestrelConnection);

            Assert.Equal(stateObject, callbackState);
            var log = mockLogger.Invocations.First();

            Assert.Equal("An error occured running an IConnectionCompleteFeature.OnCompleted callback.", log.Arguments[2].ToString());
            Assert.IsType <InvalidTimeZoneException>(log.Arguments[3]);
        }
        private void UnrootedConnectionsGetRemovedFromHeartbeatInnerScope(
            string connectionId,
            ConnectionManager httpConnectionManager,
            Mock <IKestrelTrace> trace)
        {
            var mock = new Mock <DefaultConnectionContext>()
            {
                CallBase = true
            };

            mock.Setup(m => m.ConnectionId).Returns(connectionId);
            var httpConnection = new KestrelConnection(mock.Object, Mock.Of <ILogger>());

            httpConnectionManager.AddConnection(0, httpConnection);

            var connectionCount = 0;

            httpConnectionManager.Walk(_ => connectionCount++);

            Assert.Equal(1, connectionCount);
            trace.Verify(t => t.ApplicationNeverCompleted(connectionId), Times.Never());

            // Ensure httpConnection doesn't get GC'd before this point.
            GC.KeepAlive(httpConnection);
        }
        public async Task OnConnectionCreatesLogScopeWithConnectionId()
        {
            var serviceContext = new TestServiceContext();
            // This needs to run inline
            var tcs = new TaskCompletionSource <object>();

            var connection = new Mock <DefaultConnectionContext> {
                CallBase = true
            }.Object;

            connection.ConnectionClosed = new CancellationToken(canceled: true);
            var kestrelConnection = new KestrelConnection(0, serviceContext, _ => tcs.Task, connection, serviceContext.Log);

            var task = kestrelConnection.ExecuteAsync();

            // The scope should be created
            var scopeObjects = ((TestKestrelTrace)serviceContext.Log)
                               .Logger
                               .Scopes
                               .OfType <IReadOnlyList <KeyValuePair <string, object> > >()
                               .ToList();

            Assert.Single(scopeObjects);
            var pairs = scopeObjects[0].ToDictionary(p => p.Key, p => p.Value);

            Assert.True(pairs.ContainsKey("ConnectionId"));
            Assert.Equal(connection.ConnectionId, pairs["ConnectionId"]);

            tcs.TrySetResult(null);

            await task;

            // Verify the scope was disposed after request processing completed
            Assert.True(((TestKestrelTrace)serviceContext.Log).Logger.Scopes.IsEmpty);
        }
Beispiel #8
0
    public ConnectionReference(long id, KestrelConnection connection, TransportConnectionManager transportConnectionManager)
    {
        _id = id;

        _weakReference = new WeakReference <KestrelConnection>(connection);
        ConnectionId   = connection.TransportConnection.ConnectionId;

        _transportConnectionManager = transportConnectionManager;
    }
    public void AddConnection(long id, KestrelConnection connection)
    {
        var connectionReference = new ConnectionReference(id, connection, this);

        if (!_connectionReferences.TryAdd(id, connectionReference))
        {
            throw new ArgumentException("Unable to add specified id.", nameof(id));
        }

        _connectionManager.AddConnection(id, connectionReference);
    }
Beispiel #10
0
        private async Task Execute(KestrelConnection connection)
        {
            var id = Interlocked.Increment(ref _lastConnectionId);
            var connectionContext = connection.TransportConnection;

            try
            {
                _serviceContext.ConnectionManager.AddConnection(id, connection);

                Log.ConnectionStart(connectionContext.ConnectionId);
                KestrelEventSource.Log.ConnectionStart(connectionContext);

                using (BeginConnectionScope(connectionContext))
                {
                    try
                    {
                        await _connectionDelegate(connectionContext);
                    }
                    catch (Exception ex)
                    {
                        Log.LogCritical(0, ex, $"{nameof(ConnectionDispatcher)}.{nameof(Execute)}() {connectionContext.ConnectionId}");
                    }
                    finally
                    {
                        // Complete the transport PipeReader and PipeWriter after calling into application code
                        connectionContext.Transport.Input.Complete();
                        connectionContext.Transport.Output.Complete();
                    }

                    // Wait for the transport to close
                    await CancellationTokenAsTask(connectionContext.ConnectionClosed);
                }
            }
            finally
            {
                await connectionContext.CompleteAsync();

                Log.ConnectionStop(connectionContext.ConnectionId);
                KestrelEventSource.Log.ConnectionStop(connectionContext);

                connection.Complete();

                _serviceContext.ConnectionManager.RemoveConnection(id);
            }
        }
    private void StartAcceptingConnectionsCore(IConnectionListener <T> listener)
    {
        // REVIEW: Multiple accept loops in parallel?
        _ = AcceptConnectionsAsync();

        async Task AcceptConnectionsAsync()
        {
            try
            {
                while (true)
                {
                    var connection = await listener.AcceptAsync();

                    if (connection == null)
                    {
                        // We're done listening
                        break;
                    }

                    // Add the connection to the connection manager before we queue it for execution
                    var id = _transportConnectionManager.GetNewConnectionId();
                    var kestrelConnection = new KestrelConnection <T>(
                        id, _serviceContext, _transportConnectionManager, _connectionDelegate, connection, Log);

                    _transportConnectionManager.AddConnection(id, kestrelConnection);

                    Log.ConnectionAccepted(connection.ConnectionId);
                    KestrelEventSource.Log.ConnectionQueuedStart(connection);

                    ThreadPool.UnsafeQueueUserWorkItem(kestrelConnection, preferLocal: false);
                }
            }
            catch (Exception ex)
            {
                // REVIEW: If the accept loop ends should this trigger a server shutdown? It will manifest as a hang
                Log.LogCritical(0, ex, "The connection listener failed to accept any new connections.");
            }
            finally
            {
                _acceptLoopTcs.TrySetResult();
            }
        }
    }
        internal async Task Execute(KestrelConnection connection)
        {
            var id = Interlocked.Increment(ref _lastConnectionId);
            var connectionContext = connection.TransportConnection;

            try
            {
                _serviceContext.ConnectionManager.AddConnection(id, connection);

                Log.ConnectionStart(connectionContext.ConnectionId);
                KestrelEventSource.Log.ConnectionStart(connectionContext);

                using (BeginConnectionScope(connectionContext))
                {
                    try
                    {
                        await _connectionDelegate(connectionContext);
                    }
                    catch (Exception ex)
                    {
                        Log.LogError(0, ex, "Unhandled exception while processing {ConnectionId}.", connectionContext.ConnectionId);
                    }
                }
            }
            finally
            {
                await connection.FireOnCompletedAsync();

                Log.ConnectionStop(connectionContext.ConnectionId);
                KestrelEventSource.Log.ConnectionStop(connectionContext);

                // Dispose the transport connection, this needs to happen before removing it from the
                // connection manager so that we only signal completion of this connection after the transport
                // is properly torn down.
                await connection.TransportConnection.DisposeAsync();

                _serviceContext.ConnectionManager.RemoveConnection(id);
            }
        }
Beispiel #13
0
        public async Task OnConnectionFiresOnCompleted()
        {
            var serviceContext = new TestServiceContext();
            var dispatcher     = new ConnectionDispatcher(serviceContext, _ => Task.CompletedTask);

            var connection = new Mock <DefaultConnectionContext> {
                CallBase = true
            }.Object;

            connection.ConnectionClosed = new CancellationToken(canceled: true);
            var kestrelConnection = new KestrelConnection(connection, Mock.Of <ILogger>());
            var completeFeature   = kestrelConnection.TransportConnection.Features.Get <IConnectionCompleteFeature>();

            Assert.NotNull(completeFeature);
            object stateObject   = new object();
            object callbackState = null;

            completeFeature.OnCompleted(state => { callbackState = state; return(Task.CompletedTask); }, stateObject);

            await dispatcher.Execute(kestrelConnection);

            Assert.Equal(stateObject, callbackState);
        }
Beispiel #14
0
 private void WalkCallback(KestrelConnection connection)
 {
     connection.TickHeartbeat();
 }