Пример #1
0
        private void StopProcessingNextRequest()
        {
            ProtocolSelectionState previousState;

            lock (_protocolSelectionLock)
            {
                previousState = _protocolSelectionState;

                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    _protocolSelectionState = ProtocolSelectionState.Aborted;
                    break;

                case ProtocolSelectionState.Selected:
                case ProtocolSelectionState.Aborted:
                    break;
                }
            }

            switch (previousState)
            {
            case ProtocolSelectionState.Initializing:
                _context.ConnectionContext.Abort(new ConnectionAbortedException(CoreStrings.ServerShutdownDuringConnectionInitialization));
                break;

            case ProtocolSelectionState.Selected:
                _requestProcessor.StopProcessingNextRequest();
                break;

            case ProtocolSelectionState.Aborted:
                break;
            }
        }
Пример #2
0
        public async Task Execute()
        {
            try
            {
                IRequestProcessor requestProcessor = null;
                Context.ServiceContext.ConnectionManager.AddConnection(Context.Features.Connection.HttpConnectionId, this);
                _lastTimestamp = Context.ServiceContext.SystemClock.UtcNow.Ticks;

                lock (_protocolSelectionLock)
                {
                    // Ensure that the connection hasn't already been stopped.
                    if (_protocolSelectionState == ProtocolSelectionState.Initializing)
                    {
                        //if (ApplicationProtocol=="h2")
                        //{
                        //    requestProcessor = new Http2.Http2Connection(new Http2.Http2ConnectionContext
                        //    {
                        //        Context = Context,
                        //        ToTransport = new PipeConnection(Context.ReceivePipe.Reader, Context.SendPipe.Writer),
                        //        ToApplication = new PipeConnection(Context.SendPipe.Reader, Context.ReceivePipe.Writer)
                        //    });
                        //}
                        //else
                        //{
                        _http1Connection = new Http1Connection(new Http1ConnectionContext
                        {
                            TimeoutControl = this,
                            Context        = Context,
                            ToTransport    = new PipeConnection(Context.ReceivePipe.Reader, Context.SendPipe.Writer),
                            ToApplication  = new PipeConnection(Context.SendPipe.Reader, Context.ReceivePipe.Writer),
                        });
                        //_http1Connection = requestProcessor;
                        requestProcessor        = _http1Connection;
                        _protocolSelectionState = ProtocolSelectionState.Selected;

                        _requestProcessor = requestProcessor;
                    }
                }

                if (requestProcessor != null)
                {
                    await requestProcessor.ProcessRequestsAsync(Context.ServiceContext.Application);
                }
            }
            catch (Exception ex)
            {
                Context.ServiceContext.Log.LogError(ex.Message, ex);
            }
            finally
            {
                Context.ServiceContext.ConnectionManager.RemoveConnection(Context.Features.Connection.HttpConnectionId);
            }
        }
Пример #3
0
        private void OnInputOrOutputCompleted()
        {
            lock (_protocolSelectionLock)
            {
                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    CloseUninitializedConnection(abortReason: null);
                    _protocolSelectionState = ProtocolSelectionState.Aborted;
                    break;

                case ProtocolSelectionState.Selected:
                    _requestProcessor.OnInputOrOutputCompleted();
                    break;

                case ProtocolSelectionState.Aborted:
                    break;
                }
            }
        }
Пример #4
0
        private void StopProcessingNextRequest()
        {
            lock (_protocolSelectionLock)
            {
                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    CloseUninitializedConnection(new ConnectionAbortedException(CoreStrings.ServerShutdownDuringConnectionInitialization));
                    _protocolSelectionState = ProtocolSelectionState.Aborted;
                    break;

                case ProtocolSelectionState.Selected:
                    _requestProcessor.StopProcessingNextRequest();
                    break;

                case ProtocolSelectionState.Aborted:
                    break;
                }
            }
        }
Пример #5
0
        private void StopProcessingNextRequest()
        {
            lock (_protocolSelectionLock)
            {
                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    CloseUninitializedConnection(abortReason: null);
                    _protocolSelectionState = ProtocolSelectionState.Aborted;
                    break;

                case ProtocolSelectionState.Selected:
                    _requestProcessor.StopProcessingNextRequest();
                    break;

                case ProtocolSelectionState.Aborted:
                    break;
                }
            }
        }
