Пример #1
0
 public TimingPipeFlusher(
     ITimeoutControl?timeoutControl,
     KestrelTrace log)
 {
     _timeoutControl = timeoutControl;
     _log            = log;
 }
Пример #2
0
        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);
        }
Пример #5
0
        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);
                }
        }
Пример #6
0
        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);
                }
        }
Пример #7
0
    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();
    }
Пример #8
0
        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);
        }
Пример #9
0
        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,
            });
        }
Пример #10
0
 public Heartbeat(IHeartbeatHandler[] callbacks, ISystemClock systemClock, IDebugger debugger, KestrelTrace trace)
 {
     _callbacks   = callbacks;
     _systemClock = systemClock;
     _debugger    = debugger;
     _trace       = trace;
     _interval    = Interval;
 }
Пример #11
0
        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);
                    }
                }
        }
Пример #12
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);
                }
        }
Пример #13
0
        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));
                }
        }
Пример #14
0
        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
            });
        }
Пример #15
0
 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
     };
 }
Пример #16
0
        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
            };
        }
Пример #17
0
        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);
                }
        }
Пример #18
0
 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);
 }
Пример #19
0
        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);
                }
        }
Пример #20
0
    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);
    }
Пример #21
0
        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);
        }
Пример #22
0
        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));
            }
        }
Пример #24
0
    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);
    }
Пример #25
0
    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;
    }
Пример #26
0
    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();
    }
Пример #27
0
        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"));
        }
Пример #28
0
    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();
    }
Пример #29
0
    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
        });
    }
Пример #30
0
        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);
        }