public bool TakeMessageHeaders(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { // Make sure the buffer is limited bool overLength = false; if (buffer.Length >= _remainingRequestHeadersBytesAllowed) { buffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed); // If we sliced it means the current buffer bigger than what we're // allowed to look at overLength = true; } var result = _parser.ParseHeaders(new Proto1ParsingHandler(this), buffer, out consumed, out examined, out var consumedBytes); _remainingRequestHeadersBytesAllowed -= consumedBytes; if (!result && overLength) { BadProtoRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize); } if (result) { TimeoutControl.CancelTimeout(); } return(result); }
public HttpConnection(HttpConnectionContext context) { _context = context; _systemClock = _context.ServiceContext.SystemClock; _timeoutControl = new TimeoutControl(this); }
public Http3Connection(Http3ConnectionContext context) { _multiplexedContext = context.ConnectionContext; _context = context; DynamicTable = new DynamicTable(0); _systemClock = context.ServiceContext.SystemClock; _timeoutControl = new TimeoutControl(this); _context.TimeoutControl ??= _timeoutControl; }
protected override void OnRequestProcessingEnded() { TimeoutControl.StartDrainTimeout(MinResponseDataRate, ServerOptions.Limits.MaxResponseBufferSize); // Prevent RequestAborted from firing. Free up unneeded feature references. Reset(); _http1Output.Dispose(); }
public HttpConnection(BaseHttpConnectionContext context) { _context = context; _systemClock = _context.ServiceContext.SystemClock; _timeoutControl = new TimeoutControl(this); // Tests override the timeout control sometimes _context.TimeoutControl ??= _timeoutControl; }
public Http3InMemory(ServiceContext serviceContext, MockSystemClock mockSystemClock, ITimeoutHandler timeoutHandler, ILoggerFactory loggerFactory) { _serviceContext = serviceContext; _timeoutControl = new TimeoutControl(new TimeoutControlConnectionInvoker(this, timeoutHandler)); _timeoutControl.Debugger = new TestDebugger(); _mockSystemClock = mockSystemClock; _serverReceivedSettings = Channel.CreateUnbounded <KeyValuePair <Http3SettingType, long> >(); Logger = loggerFactory.CreateLogger <Http3InMemory>(); }
public Http3Connection(Http3ConnectionContext context) { _multiplexedContext = context.ConnectionContext; _context = context; _systemClock = context.ServiceContext.SystemClock; _timeoutControl = new TimeoutControl(this); _context.TimeoutControl ??= _timeoutControl; var httpLimits = context.ServiceContext.ServerOptions.Limits; _serverSettings.HeaderTableSize = (uint)httpLimits.Http3.HeaderTableSize; _serverSettings.MaxRequestHeaderFieldSize = (uint)httpLimits.Http3.MaxRequestHeaderFieldSize; }
public bool TakeMessageHeaders(ref SequenceReader <byte> reader, bool trailers) { // Make sure the buffer is limited if (reader.Remaining > _remainingRequestHeadersBytesAllowed) { // Input oversize, cap amount checked return(TrimAndTakeMessageHeaders(ref reader, trailers)); } var alreadyConsumed = reader.Consumed; try { var result = _parser.ParseHeaders(new Http1ParsingHandler(this, trailers), ref reader); if (result) { TimeoutControl.CancelTimeout(); } return(result); } finally { _remainingRequestHeadersBytesAllowed -= reader.Consumed - alreadyConsumed; } bool TrimAndTakeMessageHeaders(ref SequenceReader <byte> reader, bool trailers) { var trimmedBuffer = reader.Sequence.Slice(reader.Position, _remainingRequestHeadersBytesAllowed); var trimmedReader = new SequenceReader <byte>(trimmedBuffer); try { if (!_parser.ParseHeaders(new Http1ParsingHandler(this, trailers), ref trimmedReader)) { // We read the maximum allowed but didn't complete the headers. KestrelBadHttpRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize); } TimeoutControl.CancelTimeout(); reader.Advance(trimmedReader.Consumed); return(true); } finally { _remainingRequestHeadersBytesAllowed -= trimmedReader.Consumed; } } }
public Http3TestBase() { _timeoutControl = new TimeoutControl(_mockTimeoutHandler.Object); _mockTimeoutControl = new Mock <MockTimeoutControlBase>(_timeoutControl) { CallBase = true }; _timeoutControl.Debugger = Mock.Of <IDebugger>(); _mockKestrelTrace .Setup(m => m.Http3ConnectionClosed(It.IsAny <string>(), It.IsAny <long>())) .Callback(() => _closedStateReached.SetResult()); _noopApplication = context => Task.CompletedTask; _echoApplication = async context => { var buffer = new byte[16 * 1024]; var received = 0; while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) { await context.Response.Body.WriteAsync(buffer, 0, received); } }; _echoMethod = context => { context.Response.Headers["Method"] = context.Request.Method; return(Task.CompletedTask); }; _echoPath = context => { context.Response.Headers["path"] = context.Request.Path.ToString(); context.Response.Headers["rawtarget"] = context.Features.Get <IHttpRequestFeature>().RawTarget; return(Task.CompletedTask); }; _echoHost = context => { context.Response.Headers[HeaderNames.Host] = context.Request.Headers[HeaderNames.Host]; return(Task.CompletedTask); }; }
protected override void OnRequestProcessingEnded() { if (IsUpgraded) { KestrelEventSource.Log.RequestUpgradedStop(this); ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne(); } TimeoutControl.StartDrainTimeout(MinResponseDataRate, ServerOptions.Limits.MaxResponseBufferSize); // Prevent RequestAborted from firing. Free up unneeded feature references. Reset(); _http1Output.Dispose(); }
public bool ParseRequest(ref SequenceReader <byte> reader) { switch (_requestProcessingStatus) { case RequestProcessingStatus.RequestPending: // Skip any empty lines (\r or \n) between requests. // Peek first as a minor performance optimization; it's a quick inlined check. if (reader.TryPeek(out byte b) && (b == ByteCR || b == ByteLF)) { reader.AdvancePastAny(ByteCR, ByteLF); } if (reader.End) { break; } TimeoutControl.ResetTimeout(_requestHeadersTimeoutTicks, TimeoutReason.RequestHeaders); _requestProcessingStatus = RequestProcessingStatus.ParsingRequestLine; goto case RequestProcessingStatus.ParsingRequestLine; case RequestProcessingStatus.ParsingRequestLine: if (TakeStartLine(ref reader)) { _requestProcessingStatus = RequestProcessingStatus.ParsingHeaders; goto case RequestProcessingStatus.ParsingHeaders; } else { break; } case RequestProcessingStatus.ParsingHeaders: if (TakeMessageHeaders(ref reader, trailers: false)) { _requestProcessingStatus = RequestProcessingStatus.AppStarted; // Consumed preamble return(true); } break; } // Haven't completed consuming preamble return(false); }
public Http3TestBase() { _timeoutControl = new TimeoutControl(_mockTimeoutHandler.Object); _mockTimeoutControl = new Mock <MockTimeoutControlBase>(_timeoutControl) { CallBase = true }; _timeoutControl.Debugger = Mock.Of <IDebugger>(); _noopApplication = context => Task.CompletedTask; _echoApplication = async context => { var buffer = new byte[Http3PeerSettings.MinAllowedMaxFrameSize]; var received = 0; while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) { await context.Response.Body.WriteAsync(buffer, 0, received); } }; _echoMethod = context => { context.Response.Headers["Method"] = context.Request.Method; return(Task.CompletedTask); }; _echoPath = context => { context.Response.Headers["path"] = context.Request.Path.ToString(); context.Response.Headers["rawtarget"] = context.Features.Get <IHttpRequestFeature>().RawTarget; return(Task.CompletedTask); }; _echoHost = context => { context.Response.Headers[HeaderNames.Host] = context.Request.Headers[HeaderNames.Host]; return(Task.CompletedTask); }; }
public Http3TestBase() { _timeoutControl = new TimeoutControl(_mockTimeoutHandler.Object); _mockTimeoutControl = new Mock <MockTimeoutControlBase>(_timeoutControl) { CallBase = true }; _timeoutControl.Debugger = Mock.Of <IDebugger>(); _echoApplication = async context => { var buffer = new byte[Http3PeerSettings.MinAllowedMaxFrameSize]; var received = 0; while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) { await context.Response.Body.WriteAsync(buffer, 0, received); } }; }
public bool ParseRequest(ref SequenceReader <byte> reader) { switch (_requestProcessingStatus) { case RequestProcessingStatus.RequestPending: if (reader.End) { break; } TimeoutControl.ResetTimeout(_requestHeadersTimeoutTicks, TimeoutReason.RequestHeaders); _requestProcessingStatus = RequestProcessingStatus.ParsingRequestLine; goto case RequestProcessingStatus.ParsingRequestLine; case RequestProcessingStatus.ParsingRequestLine: if (TakeStartLine(ref reader)) { _requestProcessingStatus = RequestProcessingStatus.ParsingHeaders; goto case RequestProcessingStatus.ParsingHeaders; } else { break; } case RequestProcessingStatus.ParsingHeaders: if (TakeMessageHeaders(ref reader, trailers: false)) { _requestProcessingStatus = RequestProcessingStatus.AppStarted; // Consumed preamble return(true); } break; } // Haven't completed consuming preamble return(false); }
public void ParseRequest(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.End; switch (_requestProcessingStatus) { case RequestProcessingStatus.RequestPending: if (buffer.IsEmpty) { break; } TimeoutControl.ResetTimeout(_requestHeadersTimeoutTicks, TimeoutReason.RequestHeaders); _requestProcessingStatus = RequestProcessingStatus.ParsingRequestLine; goto case RequestProcessingStatus.ParsingRequestLine; case RequestProcessingStatus.ParsingRequestLine: if (TakeStartLine(buffer, out consumed, out examined)) { buffer = buffer.Slice(consumed, buffer.End); _requestProcessingStatus = RequestProcessingStatus.ParsingHeaders; goto case RequestProcessingStatus.ParsingHeaders; } else { break; } case RequestProcessingStatus.ParsingHeaders: if (TakeMessageHeaders(buffer, trailers: false, out consumed, out examined)) { _requestProcessingStatus = RequestProcessingStatus.AppStarted; } break; } }
protected override void BeginRequestProcessing() { // Reset the features and timeout. Reset(); TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutReason.KeepAlive); }
/// <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 ProcessRequestsAsync() { try { while (!_requestProcessingStopping) { TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutAction.CloseConnection); Reset(); while (!_requestProcessingStopping) { var result = await Input.ReadAsync(); var examined = result.Buffer.End; var consumed = result.Buffer.End; try { ParseRequest(result.Buffer, out consumed, out examined); } catch (InvalidOperationException) { if (_requestProcessingStatus == RequestProcessingStatus.ParsingHeaders) { throw BadHttpRequestException.GetException(RequestRejectionReason .MalformedRequestInvalidHeaders); } throw; } finally { Input.Advance(consumed, examined); } if (_requestProcessingStatus == RequestProcessingStatus.AppStarted) { break; } if (result.IsCompleted) { switch (_requestProcessingStatus) { case RequestProcessingStatus.RequestPending: return; case RequestProcessingStatus.ParsingRequestLine: throw BadHttpRequestException.GetException( RequestRejectionReason.InvalidRequestLine); case RequestProcessingStatus.ParsingHeaders: throw BadHttpRequestException.GetException( RequestRejectionReason.MalformedRequestInvalidHeaders); } } } if (!_requestProcessingStopping) { EnsureHostHeaderExists(); var messageBody = MessageBody.For(_httpVersion, FrameRequestHeaders, this); _keepAlive = messageBody.RequestKeepAlive; _upgradeAvailable = messageBody.RequestUpgrade; InitializeStreams(messageBody); var context = _application.CreateContext(this); try { try { KestrelEventSource.Log.RequestStart(this); await _application.ProcessRequestAsync(context); if (Volatile.Read(ref _requestAborted) == 0) { VerifyResponseContentLength(); } } catch (Exception ex) { ReportApplicationError(ex); if (ex is BadHttpRequestException) { throw; } } finally { KestrelEventSource.Log.RequestStop(this); // 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 (!HasResponseStarted && _applicationException == null && _onStarting != null) { await FireOnStarting(); } PauseStreams(); if (_onCompleted != null) { await FireOnCompleted(); } } // If _requestAbort is set, the connection has already been closed. if (Volatile.Read(ref _requestAborted) == 0) { if (HasResponseStarted) { // If the response has already started, call ProduceEnd() before // consuming the rest of the request body to prevent // delaying clients waiting for the chunk terminator: // // https://github.com/dotnet/corefx/issues/17330#issuecomment-288248663 // // ProduceEnd() must be called before _application.DisposeContext(), to ensure // HttpContext.Response.StatusCode is correctly set when // IHttpContextFactory.Dispose(HttpContext) is called. await ProduceEnd(); } // ForZeroContentLength does not complete the reader nor the writer if (!messageBody.IsEmpty && _keepAlive) { // Finish reading the request body in case the app did not. TimeoutControl.SetTimeout(Constants.RequestBodyDrainTimeout.Ticks, TimeoutAction.SendTimeoutResponse); await messageBody.ConsumeAsync(); TimeoutControl.CancelTimeout(); } if (!HasResponseStarted) { await ProduceEnd(); } } else if (!HasResponseStarted) { // If the request was aborted and no response was sent, there's no // meaningful status code to log. StatusCode = 0; } } catch (BadHttpRequestException ex) { // Handle BadHttpRequestException thrown during app execution or remaining message body consumption. // This has to be caught here so StatusCode is set properly before disposing the HttpContext // (DisposeContext logs StatusCode). SetBadRequestState(ex); } finally { _application.DisposeContext(context, _applicationException); // StopStreams should be called before the end of the "if (!_requestProcessingStopping)" block // to ensure InitializeStreams has been called. StopStreams(); if (HasStartedConsumingRequestBody) { RequestBodyPipe.Reader.Complete(); // Wait for MessageBody.PumpAsync() to call RequestBodyPipe.Writer.Complete(). await messageBody.StopAsync(); // At this point both the request body pipe reader and writer should be completed. RequestBodyPipe.Reset(); } } } if (!_keepAlive) { // End the connection for non keep alive as data incoming may have been thrown off return; } } } catch (BadHttpRequestException ex) { // Handle BadHttpRequestException thrown during request line or header parsing. // SetBadRequestState logs the error. SetBadRequestState(ex); } catch (ConnectionResetException ex) { // Don't log ECONNRESET errors made between requests. Browsers like IE will reset connections regularly. if (_requestProcessingStatus != RequestProcessingStatus.RequestPending) { Log.RequestProcessingError(ConnectionId, ex); } } catch (IOException ex) { Log.RequestProcessingError(ConnectionId, ex); } catch (Exception ex) { Log.LogWarning(0, ex, CoreStrings.RequestProcessingEndError); } finally { try { Input.Complete(); // If _requestAborted is set, the connection has already been closed. if (Volatile.Read(ref _requestAborted) == 0) { await TryProduceInvalidRequestResponse(); Output.Dispose(); } } catch (Exception ex) { Log.LogWarning(0, ex, CoreStrings.ConnectionShutdownError); } } }
public Http3TestBase() { _timeoutControl = new TimeoutControl(_mockTimeoutHandler.Object); _mockTimeoutControl = new Mock <MockTimeoutControlBase>(_timeoutControl) { CallBase = true }; _timeoutControl.Debugger = Mock.Of <IDebugger>(); _mockKestrelTrace .Setup(m => m.Http3ConnectionClosed(It.IsAny <string>(), It.IsAny <long>())) .Callback(() => _closedStateReached.SetResult()); _serverReceivedSettings = Channel.CreateUnbounded <KeyValuePair <Internal.Http3.Http3SettingType, long> >(); _noopApplication = context => Task.CompletedTask; _echoApplication = async context => { var buffer = new byte[16 * 1024]; var received = 0; while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) { await context.Response.Body.WriteAsync(buffer, 0, received); } }; _readRateApplication = async context => { var expectedBytes = int.Parse(context.Request.Path.Value.Substring(1), CultureInfo.InvariantCulture); var buffer = new byte[16 * 1024]; var received = 0; while (received < expectedBytes) { received += await context.Request.Body.ReadAsync(buffer, 0, buffer.Length); } var stalledReadTask = context.Request.Body.ReadAsync(buffer, 0, buffer.Length); // Write to the response so the test knows the app started the stalled read. await context.Response.Body.WriteAsync(new byte[1], 0, 1); await stalledReadTask; }; _echoMethod = context => { context.Response.Headers["Method"] = context.Request.Method; return(Task.CompletedTask); }; _echoPath = context => { context.Response.Headers["path"] = context.Request.Path.ToString(); context.Response.Headers["rawtarget"] = context.Features.Get <IHttpRequestFeature>().RawTarget; return(Task.CompletedTask); }; _echoHost = context => { context.Response.Headers.Host = context.Request.Headers.Host; return(Task.CompletedTask); }; }
public TimeoutControlTests() { _mockTimeoutHandler = new Mock <ITimeoutHandler>(); _timeoutControl = new TimeoutControl(_mockTimeoutHandler.Object); _systemClock = new MockSystemClock(); }
public Http2TestBase() { // Always dispatch test code back to the ThreadPool. This prevents deadlocks caused by continuing // Http2Connection.ProcessRequestsAsync() loop with writer locks acquired. Run product code inline to make // it easier to verify request frames are processed correctly immediately after sending the them. var inputPipeOptions = new PipeOptions( pool: _memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.ThreadPool, useSynchronizationContext: false ); var outputPipeOptions = new PipeOptions( pool: _memoryPool, readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false ); _pair = DuplexPipe.CreateConnectionPair(inputPipeOptions, outputPipeOptions); _hpackDecoder = new HPackDecoder((int)_clientSettings.HeaderTableSize, MaxRequestHeaderFieldSize); _timeoutControl = new TimeoutControl(_mockTimeoutHandler.Object); _noopApplication = context => Task.CompletedTask; _readHeadersApplication = context => { foreach (var header in context.Request.Headers) { _receivedHeaders[header.Key] = header.Value.ToString(); } return(Task.CompletedTask); }; _readTrailersApplication = async context => { using (var ms = new MemoryStream()) { // Consuming the entire request body guarantees trailers will be available await context.Request.Body.CopyToAsync(ms); } foreach (var header in context.Request.Headers) { _receivedHeaders[header.Key] = header.Value.ToString(); } }; _bufferingApplication = async context => { var data = new List <byte>(); var buffer = new byte[1024]; var received = 0; while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) { data.AddRange(new ArraySegment <byte>(buffer, 0, received)); } await context.Response.Body.WriteAsync(data.ToArray(), 0, data.Count); }; _echoApplication = async context => { var buffer = new byte[Http2PeerSettings.MinAllowedMaxFrameSize]; var received = 0; while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) { await context.Response.Body.WriteAsync(buffer, 0, received); } }; _echoWaitForAbortApplication = async context => { var buffer = new byte[Http2PeerSettings.MinAllowedMaxFrameSize]; var received = 0; while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) { await context.Response.Body.WriteAsync(buffer, 0, received); } var sem = new SemaphoreSlim(0); context.RequestAborted.Register(() => { sem.Release(); }); await sem.WaitAsync().DefaultTimeout(); }; _largeHeadersApplication = context => { foreach (var name in new[] { "a", "b", "c", "d", "e", "f", "g", "h" }) { context.Response.Headers[name] = _4kHeaderValue; } return(Task.CompletedTask); }; _waitForAbortApplication = async context => { var streamIdFeature = context.Features.Get <IHttp2StreamIdFeature>(); var sem = new SemaphoreSlim(0); context.RequestAborted.Register(() => { lock (_abortedStreamIdsLock) { _abortedStreamIds.Add(streamIdFeature.StreamId); } sem.Release(); }); await sem.WaitAsync().DefaultTimeout(); _runningStreams[streamIdFeature.StreamId].TrySetResult(null); }; _waitForAbortFlushingApplication = async context => { var streamIdFeature = context.Features.Get <IHttp2StreamIdFeature>(); var sem = new SemaphoreSlim(0); context.RequestAborted.Register(() => { lock (_abortedStreamIdsLock) { _abortedStreamIds.Add(streamIdFeature.StreamId); } sem.Release(); }); await sem.WaitAsync().DefaultTimeout(); await context.Response.Body.FlushAsync(); _runningStreams[streamIdFeature.StreamId].TrySetResult(null); }; _waitForAbortWithDataApplication = async context => { var streamIdFeature = context.Features.Get <IHttp2StreamIdFeature>(); var sem = new SemaphoreSlim(0); context.RequestAborted.Register(() => { lock (_abortedStreamIdsLock) { _abortedStreamIds.Add(streamIdFeature.StreamId); } sem.Release(); }); await sem.WaitAsync().DefaultTimeout(); await context.Response.Body.WriteAsync(new byte[10], 0, 10); _runningStreams[streamIdFeature.StreamId].TrySetResult(null); }; _echoMethod = context => { context.Response.Headers["Method"] = context.Request.Method; return(Task.CompletedTask); }; _echoHost = context => { context.Response.Headers[HeaderNames.Host] = context.Request.Headers[HeaderNames.Host]; return(Task.CompletedTask); }; _echoPath = context => { context.Response.Headers["path"] = context.Request.Path.ToString(); context.Response.Headers["rawtarget"] = context.Features.Get <IHttpRequestFeature>().RawTarget; return(Task.CompletedTask); }; }