Пример #6
0
        private void Abort(ConnectionAbortedException ex)
        {
            lock (_protocolSelectionLock)
            {
                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    CloseUninitializedConnection(ex);
                    break;

                case ProtocolSelectionState.Selected:
                    _requestProcessor.Abort(ex);
                    break;

                case ProtocolSelectionState.Aborted:
                    break;
                }

                _protocolSelectionState = ProtocolSelectionState.Aborted;
            }
        }
Пример #7
0
        private void Abort(ConnectionAbortedException ex)
        {
            ProtocolSelectionState previousState;

            lock (_protocolSelectionLock) {
                previousState = _protocolSelectionState;
                Debug.Assert(previousState != ProtocolSelectionState.Initializing, "The state should never be initializing");

                _protocolSelectionState = ProtocolSelectionState.Aborted;
            }

            switch (previousState)
            {
            case ProtocolSelectionState.Selected:
                _requestProcessor.Abort(ex);
                break;

            case ProtocolSelectionState.Aborted:
                break;
            }
        }
Пример #8
0
        public Task StopProcessingNextRequestAsync()
        {
            lock (_protocolSelectionLock)
            {
                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    CloseUninitializedConnection(abortReason: null);
                    _protocolSelectionState = ProtocolSelectionState.Aborted;
                    break;

                case ProtocolSelectionState.Selected:
                    _requestProcessor.StopProcessingNextRequest();
                    break;

                case ProtocolSelectionState.Aborted:
                    break;
                }
            }

            return(_lifetimeTcs.Task);
        }
Пример #9
0
        public async Task Execute()
        {
            IRequestProcessor requestProcessor = null;

            lock (_protocolSelectionLock)
            {
                // Ensure that the connection hasn't already been stopped.
                if (_protocolSelectionState == ProtocolSelectionState.Initializing)
                {
                    //if (ApplicationProtocol=="h2")
                    //{
                    //    requestProcessor = new Http2.Http2Connection(new Http2.Http2ConnectionContext
                    //    {
                    //        Context = Context,
                    //        ToTransport = new PipeConnection(Context.ReceivePipe.Reader, Context.SendPipe.Writer),
                    //        ToApplication = new PipeConnection(Context.SendPipe.Reader, Context.ReceivePipe.Writer)
                    //    });
                    //}
                    //else
                    //{
                    requestProcessor = new Http1Connection(new Http1ConnectionContext
                    {
                        TimeoutControl = this,
                        Context        = Context,
                        ToTransport    = new PipeConnection(Context.ReceivePipe.Reader, Context.SendPipe.Writer),
                        ToApplication  = new PipeConnection(Context.SendPipe.Reader, Context.ReceivePipe.Writer),
                    });

                    _protocolSelectionState = ProtocolSelectionState.Selected;

                    _requestProcessor = requestProcessor;
                }
            }

            if (requestProcessor != null)
            {
                await requestProcessor.ProcessRequestsAsync(Context.ServiceContext.Application);
            }
        }
Пример #10
0
        public void Abort(Exception ex)
        {
            lock (_protocolSelectionLock)
            {
                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    CloseUninitializedConnection();
                    break;

                case ProtocolSelectionState.Selected:
                case ProtocolSelectionState.Stopping:
                    _requestProcessor.Abort(ex);
                    break;

                case ProtocolSelectionState.Stopped:
                    break;
                }

                _protocolSelectionState = ProtocolSelectionState.Stopped;
            }
        }
Пример #11
0
        private void OnInputOrOutputCompleted()
        {
            lock (_protocolSelectionLock)
            {
                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    // OnReader/WriterCompleted callbacks are not wired until after leaving the Initializing state.
                    Debug.Assert(false);

                    CloseUninitializedConnection(new ConnectionAbortedException("HttpConnection.OnInputOrOutputCompleted() called while in the ProtocolSelectionState.Initializing state!?"));
                    _protocolSelectionState = ProtocolSelectionState.Aborted;
                    break;

                case ProtocolSelectionState.Selected:
                    _requestProcessor.OnInputOrOutputCompleted();
                    break;

                case ProtocolSelectionState.Aborted:
                    break;
                }
            }
        }
