Ejemplo n.º 1
0
        private async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> httpApplication)
        {
            try
            {
                KestrelEventSource.Log.ConnectionStart(this);

                AdaptedPipeline adaptedPipeline     = null;
                var             adaptedPipelineTask = Task.CompletedTask;
                var             transport           = _context.Transport;
                var             application         = _context.Application;


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

                    transport = adaptedPipeline;
                }

                // _http1Connection must be initialized before adding the connection to the connection manager
                CreateHttp1Connection(httpApplication, transport, application);

                // _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.
                CreateHttp2Connection(httpApplication, transport, application);

                // 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;

                _http1Connection.ConnectionFeatures.Set <IConnectionTimeoutFeature>(this);
                _http2Connection.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);
                }

                var protocol = SelectProtocol();

                if (protocol == HttpProtocols.None)
                {
                    Abort(ex: null);
                }

                // One of these has to run even if no protocol was selected so the abort propagates and everything completes properly
                if (protocol == HttpProtocols.Http2 && Interlocked.CompareExchange(ref _http2ConnectionState, Http2ConnectionStarted, Http2ConnectionNotStarted) == Http2ConnectionNotStarted)
                {
                    await _http2Connection.ProcessAsync(httpApplication);
                }
                else
                {
                    await _http1Connection.ProcessRequestsAsync();
                }

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

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

                KestrelEventSource.Log.ConnectionStop(this);
            }
        }