diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs index 15f57a8076..3d335971e5 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http } // Don't initialize _frame until SocketInput and SocketOutput are set to their final values. - if (ConnectionFilter == null) + if (ServerInformation.ConnectionFilter == null) { SocketInput = _rawSocketInput; SocketOutput = _rawSocketOutput; @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http try { - ConnectionFilter.OnConnectionAsync(_filterContext).ContinueWith((task, state) => + ServerInformation.ConnectionFilter.OnConnectionAsync(_filterContext).ContinueWith((task, state) => { var connection = (Connection)state; diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs index b84f63e87f..f40d4a06ee 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs @@ -45,6 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http private readonly object _onStartingSync = new Object(); private readonly object _onCompletedSync = new Object(); + protected bool _poolingPermitted = true; private Headers _frameHeaders; private Streams _frameStreams; @@ -279,7 +280,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http DuplexStream = null; var frameStreams = _frameStreams; _frameStreams = null; - HttpComponentFactory.DisposeStreams(frameStreams, poolingPermitted: (poolingPermitted && ReuseStreams)); + HttpComponentFactory.DisposeStreams(frameStreams, poolingPermitted); } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/FrameOfT.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/FrameOfT.cs index 1c0191c6cb..affb4d5867 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/FrameOfT.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/FrameOfT.cs @@ -131,14 +131,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http } catch (Exception ex) { + // Error occurred, do not return components to pool + _poolingPermitted = false; Log.LogWarning(0, ex, "Connection processing ended abnormally"); } finally { - // Error occurred, do not return components to pool - ResetComponents(poolingPermitted: false); try { + ResetComponents(poolingPermitted: _poolingPermitted); _abortedCts = null; // If _requestAborted is set, the connection has already been closed. diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListener.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListener.cs index 4c0f8f19ba..fc845b5239 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListener.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListener.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { var socket = new UvTcpHandle(Log); socket.Init(Thread.Loop, Thread.QueueCloseHandle); - socket.NoDelay(NoDelay); + socket.NoDelay(ServerInformation.NoDelay); socket.Bind(ServerAddress); socket.Listen(Constants.ListenBacklog, (stream, status, error, state) => ConnectionCallback(stream, status, error, state), this); return socket; @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http try { acceptSocket.Init(Thread.Loop, Thread.QueueCloseHandle); - acceptSocket.NoDelay(NoDelay); + acceptSocket.NoDelay(ServerInformation.NoDelay); listenSocket.Accept(acceptSocket); DispatchConnection(acceptSocket); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListenerPrimary.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListenerPrimary.cs index 6c1697cfe8..e791d30568 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListenerPrimary.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListenerPrimary.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { var socket = new UvTcpHandle(Log); socket.Init(Thread.Loop, Thread.QueueCloseHandle); - socket.NoDelay(NoDelay); + socket.NoDelay(ServerInformation.NoDelay); socket.Bind(ServerAddress); socket.Listen(Constants.ListenBacklog, (stream, status, error, state) => ConnectionCallback(stream, status, error, state), this); return socket; @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http try { acceptSocket.Init(Thread.Loop, Thread.QueueCloseHandle); - acceptSocket.NoDelay(NoDelay); + acceptSocket.NoDelay(ServerInformation.NoDelay); listenSocket.Accept(acceptSocket); DispatchConnection(acceptSocket); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListenerSecondary.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListenerSecondary.cs index ce0616171b..d52ac62b7e 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListenerSecondary.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/TcpListenerSecondary.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { var acceptSocket = new UvTcpHandle(Log); acceptSocket.Init(Thread.Loop, Thread.QueueCloseHandle); - acceptSocket.NoDelay(NoDelay); + acceptSocket.NoDelay(ServerInformation.NoDelay); return acceptSocket; } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/IKestrelServerInformation.cs b/src/Microsoft.AspNetCore.Server.Kestrel/IKestrelServerInformation.cs index a08db08ea6..fa81591879 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/IKestrelServerInformation.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/IKestrelServerInformation.cs @@ -12,17 +12,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel bool NoDelay { get; set; } /// - /// Gets or sets a flag that instructs whether it is safe to - /// reuse the Request and Response objects + /// Gets or sets values that instruct whether it is safe to + /// pool the Request and Response objects, Headers etc /// for another request after the Response's OnCompleted callback has fired. - /// When this is set to true it is not safe to retain references to these streams after this event has fired. - /// It is false by default. + /// When these values are greater than zero it is not safe to retain references to feature components after this event has fired. + /// They are zero by default. /// - /// - /// When this is set to true it is not safe to retain references to these streams after this event has fired. - /// It is false by default. - /// - bool ReuseStreams { get; set; } + KestrelServerPoolingParameters PoolingParameters { get; } IConnectionFilter ConnectionFilter { get; set; } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/HttpComponentFactory.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/HttpComponentFactory.cs index 98cdfef311..f58102c1bb 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/HttpComponentFactory.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/HttpComponentFactory.cs @@ -2,17 +2,24 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Concurrent; -using Microsoft.AspNetCore.Server.Kestrel.Http; using System.Text; +using Microsoft.AspNetCore.Server.Kestrel.Http; namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure { class HttpComponentFactory : IHttpComponentFactory { - private const int _maxPooledComponents = 128; + private ConcurrentQueue _streamPool = new ConcurrentQueue(); private ConcurrentQueue _headerPool = new ConcurrentQueue(); + public IKestrelServerInformation ServerInformation { get; set; } + + public HttpComponentFactory(IKestrelServerInformation serverInformation) + { + ServerInformation = serverInformation; + } + public Streams CreateStreams(FrameContext owner) { Streams streams; @@ -29,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure public void DisposeStreams(Streams streams, bool poolingPermitted) { - if (poolingPermitted && _streamPool.Count < _maxPooledComponents) + if (poolingPermitted && _streamPool.Count < ServerInformation.PoolingParameters.MaxPooledStreams) { streams.Uninitialize(); @@ -53,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure public void DisposeHeaders(Headers headers, bool poolingPermitted) { - if (poolingPermitted && _headerPool.Count < _maxPooledComponents) + if (poolingPermitted && _headerPool.Count < ServerInformation.PoolingParameters.MaxPooledHeaders) { headers.Uninitialize(); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/IHttpComponentFactory.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/IHttpComponentFactory.cs index b02300774a..620c663fbb 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/IHttpComponentFactory.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/IHttpComponentFactory.cs @@ -7,6 +7,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure { interface IHttpComponentFactory { + IKestrelServerInformation ServerInformation { get; set; } + Streams CreateStreams(FrameContext owner); void DisposeStreams(Streams streams, bool poolingPermitted); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServer.cs b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServer.cs index 6e3826d971..b6768de672 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServer.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServer.cs @@ -54,9 +54,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel try { var information = (KestrelServerInformation)Features.Get(); + var componentFactory = Features.Get(); var dateHeaderValueManager = new DateHeaderValueManager(); var trace = new KestrelTrace(_logger); - var componentFactory = new HttpComponentFactory(); var engine = new KestrelEngine(new ServiceContext { FrameFactory = (context, remoteEP, localEP, prepareRequest) => @@ -67,9 +67,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel Log = trace, ThreadPool = new LoggingThreadPool(trace), DateHeaderValueManager = dateHeaderValueManager, - ConnectionFilter = information.ConnectionFilter, - NoDelay = information.NoDelay, - ReuseStreams = information.ReuseStreams, + ServerInformation = information, HttpComponentFactory = componentFactory }); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerInformation.cs b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerInformation.cs index 6f05a1da58..b1d4d335ab 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerInformation.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerInformation.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel Addresses = GetAddresses(configuration); ThreadCount = GetThreadCount(configuration); NoDelay = GetNoDelay(configuration); - ReuseStreams = GetReuseStreams(configuration); + PoolingParameters = new KestrelServerPoolingParameters(configuration); } public ICollection Addresses { get; } @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel public bool NoDelay { get; set; } - public bool ReuseStreams { get; set; } + public KestrelServerPoolingParameters PoolingParameters { get; } public IConnectionFilter ConnectionFilter { get; set; } @@ -110,18 +110,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel return true; } - - private static bool GetReuseStreams(IConfiguration configuration) - { - var reuseStreamsString = configuration["kestrel.reuseStreams"]; - - bool reuseStreams; - if (bool.TryParse(reuseStreamsString, out reuseStreams)) - { - return reuseStreams; - } - - return false; - } } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerPoolingParameters.cs b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerPoolingParameters.cs new file mode 100644 index 0000000000..9a019d1d94 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerPoolingParameters.cs @@ -0,0 +1,43 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Globalization; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.AspNetCore.Server.Kestrel +{ + public class KestrelServerPoolingParameters + { + public KestrelServerPoolingParameters(IConfiguration configuration) + { + if (configuration == null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + MaxPooledStreams = GetPooledCount(configuration["kestrel.maxPooledStreams"]); + MaxPooledHeaders = GetPooledCount(configuration["kestrel.maxPooledHeaders"]); + } + + public int MaxPooledStreams { get; set; } + + public int MaxPooledHeaders { get; set; } + + private static int GetPooledCount(string countString) + { + if (string.IsNullOrEmpty(countString)) + { + return 0; + } + + int count; + if (int.TryParse(countString, NumberStyles.Integer, CultureInfo.InvariantCulture, out count)) + { + return count; + } + + return 0; + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/ServerFactory.cs b/src/Microsoft.AspNetCore.Server.Kestrel/ServerFactory.cs index 06a7fb3686..c6bf62f604 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/ServerFactory.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/ServerFactory.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Features; +using Microsoft.AspNetCore.Server.Kestrel.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -28,8 +29,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel public IServer CreateServer(IConfiguration configuration) { var information = new KestrelServerInformation(configuration); + var componentFactory = new HttpComponentFactory(information); var serverFeatures = new FeatureCollection(); serverFeatures.Set(information); + serverFeatures.Set(componentFactory); serverFeatures.Set(information); return new KestrelServer(serverFeatures, _appLifetime, _loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel")); } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/ServiceContext.cs b/src/Microsoft.AspNetCore.Server.Kestrel/ServiceContext.cs index b0d26c0953..f702fd1c5e 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/ServiceContext.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/ServiceContext.cs @@ -24,9 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel ThreadPool = context.ThreadPool; FrameFactory = context.FrameFactory; DateHeaderValueManager = context.DateHeaderValueManager; - ConnectionFilter = context.ConnectionFilter; - NoDelay = context.NoDelay; - ReuseStreams = context.ReuseStreams; + ServerInformation = context.ServerInformation; HttpComponentFactory = context.HttpComponentFactory; } @@ -40,11 +38,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel public DateHeaderValueManager DateHeaderValueManager { get; set; } - public IConnectionFilter ConnectionFilter { get; set; } - - public bool NoDelay { get; set; } - - public bool ReuseStreams { get; set; } + public IKestrelServerInformation ServerInformation { get; set; } internal IHttpComponentFactory HttpComponentFactory { get; set; } } diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs index 3f9b0870dd..a6fac125ea 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs @@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [ConditionalFact] [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Test hangs after execution on Mono.")] - public async Task RequestPathIsNormalized() + public void RequestPathIsNormalized() { var port = PortManager.GetPort(); var config = new ConfigurationBuilder().AddInMemoryCollection( diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/ConnectionFilterTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/ConnectionFilterTests.cs index 353d998e5d..dce414fa3e 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/ConnectionFilterTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/ConnectionFilterTests.cs @@ -36,10 +36,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests public async Task CanReadAndWriteWithRewritingConnectionFilter() { var filter = new RewritingConnectionFilter(); - var serviceContext = new TestServiceContext() - { - ConnectionFilter = filter - }; + var serviceContext = new TestServiceContext(filter); + var sendString = "POST / HTTP/1.0\r\n\r\nHello World?"; using (var server = new TestServer(App, serviceContext)) @@ -62,10 +60,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Test hangs after execution on Mono.")] public async Task CanReadAndWriteWithAsyncConnectionFilter() { - var serviceContext = new TestServiceContext() - { - ConnectionFilter = new AsyncConnectionFilter() - }; + var serviceContext = new TestServiceContext(new AsyncConnectionFilter()); using (var server = new TestServer(App, serviceContext)) { @@ -87,10 +82,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Test hangs after execution on Mono.")] public async Task ThrowingSynchronousConnectionFilterDoesNotCrashServer() { - var serviceContext = new TestServiceContext() - { - ConnectionFilter = new ThrowingConnectionFilter() - }; + var serviceContext = new TestServiceContext(new ThrowingConnectionFilter()); using (var server = new TestServer(App, serviceContext)) { diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs index 42315796d5..73c159299d 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs @@ -35,10 +35,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests new TestServiceContext() }, { - new TestServiceContext - { - ConnectionFilter = new PassThroughConnectionFilter() - } + new TestServiceContext(new PassThroughConnectionFilter()) } }; } @@ -188,7 +185,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [MemberData(nameof(ConnectionFilterData))] public async Task ReuseStreamsOn(ServiceContext testContext) { - testContext.ReuseStreams = true; + testContext.ServerInformation.PoolingParameters.MaxPooledStreams = 120; var streamCount = 0; var loopCount = 20; @@ -231,7 +228,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [MemberData(nameof(ConnectionFilterData))] public async Task ReuseStreamsOff(ServiceContext testContext) { - testContext.ReuseStreams = false; + testContext.ServerInformation.PoolingParameters.MaxPooledStreams = 0; var streamCount = 0; var loopCount = 20; diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameResponseHeadersTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameResponseHeadersTests.cs index 8bdf782e9f..30c03a0b35 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameResponseHeadersTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameResponseHeadersTests.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Http; using Microsoft.AspNetCore.Server.Kestrel.Infrastructure; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Primitives; using Xunit; @@ -16,12 +17,15 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [Fact] public void InitialDictionaryContainsServerAndDate() { + var configuration = new ConfigurationBuilder().Build(); + var serverInformation = new KestrelServerInformation(configuration); var connectionContext = new ConnectionContext { DateHeaderValueManager = new DateHeaderValueManager(), ServerAddress = ServerAddress.FromUrl("http://localhost:5000"), - HttpComponentFactory = new HttpComponentFactory() - }; + ServerInformation = serverInformation, + HttpComponentFactory = new HttpComponentFactory(serverInformation) + }; var frame = new Frame(application: null, context: connectionContext) .InitializeHeaders(); @@ -47,11 +51,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [Fact] public void InitialEntriesCanBeCleared() { + var configuration = new ConfigurationBuilder().Build(); + var serverInformation = new KestrelServerInformation(configuration); var connectionContext = new ConnectionContext { DateHeaderValueManager = new DateHeaderValueManager(), ServerAddress = ServerAddress.FromUrl("http://localhost:5000"), - HttpComponentFactory = new HttpComponentFactory() + ServerInformation = serverInformation, + HttpComponentFactory = new HttpComponentFactory(serverInformation) }; var frame = new Frame(application: null, context: connectionContext) .InitializeHeaders(); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/HttpsConnectionFilterTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/HttpsConnectionFilterTests.cs index e3bed702bc..3758a54fc3 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/HttpsConnectionFilterTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/HttpsConnectionFilterTests.cs @@ -59,13 +59,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; #endif var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/"; - var serviceContext = new TestServiceContext() - { - ConnectionFilter = new HttpsConnectionFilter( + var serviceContext = new TestServiceContext(new HttpsConnectionFilter( new HttpsConnectionFilterOptions - { ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword")}, + { ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword") }, new NoOpConnectionFilter()) - }; + ); using (var server = new TestServer(App, serviceContext, serverAddress)) { @@ -108,16 +106,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests #endif var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/"; - var serviceContext = new TestServiceContext() - { - ConnectionFilter = new HttpsConnectionFilter( + var serviceContext = new TestServiceContext(new HttpsConnectionFilter( new HttpsConnectionFilterOptions { ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword"), ClientCertificateMode = ClientCertificateMode.RequireCertificate }, new NoOpConnectionFilter()) - }; + ); using (var server = new TestServer(App, serviceContext, serverAddress)) { @@ -157,16 +153,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests #endif var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/"; - var serviceContext = new TestServiceContext() - { - ConnectionFilter = new HttpsConnectionFilter( - new HttpsConnectionFilterOptions - { - ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword"), - ClientCertificateMode = ClientCertificateMode.AllowCertificate - }, - new NoOpConnectionFilter()) - }; + var serviceContext = new TestServiceContext(new HttpsConnectionFilter( + new HttpsConnectionFilterOptions + { + ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword"), + ClientCertificateMode = ClientCertificateMode.AllowCertificate + }, + new NoOpConnectionFilter()) + ); RequestDelegate app = context => { @@ -209,17 +203,15 @@ namespace Microsoft.AspNetCore.Server.KestrelTests #endif var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/"; - var serviceContext = new TestServiceContext() - { - ConnectionFilter = new HttpsConnectionFilter( - new HttpsConnectionFilterOptions - { - ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword"), - ClientCertificateMode = ClientCertificateMode.RequireCertificate, - ClientCertificateValidation = (certificate, chain, sslPolicyErrors) => true - }, - new NoOpConnectionFilter()) - }; + var serviceContext = new TestServiceContext(new HttpsConnectionFilter( + new HttpsConnectionFilterOptions + { + ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword"), + ClientCertificateMode = ClientCertificateMode.RequireCertificate, + ClientCertificateValidation = (certificate, chain, sslPolicyErrors) => true + }, + new NoOpConnectionFilter()) + ); RequestDelegate app = context => { @@ -281,15 +273,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests #endif var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/"; - var serviceContext = new TestServiceContext() - { - ConnectionFilter = new HttpsConnectionFilter( + var serviceContext = new TestServiceContext( + new HttpsConnectionFilter( new HttpsConnectionFilterOptions { ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword") }, new NoOpConnectionFilter()) - }; + ); RequestDelegate app = context => context.Response.WriteAsync(context.Request.Scheme); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/KestrelServerInformationTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/KestrelServerInformationTests.cs index 9818d9d426..d8594e623c 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/KestrelServerInformationTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/KestrelServerInformationTests.cs @@ -86,19 +86,19 @@ namespace Microsoft.AspNetCore.Server.KestrelTests } [Theory] - [InlineData(null, false)] - [InlineData("", false)] - [InlineData("false", false)] - [InlineData("False", false)] - [InlineData("true", true)] - [InlineData("True", true)] - [InlineData("Foo", false)] - [InlineData("FooBar", false)] - public void SetReuseStreamsUsingConfiguration(string input, bool expected) + [InlineData(null, 0)] + [InlineData("", 0)] + [InlineData("0", 0)] + [InlineData("00", 0)] + [InlineData("0.0", 0)] + [InlineData("1", 1)] + [InlineData("16", 16)] + [InlineData("1000", 1000)] + public void SetMaxPooledStreamsUsingConfiguration(string input, int expected) { var values = new Dictionary { - { "kestrel.reuseStreams", input } + { "kestrel.maxPooledStreams", input } }; var configuration = new ConfigurationBuilder() @@ -107,7 +107,33 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var information = new KestrelServerInformation(configuration); - Assert.Equal(expected, information.ReuseStreams); + Assert.Equal(expected, information.PoolingParameters.MaxPooledStreams); + } + + + [Theory] + [InlineData(null, 0)] + [InlineData("", 0)] + [InlineData("0", 0)] + [InlineData("00", 0)] + [InlineData("0.0", 0)] + [InlineData("1", 1)] + [InlineData("16", 16)] + [InlineData("1000", 1000)] + public void SetMaxPooledHeadersUsingConfiguration(string input, int expected) + { + var values = new Dictionary + { + { "kestrel.maxPooledHeaders", input } + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); + + var information = new KestrelServerInformation(configuration); + + Assert.Equal(expected, information.PoolingParameters.MaxPooledHeaders); } private static int Clamp(int value, int min, int max) diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/TestServiceContext.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/TestServiceContext.cs index 679abaa3a7..0ac9c5c76d 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/TestServiceContext.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/TestServiceContext.cs @@ -3,8 +3,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel; +using Microsoft.AspNetCore.Server.Kestrel.Filter; using Microsoft.AspNetCore.Server.Kestrel.Http; using Microsoft.AspNetCore.Server.Kestrel.Infrastructure; +using Microsoft.Extensions.Configuration; namespace Microsoft.AspNetCore.Server.KestrelTests { @@ -18,7 +20,16 @@ namespace Microsoft.AspNetCore.Server.KestrelTests Log = new TestKestrelTrace(); ThreadPool = new LoggingThreadPool(Log); DateHeaderValueManager = new TestDateHeaderValueManager(); - HttpComponentFactory = new HttpComponentFactory(); + + var configuration = new ConfigurationBuilder().Build(); + ServerInformation = new KestrelServerInformation(configuration); + HttpComponentFactory = new HttpComponentFactory(ServerInformation); + } + + public TestServiceContext(IConnectionFilter filter) + : base() + { + ServerInformation.ConnectionFilter = filter; } public RequestDelegate App