Пример #12
0
        private void OnConnectionClosed()
        {
            ProtocolSelectionState previousState;

            lock (_protocolSelectionLock)
            {
                previousState = _protocolSelectionState;

                switch (_protocolSelectionState)
                {
                case ProtocolSelectionState.Initializing:
                    _protocolSelectionState = ProtocolSelectionState.Aborted;
                    break;

                case ProtocolSelectionState.Selected:
                case ProtocolSelectionState.Aborted:
                    break;
                }
            }

            switch (previousState)
            {
            case ProtocolSelectionState.Initializing:
                // ConnectionClosed callback is not wired up until after leaving the Initializing state.
                Debug.Assert(false);

                _context.ConnectionContext.Abort(new ConnectionAbortedException("HttpConnection.OnInputOrOutputCompleted() called while in the ProtocolSelectionState.Initializing state!?"));
                break;

            case ProtocolSelectionState.Selected:
                _requestProcessor.OnInputOrOutputCompleted();
                break;

            case ProtocolSelectionState.Aborted:
                break;
            }
        }
Пример #13
0
        private void Abort(ConnectionAbortedException ex)
        {
            ProtocolSelectionState previousState;

            lock (_protocolSelectionLock)
            {
                previousState           = _protocolSelectionState;
                _protocolSelectionState = ProtocolSelectionState.Aborted;
            }

            switch (previousState)
            {
            case ProtocolSelectionState.Initializing:
                _context.ConnectionContext.Abort(ex);
                break;

            case ProtocolSelectionState.Selected:
                _requestProcessor.Abort(ex);
                break;

            case ProtocolSelectionState.Aborted:
                break;
            }
        }
Пример #14
0
        public async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> httpApplication)
        {
            try
            {
                // Ensure TimeoutControl._lastTimestamp is initialized before anything that could set timeouts runs.
                _timeoutControl.Initialize(_systemClock.UtcNowTicks);

                IRequestProcessor requestProcessor = null;

                var httpConnectionContext = new HttpConnectionContext
                {
                    ConnectionId       = _context.ConnectionId,
                    ConnectionFeatures = _context.ConnectionFeatures,
                    MemoryPool         = _context.MemoryPool,
                    LocalEndPoint      = _context.LocalEndPoint,
                    RemoteEndPoint     = _context.RemoteEndPoint,
                    ServiceContext     = _context.ServiceContext,
                    ConnectionContext  = _context.ConnectionContext,
                    TimeoutControl     = _timeoutControl,
                    Transport          = _context.Transport
                };

                switch (SelectProtocol())
                {
                case HttpProtocols.Http1:
                    // _http1Connection must be initialized before adding the connection to the connection manager
                    requestProcessor        = _http1Connection = new Http1Connection(httpConnectionContext);
                    _protocolSelectionState = ProtocolSelectionState.Selected;
                    break;

                case HttpProtocols.Http2:
                    // _http2Connection must be initialized before yielding control to the transport thread,
                    // to prevent a race condition where _http2Connection.Abort() is called just as
                    // _http2Connection is about to be initialized.
                    requestProcessor        = new Http2Connection(httpConnectionContext);
                    _protocolSelectionState = ProtocolSelectionState.Selected;
                    break;

                case HttpProtocols.None:
                    // An error was already logged in SelectProtocol(), but we should close the connection.
                    Abort(new ConnectionAbortedException(CoreStrings.ProtocolSelectionFailed));
                    break;

                default:
                    // SelectProtocol() only returns Http1, Http2 or None.
                    throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
                }

                _requestProcessor = requestProcessor;

                if (requestProcessor != null)
                {
                    var connectionHeartbeatFeature            = _context.ConnectionFeatures.Get <IConnectionHeartbeatFeature>();
                    var connectionLifetimeNotificationFeature = _context.ConnectionFeatures.Get <IConnectionLifetimeNotificationFeature>();

                    // These features should never be null in Kestrel itself, if this middleware is ever refactored to run outside of kestrel,
                    // we'll need to handle these missing.
                    Debug.Assert(connectionHeartbeatFeature != null, nameof(IConnectionHeartbeatFeature) + " is missing!");
                    Debug.Assert(connectionLifetimeNotificationFeature != null, nameof(IConnectionLifetimeNotificationFeature) + " is missing!");

                    // Register the various callbacks once we're going to start processing requests

                    // The heart beat for various timeouts
                    connectionHeartbeatFeature?.OnHeartbeat(state => ((HttpConnection)state).Tick(), this);

                    // Register for graceful shutdown of the server
                    using var shutdownRegistration = connectionLifetimeNotificationFeature?.ConnectionClosedRequested.Register(state => ((HttpConnection)state).StopProcessingNextRequest(), this);

                    // Register for connection close
                    using var closedRegistration = _context.ConnectionContext.ConnectionClosed.Register(state => ((HttpConnection)state).OnConnectionClosed(), this);

                    await requestProcessor.ProcessRequestsAsync(httpApplication);
                }
            }
            catch (Exception ex)
            {
                Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
            }
            finally
            {
                if (_http1Connection?.IsUpgraded == true)
                {
                    _context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
                }
            }
        }
