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; } }
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); } }
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; } } }
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; } } }
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; } } }
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; } }
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; } }
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); }
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); } }
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; } }
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; } } }
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; } }
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; } }
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(); } } }
// For testing only internal void Initialize(IDuplexPipe transport) { _requestProcessor = _http1Connection = new Http1Connection(CreateDerivedContext(transport)); _protocolSelectionState = ProtocolSelectionState.Selected; }
// For testing only internal void Initialize(IRequestProcessor requestProcessor) { _requestProcessor = requestProcessor; _http1Connection = requestProcessor as Http1Connection; _protocolSelectionState = ProtocolSelectionState.Selected; }
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(); } } }
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); } }
// For testing only internal void Initialize(IDuplexPipe transport, IDuplexPipe application) { _requestProcessor = _http1Connection = CreateHttp1Connection(transport, application); _protocolSelectionState = ProtocolSelectionState.Selected; }
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(); } } }