public FrameRequestStream(MessageBody body) { _body = body; }
/// <summary> /// Primary loop which consumes socket input, parses it for protocol framing, and invokes the /// application delegate for as long as the socket is intended to remain open. /// The resulting Task from this loop is preserved in a field which is used when the server needs /// to drain and close all currently active connections. /// </summary> public override async Task RequestProcessingAsync() { try { while (!_requestProcessingStopping) { while (!_requestProcessingStopping && !TakeStartLine(SocketInput)) { if (SocketInput.RemoteIntakeFin) { return; } await SocketInput; } while (!_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders)) { if (SocketInput.RemoteIntakeFin) { return; } await SocketInput; } if (!_requestProcessingStopping) { var messageBody = MessageBody.For(HttpVersion, _requestHeaders, this); _keepAlive = messageBody.RequestKeepAlive; // _duplexStream may be null if flag switched while running if (!ReuseStreams || _duplexStream == null) { _requestBody = new FrameRequestStream(); _responseBody = new FrameResponseStream(this); _duplexStream = new FrameDuplexStream(_requestBody, _responseBody); } RequestBody = _requestBody.StartAcceptingReads(messageBody); ResponseBody = _responseBody.StartAcceptingWrites(); DuplexStream = _duplexStream; _abortedCts = null; _manuallySetRequestAbortToken = null; var context = _application.CreateContext(this); try { await _application.ProcessRequestAsync(context).ConfigureAwait(false); } catch (Exception ex) { ReportApplicationError(ex); } finally { // Trigger OnStarting if it hasn't been called yet and the app hasn't // already failed. If an OnStarting callback throws we can go through // our normal error handling in ProduceEnd. // https://github.com/aspnet/KestrelHttpServer/issues/43 if (!_responseStarted && _applicationException == null && _onStarting != null) { await FireOnStarting(); } _requestBody.PauseAcceptingReads(); _responseBody.PauseAcceptingWrites(); if (_onCompleted != null) { await FireOnCompleted(); } _application.DisposeContext(context, _applicationException); // If _requestAbort is set, the connection has already been closed. if (!_requestAborted) { _responseBody.ResumeAcceptingWrites(); await ProduceEnd(); if (_keepAlive) { _requestBody.ResumeAcceptingReads(); // Finish reading the request body in case the app did not. await messageBody.Consume(); } } _requestBody.StopAcceptingReads(); _responseBody.StopAcceptingWrites(); } if (!_keepAlive) { return; } } Reset(); } } catch (Exception ex) { Log.LogWarning("Connection processing ended abnormally", ex); } finally { try { _abortedCts = null; // If _requestAborted is set, the connection has already been closed. if (!_requestAborted) { // Inform client no more data will ever arrive ConnectionControl.End(ProduceEndType.SocketShutdownSend); // Wait for client to either disconnect or send unexpected data await SocketInput; // Dispose socket ConnectionControl.End(ProduceEndType.SocketDisconnect); } } catch (Exception ex) { Log.LogWarning("Connection shutdown abnormally", ex); } } }
/// <summary> /// Primary loop which consumes socket input, parses it for protocol framing, and invokes the /// application delegate for as long as the socket is intended to remain open. /// The resulting Task from this loop is preserved in a field which is used when the server needs /// to drain and close all currently active connections. /// </summary> public async Task RequestProcessingAsync() { try { var terminated = false; while (!terminated && !_requestProcessingStopping) { while (!terminated && !_requestProcessingStopping && !TakeStartLine(SocketInput)) { terminated = SocketInput.RemoteIntakeFin; if (!terminated) { await SocketInput; } } while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput)) { terminated = SocketInput.RemoteIntakeFin; if (!terminated) { await SocketInput; } } if (!terminated && !_requestProcessingStopping) { MessageBody = MessageBody.For(HttpVersion, _requestHeaders, this); _keepAlive = MessageBody.RequestKeepAlive; RequestBody = new FrameRequestStream(MessageBody); ResponseBody = new FrameResponseStream(this); DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody); Exception error = null; try { await Application.Invoke(this).ConfigureAwait(false); // Trigger FireOnStarting if ProduceStart hasn't been called yet. // We call it here, so it can go through our normal error handling // and respond with a 500 if an OnStarting callback throws. if (!_responseStarted) { FireOnStarting(); } } catch (Exception ex) { error = ex; } finally { FireOnCompleted(); ProduceEnd(error); } terminated = !_keepAlive; } Reset(); } } catch (Exception ex) { Log.LogWarning("Connection processing ended abnormally", ex); } finally { try { // Inform client no more data will ever arrive ConnectionControl.End(ProduceEndType.SocketShutdownSend); // Wait for client to either disconnect or send unexpected data await SocketInput; // Dispose socket ConnectionControl.End(ProduceEndType.SocketDisconnect); } catch (Exception ex) { Log.LogWarning("Connection shutdown abnormally", ex); } } }
//int _readLength; //bool _readFin; //Exception _readError; public FrameRequestStream(MessageBody body) { _body = body; }
/* * public bool LocalIntakeFin * { * get * { * return _mode == Mode.MessageBody * ? _messageBody.LocalIntakeFin * : _mode == Mode.Terminated; * } * } */ public void Consume() { var input = SocketInput; for (; ;) { switch (_mode) { case Mode.StartLine: if (input.Buffer.Count == 0 && input.RemoteIntakeFin) { _mode = Mode.Terminated; return; } if (!TakeStartLine(input)) { if (input.RemoteIntakeFin) { _mode = Mode.Terminated; } return; } _mode = Mode.MessageHeader; break; case Mode.MessageHeader: if (input.Buffer.Count == 0 && input.RemoteIntakeFin) { _mode = Mode.Terminated; return; } var endOfHeaders = false; while (!endOfHeaders) { if (!TakeMessageHeader(input, out endOfHeaders)) { if (input.RemoteIntakeFin) { _mode = Mode.Terminated; } return; } } //var resumeBody = HandleExpectContinue(callback); _mode = Mode.MessageBody; Execute(); break; case Mode.MessageBody: if (MessageBody.LocalIntakeFin) { // NOTE: stop reading and resume on keepalive? return; } MessageBody.Consume(); // NOTE: keep looping? return; case Mode.Terminated: return; } } }
/// <summary> /// Primary loop which consumes socket input, parses it for protocol framing, and invokes the /// application delegate for as long as the socket is intended to remain open. /// The resulting Task from this loop is preserved in a field which is used when the server needs /// to drain and close all currently active connections. /// </summary> public async Task RequestProcessingAsync() { try { var terminated = false; while (!terminated && !_requestProcessingStopping) { while (!terminated && !_requestProcessingStopping && !TakeStartLine(SocketInput)) { terminated = SocketInput.RemoteIntakeFin; if (!terminated) { await SocketInput; } } while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders)) { terminated = SocketInput.RemoteIntakeFin; if (!terminated) { await SocketInput; } } if (!terminated && !_requestProcessingStopping) { MessageBody = MessageBody.For(HttpVersion, _requestHeaders, this); _keepAlive = MessageBody.RequestKeepAlive; RequestBody = new FrameRequestStream(MessageBody); ResponseBody = new FrameResponseStream(this); DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody); try { await Application.Invoke(this).ConfigureAwait(false); } catch (Exception ex) { ReportApplicationError(ex); } finally { // Trigger OnStarting if it hasn't been called yet and the app hasn't // already failed. If an OnStarting callback throws we can go through // our normal error handling in ProduceEnd. // https://github.com/aspnet/KestrelHttpServer/issues/43 if (!_responseStarted && _applicationException == null) { await FireOnStarting(); } await FireOnCompleted(); await ProduceEnd(); while (await RequestBody.ReadAsync(_nullBuffer, 0, _nullBuffer.Length) != 0) { // Finish reading the request body in case the app did not. } } terminated = !_keepAlive; } Reset(); } } catch (Exception ex) { Log.LogWarning("Connection processing ended abnormally", ex); } finally { try { // Inform client no more data will ever arrive ConnectionControl.End(ProduceEndType.SocketShutdownSend); // Wait for client to either disconnect or send unexpected data await SocketInput; // Dispose socket ConnectionControl.End(ProduceEndType.SocketDisconnect); } catch (Exception ex) { Log.LogWarning("Connection shutdown abnormally", ex); } } }
public void StopAcceptingReads() { // Can't use dispose (or close) as can be disposed too early by user code // As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes _state = FrameStreamState.Closed; _body = null; }
public Stream StartAcceptingReads(MessageBody body) { // Only start if not aborted if (_state == FrameStreamState.Closed) { _state = FrameStreamState.Open; _body = body; } return this; }