Пример #15
0
 // For testing only
 internal void Initialize(IDuplexPipe transport)
 {
     _requestProcessor       = _http1Connection = new Http1Connection(CreateDerivedContext(transport));
     _protocolSelectionState = ProtocolSelectionState.Selected;
 }
Пример #16
0
 // For testing only
 internal void Initialize(IRequestProcessor requestProcessor)
 {
     _requestProcessor       = requestProcessor;
     _http1Connection        = requestProcessor as Http1Connection;
     _protocolSelectionState = ProtocolSelectionState.Selected;
 }
Пример #17
0
        public async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> httpApplication)
        {
            try
            {
                AdaptedPipeline adaptedPipeline     = null;
                var             adaptedPipelineTask = Task.CompletedTask;

                // _adaptedTransport must be set prior to wiring up callbacks
                // to allow the connection to be aborted prior to protocol selection.
                _adaptedTransport = _context.Transport;

                if (_context.ConnectionAdapters.Count > 0)
                {
                    adaptedPipeline = new AdaptedPipeline(_adaptedTransport,
                                                          new Pipe(AdaptedInputPipeOptions),
                                                          new Pipe(AdaptedOutputPipeOptions),
                                                          Log);

                    _adaptedTransport = adaptedPipeline;
                }

                // This feature should never be null in Kestrel
                var connectionHeartbeatFeature = _context.ConnectionFeatures.Get <IConnectionHeartbeatFeature>();

                Debug.Assert(connectionHeartbeatFeature != null, nameof(IConnectionHeartbeatFeature) + " is missing!");

                connectionHeartbeatFeature?.OnHeartbeat(state => ((HttpConnection)state).Tick(), this);

                var connectionLifetimeNotificationFeature = _context.ConnectionFeatures.Get <IConnectionLifetimeNotificationFeature>();

                Debug.Assert(connectionLifetimeNotificationFeature != null, nameof(IConnectionLifetimeNotificationFeature) + " is missing!");

                using (connectionLifetimeNotificationFeature?.ConnectionClosedRequested.Register(state => ((HttpConnection)state).StopProcessingNextRequest(), this))
                {
                    // Ensure TimeoutControl._lastTimestamp is initialized before anything that could set timeouts runs.
                    _timeoutControl.Initialize(_systemClock.UtcNowTicks);

                    _context.ConnectionFeatures.Set <IConnectionTimeoutFeature>(_timeoutControl);

                    if (adaptedPipeline != null)
                    {
                        // Stream can be null here and run async will close the connection in that case
                        var stream = await ApplyConnectionAdaptersAsync();

                        adaptedPipelineTask = adaptedPipeline.RunAsync(stream);
                    }

                    IRequestProcessor requestProcessor = null;

                    lock (_protocolSelectionLock)
                    {
                        // Ensure that the connection hasn't already been stopped.
                        if (_protocolSelectionState == ProtocolSelectionState.Initializing)
                        {
                            var derivedContext = CreateDerivedContext(_adaptedTransport);

                            switch (SelectProtocol())
                            {
                            case HttpProtocols.Http1:
                                // _http1Connection must be initialized before adding the connection to the connection manager
                                requestProcessor        = _http1Connection = new Http1Connection(derivedContext);
                                _protocolSelectionState = ProtocolSelectionState.Selected;
                                break;

                            case HttpProtocols.Http2:
                                // _http2Connection must be initialized before yielding control to the transport thread,
                                // to prevent a race condition where _http2Connection.Abort() is called just as
                                // _http2Connection is about to be initialized.
                                requestProcessor        = new Http2Connection(derivedContext);
                                _protocolSelectionState = ProtocolSelectionState.Selected;
                                break;

                            case HttpProtocols.None:
                                // An error was already logged in SelectProtocol(), but we should close the connection.
                                Abort(ex: null);
                                break;

                            default:
                                // SelectProtocol() only returns Http1, Http2 or None.
                                throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
                            }

                            _requestProcessor = requestProcessor;
                        }
                    }

                    _context.Transport.Input.OnWriterCompleted(
                        (_, state) => ((HttpConnection)state).OnInputOrOutputCompleted(),
                        this);

                    _context.Transport.Output.OnReaderCompleted(
                        (_, state) => ((HttpConnection)state).OnInputOrOutputCompleted(),
                        this);

                    if (requestProcessor != null)
                    {
                        await requestProcessor.ProcessRequestsAsync(httpApplication);
                    }

                    await adaptedPipelineTask;
                }
            }
            catch (Exception ex)
            {
                Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
            }
            finally
            {
                DisposeAdaptedConnections();

                if (_http1Connection?.IsUpgraded == true)
                {
                    _context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
                }
            }
        }
