public TimingPipeFlusher( ITimeoutControl?timeoutControl, KestrelTrace log) { _timeoutControl = timeoutControl; _log = log; }
public void EmptyHeaderValuesCanBeParsed(string rawHeaders, int numHeaders) { var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); using (var pool = new MemoryPool()) using (var socketInput = new SocketInput(pool, ltp)) { var connectionContext = new ConnectionContext() { DateHeaderValueManager = new DateHeaderValueManager(), ServerAddress = ServerAddress.FromUrl("http://localhost:5000") }; var frame = new Frame <object>(application: null, context: connectionContext); var headerCollection = new FrameRequestHeaders(); var headerArray = Encoding.ASCII.GetBytes(rawHeaders); socketInput.IncomingData(headerArray, 0, headerArray.Length); var success = frame.TakeMessageHeaders(socketInput, headerCollection); Assert.True(success); Assert.Equal(numHeaders, headerCollection.Count()); // Assert TakeMessageHeaders consumed all the input var scan = socketInput.ConsumingStart(); Assert.True(scan.IsEnd); } }
public void GetDateHeaderValue_ReturnsUpdatedValueAfterHeartbeat() { var now = DateTimeOffset.UtcNow; var future = now.AddSeconds(10); var systemClock = new MockSystemClock { UtcNow = now }; var dateHeaderValueManager = new DateHeaderValueManager(); dateHeaderValueManager.OnHeartbeat(now); var testKestrelTrace = new KestrelTrace(NullLoggerFactory.Instance); var mockHeartbeatHandler = new Mock <IHeartbeatHandler>(); using (var heartbeat = new Heartbeat(new[] { dateHeaderValueManager, mockHeartbeatHandler.Object }, systemClock, DebuggerWrapper.Singleton, testKestrelTrace)) { heartbeat.OnHeartbeat(); Assert.Equal(now.ToString(Rfc1123DateFormat), dateHeaderValueManager.GetDateHeaderValues().String); // Wait for the next heartbeat before verifying GetDateHeaderValues picks up new time. systemClock.UtcNow = future; heartbeat.OnHeartbeat(); Assert.Equal(future.ToString(Rfc1123DateFormat), dateHeaderValueManager.GetDateHeaderValues().String); Assert.Equal(4, systemClock.UtcNowCalled); } }
private void UnrootedConnectionsGetRemovedFromHeartbeatInnerScope( string connectionId, ConnectionManager httpConnectionManager, KestrelTrace trace) { var serviceContext = new TestServiceContext(); var mock = new Mock <DefaultConnectionContext>() { CallBase = true }; mock.Setup(m => m.ConnectionId).Returns(connectionId); var transportConnectionManager = new TransportConnectionManager(httpConnectionManager); var httpConnection = new KestrelConnection <ConnectionContext>(0, serviceContext, transportConnectionManager, _ => Task.CompletedTask, mock.Object, trace); transportConnectionManager.AddConnection(0, httpConnection); var connectionCount = 0; httpConnectionManager.Walk(_ => connectionCount++); Assert.Equal(1, connectionCount); Assert.Empty(TestSink.Writes.Where(c => c.EventId.Name == "ApplicationNeverCompleted")); // Ensure httpConnection doesn't get GC'd before this point. GC.KeepAlive(httpConnection); }
public void LeadingWhitespaceIsNotIncludedInHeaderValue(string rawHeaders) { var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); using (var pool = new MemoryPool()) using (var socketInput = new SocketInput(pool, ltp)) { var connectionContext = new ConnectionContext() { DateHeaderValueManager = new DateHeaderValueManager(), ServerAddress = ServerAddress.FromUrl("http://localhost:5000") }; var frame = new Frame <object>(application: null, context: connectionContext); frame.InitializeHeaders(); var headerArray = Encoding.ASCII.GetBytes(rawHeaders); socketInput.IncomingData(headerArray, 0, headerArray.Length); var success = frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders); Assert.True(success); Assert.Equal(1, frame.RequestHeaders.Count); Assert.Equal("value", frame.RequestHeaders["Header"]); // Assert TakeMessageHeaders consumed all the input var scan = socketInput.ConsumingStart(); Assert.True(scan.IsEnd); } }
public void ProducingStartAndProducingCompleteCanBeCalledAfterConnectionClose() { var mockLibuv = new MockLibuv(); using (var memory = new MemoryPool()) using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext())) { kestrelEngine.Start(count: 1); var kestrelThread = kestrelEngine.Threads[0]; var socket = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace()); var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); var connection = new MockConnection(); var socketOutput = new SocketOutput(kestrelThread, socket, memory, connection, "0", trace, ltp, new Queue <UvWriteReq>()); // Close SocketOutput var cleanupTask = socketOutput.WriteAsync( default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true); Assert.True(connection.SocketClosed.Wait(1000)); var start = socketOutput.ProducingStart(); Assert.True(start.IsDefault); // ProducingComplete should not throw given a default iterator socketOutput.ProducingComplete(start); } }
public TestInput(KestrelTrace log = null, ITimeoutControl timeoutControl = null) { _memoryPool = PinnedBlockMemoryPoolFactory.Create(); var options = new PipeOptions(pool: _memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); var pair = DuplexPipe.CreateConnectionPair(options, options); Transport = pair.Transport; Application = pair.Application; var connectionFeatures = new FeatureCollection(); connectionFeatures.Set(Mock.Of <IConnectionLifetimeFeature>()); Http1ConnectionContext = TestContextFactory.CreateHttpConnectionContext( serviceContext: new TestServiceContext { Log = log ?? new KestrelTrace(NullLoggerFactory.Instance) }, connectionContext: Mock.Of <ConnectionContext>(), transport: Transport, timeoutControl: timeoutControl ?? Mock.Of <ITimeoutControl>(), memoryPool: _memoryPool, connectionFeatures: connectionFeatures); Http1Connection = new Http1Connection(Http1ConnectionContext); Http1Connection.HttpResponseControl = Mock.Of <IHttpResponseControl>(); Http1Connection.Reset(); }
public Http2FrameWriter( PipeWriter outputPipeWriter, BaseConnectionContext connectionContext, Http2Connection http2Connection, OutputFlowControl connectionOutputFlowControl, ITimeoutControl timeoutControl, MinDataRate?minResponseDataRate, string connectionId, MemoryPool <byte> memoryPool, ServiceContext serviceContext) { // Allow appending more data to the PipeWriter when a flush is pending. _outputWriter = new ConcurrentPipeWriter(outputPipeWriter, memoryPool, _writeLock); _connectionContext = connectionContext; _http2Connection = http2Connection; _connectionOutputFlowControl = connectionOutputFlowControl; _connectionId = connectionId; _log = serviceContext.Log; _timeoutControl = timeoutControl; _minResponseDataRate = minResponseDataRate; _flusher = new TimingPipeFlusher(timeoutControl, serviceContext.Log); _flusher.Initialize(_outputWriter); _outgoingFrame = new Http2Frame(); _headerEncodingBuffer = new byte[_maxFrameSize]; _scheduleInline = serviceContext.Scheduler == PipeScheduler.Inline; _hpackEncoder = new DynamicHPackEncoder(serviceContext.ServerOptions.AllowResponseHeaderCompression); }
private static ServiceContext CreateServiceContext(IOptions <KestrelServerOptions> options, ILoggerFactory loggerFactory) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } var serverOptions = options.Value ?? new KestrelServerOptions(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel"); var trace = new KestrelTrace(logger); var connectionManager = new HttpConnectionManager( trace, serverOptions.Limits.MaxConcurrentUpgradedConnections); var systemClock = new SystemClock(); var dateHeaderValueManager = new DateHeaderValueManager(systemClock); var httpHeartbeatManager = new HttpHeartbeatManager(connectionManager); var heartbeat = new Heartbeat( new IHeartbeatHandler[] { dateHeaderValueManager, httpHeartbeatManager }, systemClock, DebuggerWrapper.Singleton, trace); // TODO: This logic will eventually move into the IConnectionHandler<T> and off // the service context once we get to https://github.com/aspnet/KestrelHttpServer/issues/1662 PipeScheduler scheduler = null; switch (serverOptions.ApplicationSchedulingMode) { case SchedulingMode.Default: case SchedulingMode.ThreadPool: scheduler = PipeScheduler.ThreadPool; break; case SchedulingMode.Inline: scheduler = PipeScheduler.Inline; break; default: throw new NotSupportedException(CoreStrings.FormatUnknownTransportMode(serverOptions.ApplicationSchedulingMode)); } return(new ServiceContext { Log = trace, HttpParser = new HttpParser <Http1ParsingHandler>(trace.IsEnabled(LogLevel.Information)), Scheduler = scheduler, SystemClock = systemClock, DateHeaderValueManager = dateHeaderValueManager, ConnectionManager = connectionManager, Heartbeat = heartbeat, ServerOptions = serverOptions, }); }
public Heartbeat(IHeartbeatHandler[] callbacks, ISystemClock systemClock, IDebugger debugger, KestrelTrace trace) { _callbacks = callbacks; _systemClock = systemClock; _debugger = debugger; _trace = trace; _interval = Interval; }
public void OnlyAllowsUpToThreeConcurrentWrites() { var writeWh = new ManualResetEventSlim(); var completeQueue = new Queue <Action <int> >(); var mockLibuv = new MockLibuv { OnWrite = (socket, buffers, triggerCompleted) => { writeWh.Set(); completeQueue.Enqueue(triggerCompleted); return(0); } }; using (var memory = new MemoryPool()) using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext())) { kestrelEngine.Start(count: 1); var kestrelThread = kestrelEngine.Threads[0]; var socket = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace()); var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); var socketOutput = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>()); var buffer = new ArraySegment <byte>(new byte[1]); // First three writes trigger uv_write socketOutput.WriteAsync(buffer, CancellationToken.None); Assert.True(writeWh.Wait(1000)); writeWh.Reset(); socketOutput.WriteAsync(buffer, CancellationToken.None); Assert.True(writeWh.Wait(1000)); writeWh.Reset(); socketOutput.WriteAsync(buffer, CancellationToken.None); Assert.True(writeWh.Wait(1000)); writeWh.Reset(); // The fourth write won't trigger uv_write since the first three haven't completed socketOutput.WriteAsync(buffer, CancellationToken.None); Assert.False(writeWh.Wait(1000)); // Complete 1st write allowing uv_write to be triggered again completeQueue.Dequeue()(0); Assert.True(writeWh.Wait(1000)); // Cleanup var cleanupTask = socketOutput.WriteAsync( default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true); foreach (var triggerCompleted in completeQueue) { triggerCompleted(0); } } }
public void WritesAreAggregated() { var writeWh = new ManualResetEventSlim(); var writeCount = 0; var mockLibuv = new MockLibuv { OnWrite = (socket, buffers, triggerCompleted) => { writeCount++; triggerCompleted(0); writeWh.Set(); return(0); } }; using (var memory = new MemoryPool()) using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext())) { kestrelEngine.Start(count: 1); var kestrelThread = kestrelEngine.Threads[0]; var socket = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace()); var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); var socketOutput = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>()); var blockThreadWh = new ManualResetEventSlim(); kestrelThread.Post(_ => { blockThreadWh.Wait(); }, state: null); var buffer = new ArraySegment <byte>(new byte[1]); // Two calls to WriteAsync trigger uv_write once if both calls // are made before write is scheduled socketOutput.WriteAsync(buffer, CancellationToken.None); socketOutput.WriteAsync(buffer, CancellationToken.None); blockThreadWh.Set(); Assert.True(writeWh.Wait(1000)); writeWh.Reset(); // Write isn't called twice after the thread is unblocked Assert.False(writeWh.Wait(1000)); Assert.Equal(1, writeCount); // One call to ScheduleWrite + One call to Post to block the thread Assert.Equal(2, mockLibuv.PostCount); // Cleanup var cleanupTask = socketOutput.WriteAsync( default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true); } }
public void WritesDontCompleteImmediatelyWhenTooManyBytesAreAlreadyPreCompleted() { // This should match _maxBytesPreCompleted in SocketOutput var maxBytesPreCompleted = 65536; var completeQueue = new Queue <Action <int> >(); // Arrange var mockLibuv = new MockLibuv { OnWrite = (socket, buffers, triggerCompleted) => { completeQueue.Enqueue(triggerCompleted); return(0); } }; using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext())) using (var memory = new MemoryPool2()) { kestrelEngine.Start(count: 1); var kestrelThread = kestrelEngine.Threads[0]; var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace()); var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue <UvWriteReq>()); var bufferSize = maxBytesPreCompleted; var buffer = new ArraySegment <byte>(new byte[bufferSize], 0, bufferSize); var completedWh = new ManualResetEventSlim(); Action <Task> onCompleted = (Task t) => { Assert.Null(t.Exception); completedWh.Set(); }; // Act socketOutput.WriteAsync(buffer).ContinueWith(onCompleted); // Assert // The first write should pre-complete since it is <= _maxBytesPreCompleted. Assert.True(completedWh.Wait(1000)); // Arrange completedWh.Reset(); // Act socketOutput.WriteAsync(buffer).ContinueWith(onCompleted); // Assert // Too many bytes are already pre-completed for the second write to pre-complete. Assert.False(completedWh.Wait(1000)); // Act completeQueue.Dequeue()(0); // Assert // Finishing the first write should allow the second write to pre-complete. Assert.True(completedWh.Wait(1000)); } }
private static ServiceContext CreateServiceContext(IOptions <KestrelServerOptions> options, ILoggerFactory loggerFactory) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } var serverOptions = options.Value ?? new KestrelServerOptions(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel"); var trace = new KestrelTrace(logger); var connectionManager = new FrameConnectionManager( trace, serverOptions.Limits.MaxConcurrentConnections, serverOptions.Limits.MaxConcurrentUpgradedConnections); var systemClock = new SystemClock(); var dateHeaderValueManager = new DateHeaderValueManager(systemClock); // TODO: This logic will eventually move into the IConnectionHandler<T> and off // the service context once we get to https://github.com/aspnet/KestrelHttpServer/issues/1662 IThreadPool threadPool = null; switch (serverOptions.ApplicationSchedulingMode) { case SchedulingMode.Default: case SchedulingMode.ThreadPool: threadPool = new LoggingThreadPool(trace); break; case SchedulingMode.Inline: threadPool = new InlineLoggingThreadPool(trace); break; default: throw new NotSupportedException(CoreStrings.FormatUnknownTransportMode(serverOptions.ApplicationSchedulingMode)); } return(new ServiceContext { Log = trace, HttpParserFactory = frameParser => new HttpParser <FrameAdapter>(frameParser.Frame.ServiceContext.Log.IsEnabled(LogLevel.Information)), ThreadPool = threadPool, SystemClock = systemClock, DateHeaderValueManager = dateHeaderValueManager, ConnectionManager = connectionManager, ServerOptions = serverOptions }); }
public Heartbeat(IHeartbeatHandler[] callbacks, ISystemClock systemClock, IDebugger debugger, KestrelTrace trace) { _callbacks = callbacks; _systemClock = systemClock; _debugger = debugger; _trace = trace; _interval = Interval; _timerThread = new Thread(state => ((Heartbeat)state !).TimerLoop()) { Name = "Kestrel Timer", IsBackground = true }; }
public TestInput() { var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); var memory2 = new MemoryPool2(); FrameContext = new FrameContext { SocketInput = new SocketInput(memory2, ltp), ConnectionControl = this, FrameControl = this }; }
public void ProducingStartAndProducingCompleteCanBeUsedDirectly() { int nBuffers = 0; var nBufferWh = new ManualResetEventSlim(); var mockLibuv = new MockLibuv { OnWrite = (socket, buffers, triggerCompleted) => { nBuffers = buffers; nBufferWh.Set(); triggerCompleted(0); return(0); } }; using (var memory = new MemoryPool()) using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext())) { kestrelEngine.Start(count: 1); var kestrelThread = kestrelEngine.Threads[0]; var socket = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace()); var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); var socketOutput = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>()); // block 1 var start = socketOutput.ProducingStart(); start.Block.End = start.Block.Data.Offset + start.Block.Data.Count; // block 2 var block2 = memory.Lease(); block2.End = block2.Data.Offset + block2.Data.Count; start.Block.Next = block2; var end = new MemoryPoolIterator(block2, block2.End); socketOutput.ProducingComplete(end); // A call to Write is required to ensure a write is scheduled socketOutput.WriteAsync(default(ArraySegment <byte>), default(CancellationToken)); Assert.True(nBufferWh.Wait(1000)); Assert.Equal(2, nBuffers); // Cleanup var cleanupTask = socketOutput.WriteAsync( default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true); } }
public KestrelConnection(long id, ServiceContext serviceContext, TransportConnectionManager transportConnectionManager, Func <T, Task> connectionDelegate, T connectionContext, KestrelTrace logger) : base(id, serviceContext, transportConnectionManager, logger) { _connectionDelegate = connectionDelegate; _transportConnection = connectionContext; connectionContext.Features.Set <IConnectionHeartbeatFeature>(this); connectionContext.Features.Set <IConnectionCompleteFeature>(this); connectionContext.Features.Set <IConnectionLifetimeNotificationFeature>(this); }
public void CanWrite1MB() { // This test was added because when initially implementing write-behind buffering in // SocketOutput, the write callback would never be invoked for writes larger than // _maxBytesPreCompleted even after the write actually completed. // Arrange var mockLibuv = new MockLibuv { OnWrite = (socket, buffers, triggerCompleted) => { triggerCompleted(0); return(0); } }; using (var memory = new MemoryPool()) using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext())) { kestrelEngine.Start(count: 1); var kestrelThread = kestrelEngine.Threads[0]; var socket = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace()); var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); var socketOutput = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>()); // I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test. var bufferSize = 1048576; var buffer = new ArraySegment <byte>(new byte[bufferSize], 0, bufferSize); var completedWh = new ManualResetEventSlim(); // Act socketOutput.WriteAsync(buffer, default(CancellationToken)).ContinueWith( (t) => { Assert.Null(t.Exception); completedWh.Set(); } ); // Assert Assert.True(completedWh.Wait(1000)); // Cleanup var cleanupTask = socketOutput.WriteAsync( default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true); } }
public void ExceptionFromHeartbeatHandlerIsLoggedAsError() { var systemClock = new MockSystemClock(); var heartbeatHandler = new Mock <IHeartbeatHandler>(); var kestrelTrace = new KestrelTrace(LoggerFactory); var ex = new Exception(); heartbeatHandler.Setup(h => h.OnHeartbeat(systemClock.UtcNow)).Throws(ex); using (var heartbeat = new Heartbeat(new[] { heartbeatHandler.Object }, systemClock, DebuggerWrapper.Singleton, kestrelTrace)) { heartbeat.OnHeartbeat(); } Assert.Equal(ex, TestSink.Writes.Single(message => message.LogLevel == LogLevel.Error).Exception); }
private void Initialize(ILoggerFactory loggerFactory, KestrelTrace kestrelTrace) { LoggerFactory = loggerFactory; Log = kestrelTrace; Scheduler = PipeScheduler.ThreadPool; MockSystemClock = new MockSystemClock(); SystemClock = MockSystemClock; DateHeaderValueManager = new DateHeaderValueManager(); ConnectionManager = new ConnectionManager(Log, ResourceCounter.Unlimited); HttpParser = new HttpParser <Http1ParsingHandler>(Log.IsEnabled(LogLevel.Information)); ServerOptions = new KestrelServerOptions { AddServerHeader = false }; DateHeaderValueManager.OnHeartbeat(SystemClock.UtcNow); }
public TestInput() { var trace = new KestrelTrace(new TestKestrelTrace()); var ltp = new LoggingThreadPool(trace); var context = new FrameContext() { DateHeaderValueManager = new DateHeaderValueManager(), ServerAddress = ServerAddress.FromUrl("http://localhost:5000"), ConnectionControl = this, FrameControl = this }; FrameContext = new Frame <object>(null, context); _memoryPool = new MemoryPool(); FrameContext.SocketInput = new SocketInput(_memoryPool, ltp); }
public void CanWrite1MB() { // This test was added because when initially implementing write-behind buffering in // SocketOutput, the write callback would never be invoked for writes larger than // _maxBytesPreCompleted even after the write actually completed. // Arrange var mockLibuv = new MockLibuv { OnWrite = (socket, buffers, triggerCompleted) => { triggerCompleted(0); return(0); } }; using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext())) { kestrelEngine.Start(count: 1); var kestrelThread = kestrelEngine.Threads[0]; var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace()); var trace = new KestrelTrace(new TestKestrelTrace()); var socketOutput = new SocketOutput(kestrelThread, socket, 0, trace); // I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test. var bufferSize = 1048576; var buffer = new ArraySegment <byte>(new byte[bufferSize], 0, bufferSize); var completedWh = new ManualResetEventSlim(); Action <Exception, object, bool> onCompleted = (ex, state, calledInline) => { Assert.Null(ex); Assert.Null(state); completedWh.Set(); }; // Act socketOutput.Write(buffer, onCompleted, null); // Assert Assert.True(completedWh.Wait(1000)); } }
public async Task HeartbeatTakingLongerThanIntervalIsLoggedAsWarning() { var systemClock = new MockSystemClock(); var heartbeatHandler = new Mock <IHeartbeatHandler>(); var debugger = new Mock <IDebugger>(); var kestrelTrace = new KestrelTrace(LoggerFactory); var handlerMre = new ManualResetEventSlim(); var handlerStartedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var now = systemClock.UtcNow; var heartbeatDuration = TimeSpan.FromSeconds(2); heartbeatHandler.Setup(h => h.OnHeartbeat(now)).Callback(() => { handlerStartedTcs.SetResult(); handlerMre.Wait(); }); debugger.Setup(d => d.IsAttached).Returns(false); Task blockedHeartbeatTask; using (var heartbeat = new Heartbeat(new[] { heartbeatHandler.Object }, systemClock, debugger.Object, kestrelTrace)) { blockedHeartbeatTask = Task.Run(() => heartbeat.OnHeartbeat()); await handlerStartedTcs.Task.DefaultTimeout(); } // 2 seconds passes... systemClock.UtcNow = systemClock.UtcNow.AddSeconds(2); handlerMre.Set(); await blockedHeartbeatTask.DefaultTimeout(); heartbeatHandler.Verify(h => h.OnHeartbeat(now), Times.Once()); var warningMessage = TestSink.Writes.Single(message => message.LogLevel == LogLevel.Warning).Message; Assert.Equal($"As of \"{now.ToString(CultureInfo.InvariantCulture)}\", the heartbeat has been running for " + $"\"{heartbeatDuration.ToString("c", CultureInfo.InvariantCulture)}\" which is longer than " + $"\"{Heartbeat.Interval.ToString("c", CultureInfo.InvariantCulture)}\". " + "This could be caused by thread pool starvation.", warningMessage); }
public Http2OutputProducer(Http2Stream stream, Http2StreamContext context) { _stream = stream; _frameWriter = context.FrameWriter; _memoryPool = context.MemoryPool; _log = context.ServiceContext.Log; var scheduleInline = context.ServiceContext.Scheduler == PipeScheduler.Inline; _pipe = CreateDataPipe(_memoryPool, scheduleInline); _pipeWriter = new ConcurrentPipeWriter(_pipe.Writer, _memoryPool, _dataWriterLock); _pipeReader = _pipe.Reader; // No need to pass in timeoutControl here, since no minDataRates are passed to the TimingPipeFlusher. // The minimum output data rate is enforced at the connection level by Http2FrameWriter. _flusher = new TimingPipeFlusher(timeoutControl: null, _log); _flusher.Initialize(_pipeWriter); _streamWindow = context.ClientPeerSettings.InitialWindowSize; }
public Http3OutputProducer( Http3FrameWriter frameWriter, MemoryPool <byte> pool, Http3Stream stream, KestrelTrace log) { _frameWriter = frameWriter; _memoryPool = pool; _stream = stream; _log = log; _pipe = CreateDataPipe(pool); _pipeWriter = _pipe.Writer; _pipeReader = _pipe.Reader; _flusher = new TimingPipeFlusher(timeoutControl: null, log); _flusher.Initialize(_pipeWriter); _dataWriteProcessingTask = ProcessDataWrites().Preserve(); }
public void UnrootedConnectionsGetRemovedFromHeartbeat() { var trace = new KestrelTrace(LoggerFactory); var connectionId = "0"; var httpConnectionManager = new ConnectionManager(trace, ResourceCounter.Unlimited); // Create HttpConnection in inner scope so it doesn't get rooted by the current frame. UnrootedConnectionsGetRemovedFromHeartbeatInnerScope(connectionId, httpConnectionManager, trace); GC.Collect(); GC.WaitForPendingFinalizers(); var connectionCount = 0; httpConnectionManager.Walk(_ => connectionCount++); Assert.Equal(0, connectionCount); Assert.Single(TestSink.Writes.Where(c => c.EventId.Name == "ApplicationNeverCompleted")); }
public Http2OutputProducer(Http2Stream stream, Http2StreamContext context, StreamOutputFlowControl flowControl) { _stream = stream; _frameWriter = context.FrameWriter; _flowControl = flowControl; _memoryPool = context.MemoryPool; _log = context.ServiceContext.Log; _pipe = CreateDataPipe(_memoryPool); _pipeWriter = new ConcurrentPipeWriter(_pipe.Writer, _memoryPool, _dataWriterLock); _pipeReader = _pipe.Reader; // No need to pass in timeoutControl here, since no minDataRates are passed to the TimingPipeFlusher. // The minimum output data rate is enforced at the connection level by Http2FrameWriter. _flusher = new TimingPipeFlusher(timeoutControl: null, _log); _flusher.Initialize(_pipeWriter); _dataWriteProcessingTask = ProcessDataWrites(); }
private static ServiceContext CreateServiceContext(IOptions <KestrelServerOptions> options, ILoggerFactory loggerFactory, DiagnosticSource?diagnosticSource) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } var serverOptions = options.Value ?? new KestrelServerOptions(); var trace = new KestrelTrace(loggerFactory); var connectionManager = new ConnectionManager( trace, serverOptions.Limits.MaxConcurrentUpgradedConnections); var heartbeatManager = new HeartbeatManager(connectionManager); var dateHeaderValueManager = new DateHeaderValueManager(); var heartbeat = new Heartbeat( new IHeartbeatHandler[] { dateHeaderValueManager, heartbeatManager }, new SystemClock(), DebuggerWrapper.Singleton, trace); return(new ServiceContext { Log = trace, Scheduler = PipeScheduler.ThreadPool, HttpParser = new HttpParser <Http1ParsingHandler>(trace.IsEnabled(LogLevel.Information)), SystemClock = heartbeatManager, DateHeaderValueManager = dateHeaderValueManager, ConnectionManager = connectionManager, Heartbeat = heartbeat, ServerOptions = serverOptions, DiagnosticSource = diagnosticSource }); }
private void RunLoop() { Uv = new Libuv(); Log = new KestrelTrace(new LoggerFactory().CreateLogger <UvTcpListener>()); Loop = new UvLoopHandle(Log); Loop.Init(Uv); _shutdownPostHandle = new UvAsyncHandle(Log); _shutdownPostHandle.Init(Loop, OnPost, _queueCloseCallback); _listenSocket = new UvTcpHandle(Log); _listenSocket.Init(Loop, _queueCloseCallback); _listenSocket.NoDelay(true); string host = null; if (_ip == IPAddress.Any) { host = "*"; } else if (_ip == IPAddress.Loopback) { host = "localhost"; } else { host = _ip.ToString(); } var url = $"http://{host}:{_port}"; var address = Microsoft.AspNetCore.Server.Kestrel.ServerAddress.FromUrl(url); _listenSocket.Bind(address); _listenSocket.Listen(10, _onConnectionCallback, this); Uv.run(Loop, 0); }