Пример #18
0
        private async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> httpApplication)
        {
            try
            {
                KestrelEventSource.Log.ConnectionStart(this);

                AdaptedPipeline adaptedPipeline     = null;
                var             adaptedPipelineTask = Task.CompletedTask;

                // _adaptedTransport must be set prior to adding the connection to the manager in order
                // to allow the connection to be aported prior to protocol selection.
                _adaptedTransport = _context.Transport;
                var application = _context.Application;


                if (_context.ConnectionAdapters.Count > 0)
                {
                    adaptedPipeline = new AdaptedPipeline(_adaptedTransport,
                                                          application,
                                                          new Pipe(AdaptedInputPipeOptions),
                                                          new Pipe(AdaptedOutputPipeOptions));

                    _adaptedTransport = adaptedPipeline;
                }

                // Do this before the first await so we don't yield control to the transport until we've
                // added the connection to the connection manager
                _context.ServiceContext.ConnectionManager.AddConnection(_context.HttpConnectionId, this);
                _lastTimestamp = _context.ServiceContext.SystemClock.UtcNow.Ticks;

                _context.ConnectionFeatures.Set <IConnectionTimeoutFeature>(this);

                if (adaptedPipeline != null)
                {
                    // Stream can be null here and run async will close the connection in that case
                    var stream = await ApplyConnectionAdaptersAsync();

                    adaptedPipelineTask = adaptedPipeline.RunAsync(stream);
                }

                IRequestProcessor requestProcessor = null;

                lock (_protocolSelectionLock)
                {
                    // Ensure that the connection hasn't already been stopped.
                    if (_protocolSelectionState == ProtocolSelectionState.Initializing)
                    {
                        switch (SelectProtocol())
                        {
                        case HttpProtocols.Http1:
                            // _http1Connection must be initialized before adding the connection to the connection manager
                            requestProcessor        = _http1Connection = CreateHttp1Connection(_adaptedTransport, application);
                            _protocolSelectionState = ProtocolSelectionState.Selected;
                            break;

                        case HttpProtocols.Http2:
                            // _http2Connection must be initialized before yielding control to the transport thread,
                            // to prevent a race condition where _http2Connection.Abort() is called just as
                            // _http2Connection is about to be initialized.
                            requestProcessor        = CreateHttp2Connection(_adaptedTransport, application);
                            _protocolSelectionState = ProtocolSelectionState.Selected;
                            break;

                        case HttpProtocols.None:
                            // An error was already logged in SelectProtocol(), but we should close the connection.
                            Abort(ex: null);
                            break;

                        default:
                            // SelectProtocol() only returns Http1, Http2 or None.
                            throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
                        }

                        _requestProcessor = requestProcessor;
                    }
                }

                if (requestProcessor != null)
                {
                    await requestProcessor.ProcessRequestsAsync(httpApplication);
                }

                await adaptedPipelineTask;
                await _socketClosedTcs.Task;
            }
            catch (Exception ex)
            {
                Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
            }
            finally
            {
                _context.ServiceContext.ConnectionManager.RemoveConnection(_context.HttpConnectionId);
                DisposeAdaptedConnections();

                if (_http1Connection?.IsUpgraded == true)
                {
                    _context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
                }

                KestrelEventSource.Log.ConnectionStop(this);
            }
        }
Пример #19
0
 // For testing only
 internal void Initialize(IDuplexPipe transport, IDuplexPipe application)
 {
     _requestProcessor       = _http1Connection = CreateHttp1Connection(transport, application);
     _protocolSelectionState = ProtocolSelectionState.Selected;
 }
Пример #20
0
        public async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> httpApplication)
        {
            try
            {
                // This feature should never be null in Kestrel
                var connectionHeartbeatFeature = _context.ConnectionFeatures.Get <IConnectionHeartbeatFeature>();

                Debug.Assert(connectionHeartbeatFeature != null, nameof(IConnectionHeartbeatFeature) + " is missing!");

                connectionHeartbeatFeature?.OnHeartbeat(state => ((HttpConnection)state).Tick(), this);

                var connectionLifetimeNotificationFeature = _context.ConnectionFeatures.Get <IConnectionLifetimeNotificationFeature>();

                Debug.Assert(connectionLifetimeNotificationFeature != null, nameof(IConnectionLifetimeNotificationFeature) + " is missing!");

                using (connectionLifetimeNotificationFeature?.ConnectionClosedRequested.Register(state => ((HttpConnection)state).StopProcessingNextRequest(), this))
                {
                    // Ensure TimeoutControl._lastTimestamp is initialized before anything that could set timeouts runs.
                    _timeoutControl.Initialize(_systemClock.UtcNowTicks);

                    _context.ConnectionFeatures.Set <IConnectionTimeoutFeature>(_timeoutControl);

                    IRequestProcessor requestProcessor = null;

                    lock (_protocolSelectionLock)
                    {
                        // Ensure that the connection hasn't already been stopped.
                        if (_protocolSelectionState == ProtocolSelectionState.Initializing)
                        {
                            var derivedContext = CreateDerivedContext(_context.Transport);

                            switch (SelectProtocol())
                            {
                            case HttpProtocols.Http1:
                                // _http1Connection must be initialized before adding the connection to the connection manager
                                requestProcessor        = _http1Connection = new Http1Connection(derivedContext);
                                _protocolSelectionState = ProtocolSelectionState.Selected;
                                break;

                            case HttpProtocols.Http2:
                                // _http2Connection must be initialized before yielding control to the transport thread,
                                // to prevent a race condition where _http2Connection.Abort() is called just as
                                // _http2Connection is about to be initialized.
                                requestProcessor        = new Http2Connection(derivedContext);
                                _protocolSelectionState = ProtocolSelectionState.Selected;
                                break;

                            case HttpProtocols.None:
                                // An error was already logged in SelectProtocol(), but we should close the connection.
                                Abort(new ConnectionAbortedException(CoreStrings.ProtocolSelectionFailed));
                                break;

                            default:
                                // SelectProtocol() only returns Http1, Http2 or None.
                                throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
                            }

                            _requestProcessor = requestProcessor;
                        }
                    }

                    var closedRegistration = _context.ConnectionContext.ConnectionClosed.Register(state => ((HttpConnection)state).OnInputOrOutputCompleted(), this);

                    // We don't care about callbacks once all requests are processed
                    using (closedRegistration)
                    {
                        if (requestProcessor != null)
                        {
                            await requestProcessor.ProcessRequestsAsync(httpApplication);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
            }
            finally
            {
                if (_http1Connection?.IsUpgraded == true)
                {
                    _context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
                }
            }
        }