diff --git a/AspNetCore.sln b/AspNetCore.sln index 16238f73a3..ec1086120b 100644 --- a/AspNetCore.sln +++ b/AspNetCore.sln @@ -1397,14 +1397,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sockets.BindTests", "src\Se EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "http2cat", "src\Servers\Kestrel\samples\http2cat\http2cat.csproj", "{8BDEC645-73BD-453B-8A5C-D616BC4EA08D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuicSampleApp", "src\Servers\Kestrel\samples\QuicSampleApp\QuicSampleApp.csproj", "{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Transport.Quic", "Transport.Quic", "{EE9D0952-6060-4723-B329-94A2950A6762}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic", "src\Servers\Kestrel\Transport.Quic\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic.csproj", "{132D43A2-067A-4E24-A520-45B9F14DCB8E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuicSampleClient", "src\Servers\Kestrel\samples\QuicSampleClient\QuicSampleClient.csproj", "{FA8D7CA4-C33B-4409-865F-54192BAC59A4}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Http3SampleApp", "src\Servers\Kestrel\samples\Http3SampleApp\Http3SampleApp.csproj", "{2EC4E939-513F-44CD-A956-498966EAC929}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpStress", "src\Servers\Kestrel\stress\HttpStress.csproj", "{987E1C29-F124-40C8-8E6F-1B2B6A4CB62A}" @@ -6667,18 +6663,6 @@ Global {8BDEC645-73BD-453B-8A5C-D616BC4EA08D}.Release|x64.Build.0 = Release|Any CPU {8BDEC645-73BD-453B-8A5C-D616BC4EA08D}.Release|x86.ActiveCfg = Release|Any CPU {8BDEC645-73BD-453B-8A5C-D616BC4EA08D}.Release|x86.Build.0 = Release|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|x64.ActiveCfg = Debug|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|x64.Build.0 = Debug|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|x86.ActiveCfg = Debug|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|x86.Build.0 = Debug|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|Any CPU.Build.0 = Release|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|x64.ActiveCfg = Release|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|x64.Build.0 = Release|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|x86.ActiveCfg = Release|Any CPU - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|x86.Build.0 = Release|Any CPU {132D43A2-067A-4E24-A520-45B9F14DCB8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {132D43A2-067A-4E24-A520-45B9F14DCB8E}.Debug|Any CPU.Build.0 = Debug|Any CPU {132D43A2-067A-4E24-A520-45B9F14DCB8E}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -6691,18 +6675,6 @@ Global {132D43A2-067A-4E24-A520-45B9F14DCB8E}.Release|x64.Build.0 = Release|Any CPU {132D43A2-067A-4E24-A520-45B9F14DCB8E}.Release|x86.ActiveCfg = Release|Any CPU {132D43A2-067A-4E24-A520-45B9F14DCB8E}.Release|x86.Build.0 = Release|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|x64.ActiveCfg = Debug|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|x64.Build.0 = Debug|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|x86.ActiveCfg = Debug|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|x86.Build.0 = Debug|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|Any CPU.Build.0 = Release|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|x64.ActiveCfg = Release|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|x64.Build.0 = Release|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|x86.ActiveCfg = Release|Any CPU - {FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|x86.Build.0 = Release|Any CPU {2EC4E939-513F-44CD-A956-498966EAC929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2EC4E939-513F-44CD-A956-498966EAC929}.Debug|Any CPU.Build.0 = Debug|Any CPU {2EC4E939-513F-44CD-A956-498966EAC929}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -7857,10 +7829,8 @@ Global {8550A02D-BA13-411A-AAD3-6124D33D669F} = {47EF1A9F-89DB-4EBA-9BC1-1D4E0E12DE44} {EDE77D0C-321A-49FD-95D7-56ED41242A93} = {47EF1A9F-89DB-4EBA-9BC1-1D4E0E12DE44} {8BDEC645-73BD-453B-8A5C-D616BC4EA08D} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB} - {CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB} {EE9D0952-6060-4723-B329-94A2950A6762} = {4FDDC525-4E60-4CAF-83A3-261C5B43721F} {132D43A2-067A-4E24-A520-45B9F14DCB8E} = {EE9D0952-6060-4723-B329-94A2950A6762} - {FA8D7CA4-C33B-4409-865F-54192BAC59A4} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB} {2EC4E939-513F-44CD-A956-498966EAC929} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB} {987E1C29-F124-40C8-8E6F-1B2B6A4CB62A} = {4FDDC525-4E60-4CAF-83A3-261C5B43721F} {3CBC4802-E9B8-48B7-BC8C-B0AFB9EEC643} = {0ACCEDA7-339C-4B4D-8DD4-1AC271F31C04} diff --git a/src/Servers/Connections.Abstractions/src/IMulitplexedConnectionListener.cs b/src/Servers/Connections.Abstractions/src/IMulitplexedConnectionListener.cs index 9173dc4e5a..7f62d00689 100644 --- a/src/Servers/Connections.Abstractions/src/IMulitplexedConnectionListener.cs +++ b/src/Servers/Connections.Abstractions/src/IMulitplexedConnectionListener.cs @@ -7,12 +7,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; -namespace Microsoft.AspNetCore.Connections +namespace Microsoft.AspNetCore.Connections.Experimental { /// /// Defines an interface that represents a listener bound to a specific . /// - public interface IMultiplexedConnectionListener : IAsyncDisposable + internal interface IMultiplexedConnectionListener : IAsyncDisposable { /// /// The endpoint that was bound. This may differ from the requested endpoint, such as when the caller requested that any free port be selected. diff --git a/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionBuilder.cs b/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionBuilder.cs index 8f3caf34db..4bbf33da20 100644 --- a/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionBuilder.cs +++ b/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionBuilder.cs @@ -3,12 +3,12 @@ using System; -namespace Microsoft.AspNetCore.Connections +namespace Microsoft.AspNetCore.Connections.Experimental { /// /// Defines an interface that provides the mechanisms to configure a connection pipeline. /// - public interface IMultiplexedConnectionBuilder + internal interface IMultiplexedConnectionBuilder { /// /// Gets the that provides access to the application's service container. diff --git a/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionFactory.cs b/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionFactory.cs index 1b11aa57ad..42f2048f49 100644 --- a/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionFactory.cs +++ b/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionFactory.cs @@ -6,12 +6,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; -namespace Microsoft.AspNetCore.Connections +namespace Microsoft.AspNetCore.Connections.Experimental { /// /// A factory abstraction for creating connections to an endpoint. /// - public interface IMultiplexedConnectionFactory + internal interface IMultiplexedConnectionFactory { /// /// Creates a new connection to an endpoint. diff --git a/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionListenerFactory.cs b/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionListenerFactory.cs index ee3e593b9d..255d85e498 100644 --- a/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionListenerFactory.cs +++ b/src/Servers/Connections.Abstractions/src/IMultiplexedConnectionListenerFactory.cs @@ -6,12 +6,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; -namespace Microsoft.AspNetCore.Connections +namespace Microsoft.AspNetCore.Connections.Experimental { /// /// Defines an interface that provides the mechanisms for binding to various types of s. /// - public interface IMultiplexedConnectionListenerFactory + internal interface IMultiplexedConnectionListenerFactory { /// /// Creates an bound to the specified . diff --git a/src/Servers/Connections.Abstractions/src/MultiplexedConnectionBuilder.cs b/src/Servers/Connections.Abstractions/src/MultiplexedConnectionBuilder.cs index 202f29df5e..4a621c98ea 100644 --- a/src/Servers/Connections.Abstractions/src/MultiplexedConnectionBuilder.cs +++ b/src/Servers/Connections.Abstractions/src/MultiplexedConnectionBuilder.cs @@ -6,9 +6,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -namespace Microsoft.AspNetCore.Connections +namespace Microsoft.AspNetCore.Connections.Experimental { - public class MultiplexedConnectionBuilder : IMultiplexedConnectionBuilder + internal class MultiplexedConnectionBuilder : IMultiplexedConnectionBuilder { private readonly IList> _components = new List>(); diff --git a/src/Servers/Connections.Abstractions/src/MultiplexedConnectionContext.cs b/src/Servers/Connections.Abstractions/src/MultiplexedConnectionContext.cs index 27ca5444de..5e99824431 100644 --- a/src/Servers/Connections.Abstractions/src/MultiplexedConnectionContext.cs +++ b/src/Servers/Connections.Abstractions/src/MultiplexedConnectionContext.cs @@ -6,12 +6,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; -namespace Microsoft.AspNetCore.Connections +namespace Microsoft.AspNetCore.Connections.Experimental { /// /// Encapsulates all information about a multiplexed connection. /// - public abstract class MultiplexedConnectionContext : BaseConnectionContext, IAsyncDisposable + internal abstract class MultiplexedConnectionContext : BaseConnectionContext, IAsyncDisposable { /// /// Asynchronously accept an incoming stream on the connection. diff --git a/src/Servers/Connections.Abstractions/src/MultiplexedConnectionDelegate.cs b/src/Servers/Connections.Abstractions/src/MultiplexedConnectionDelegate.cs index c85298ea2d..6fca4fc6eb 100644 --- a/src/Servers/Connections.Abstractions/src/MultiplexedConnectionDelegate.cs +++ b/src/Servers/Connections.Abstractions/src/MultiplexedConnectionDelegate.cs @@ -3,12 +3,12 @@ using System.Threading.Tasks; -namespace Microsoft.AspNetCore.Connections +namespace Microsoft.AspNetCore.Connections.Experimental { /// /// A function that can process a connection. /// /// A representing the connection. /// A that represents the connection lifetime. When the task completes, the connection will be closed. - public delegate Task MultiplexedConnectionDelegate(MultiplexedConnectionContext connection); + internal delegate Task MultiplexedConnectionDelegate(MultiplexedConnectionContext connection); } diff --git a/src/Servers/Connections.Abstractions/src/Properties/AssemblyInfo.cs b/src/Servers/Connections.Abstractions/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..0c36b98179 --- /dev/null +++ b/src/Servers/Connections.Abstractions/src/Properties/AssemblyInfo.cs @@ -0,0 +1,9 @@ +// 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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Core, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("InMemory.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Servers/HttpSys/test/FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/src/Servers/HttpSys/test/FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 789ce6e844..215e38e814 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/src/Servers/HttpSys/test/FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/IIS.FunctionalTests.csproj b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/IIS.FunctionalTests.csproj index b03eeccaff..7eeab63308 100644 --- a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/IIS.FunctionalTests.csproj +++ b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/IIS.FunctionalTests.csproj @@ -25,6 +25,7 @@ + diff --git a/src/Servers/IIS/IIS/test/IIS.NewHandler.FunctionalTests/IIS.NewHandler.FunctionalTests.csproj b/src/Servers/IIS/IIS/test/IIS.NewHandler.FunctionalTests/IIS.NewHandler.FunctionalTests.csproj index 70f9a69469..4c312d6f91 100644 --- a/src/Servers/IIS/IIS/test/IIS.NewHandler.FunctionalTests/IIS.NewHandler.FunctionalTests.csproj +++ b/src/Servers/IIS/IIS/test/IIS.NewHandler.FunctionalTests/IIS.NewHandler.FunctionalTests.csproj @@ -18,6 +18,7 @@ + diff --git a/src/Servers/IIS/IIS/test/IIS.NewShim.FunctionalTests/IIS.NewShim.FunctionalTests.csproj b/src/Servers/IIS/IIS/test/IIS.NewShim.FunctionalTests/IIS.NewShim.FunctionalTests.csproj index e70b5c17d4..f8964d01c7 100644 --- a/src/Servers/IIS/IIS/test/IIS.NewShim.FunctionalTests/IIS.NewShim.FunctionalTests.csproj +++ b/src/Servers/IIS/IIS/test/IIS.NewShim.FunctionalTests/IIS.NewShim.FunctionalTests.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj b/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj index 7fdf5ba6ad..c954022941 100644 --- a/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj +++ b/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj @@ -29,6 +29,7 @@ + diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs index 20a500a355..171232fbd6 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Net; @@ -10,6 +9,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http.Features; diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3ConnectionContext.cs b/src/Servers/Kestrel/Core/src/Internal/Http3ConnectionContext.cs index e20f8c33a6..488b088fdf 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http3ConnectionContext.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http3ConnectionContext.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Net; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; diff --git a/src/Servers/Kestrel/Core/src/Internal/Infrastructure/TransportManager.cs b/src/Servers/Kestrel/Core/src/Internal/Infrastructure/TransportManager.cs index 9971db7c1e..7b23f3b79d 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Infrastructure/TransportManager.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Infrastructure/TransportManager.cs @@ -10,6 +10,7 @@ using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure { diff --git a/src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs b/src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs new file mode 100644 index 0000000000..43e155bccc --- /dev/null +++ b/src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs @@ -0,0 +1,398 @@ +// 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.Collections.Generic; +using System.IO.Pipelines; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; +using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.Server.Kestrel.Core +{ + internal class KestrelServerImpl : IServer + { + private readonly ServerAddressesFeature _serverAddresses; + private readonly TransportManager _transportManager; + private readonly IConnectionListenerFactory _transportFactory; + private readonly IMultiplexedConnectionListenerFactory _multiplexedTransportFactory; + + private readonly SemaphoreSlim _bindSemaphore = new SemaphoreSlim(initialCount: 1); + private bool _hasStarted; + private int _stopping; + private readonly CancellationTokenSource _stopCts = new CancellationTokenSource(); + private readonly TaskCompletionSource _stoppedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + private IDisposable _configChangedRegistration; + + public KestrelServerImpl( + IOptions options, + IEnumerable transportFactories, + ILoggerFactory loggerFactory) + : this(transportFactories, null, CreateServiceContext(options, loggerFactory)) + { + } + + public KestrelServerImpl( + IOptions options, + IEnumerable transportFactories, + IEnumerable multiplexedFactories, + ILoggerFactory loggerFactory) + : this(transportFactories, multiplexedFactories, CreateServiceContext(options, loggerFactory)) + { + } + + // For testing + internal KestrelServerImpl(IEnumerable transportFactories, ServiceContext serviceContext) + : this(transportFactories, null, serviceContext) + { + } + + // For testing + internal KestrelServerImpl( + IEnumerable transportFactories, + IEnumerable multiplexedFactories, + ServiceContext serviceContext) + { + if (transportFactories == null) + { + throw new ArgumentNullException(nameof(transportFactories)); + } + + _transportFactory = transportFactories?.LastOrDefault(); + _multiplexedTransportFactory = multiplexedFactories?.LastOrDefault(); + + if (_transportFactory == null && _multiplexedTransportFactory == null) + { + throw new InvalidOperationException(CoreStrings.TransportNotFound); + } + + ServiceContext = serviceContext; + + Features = new FeatureCollection(); + _serverAddresses = new ServerAddressesFeature(); + Features.Set(_serverAddresses); + + _transportManager = new TransportManager(_transportFactory, _multiplexedTransportFactory, ServiceContext); + + HttpCharacters.Initialize(); + } + + private static ServiceContext CreateServiceContext(IOptions 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 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, + HttpParser = new HttpParser(trace.IsEnabled(LogLevel.Information)), + Scheduler = PipeScheduler.ThreadPool, + SystemClock = heartbeatManager, + DateHeaderValueManager = dateHeaderValueManager, + ConnectionManager = connectionManager, + Heartbeat = heartbeat, + ServerOptions = serverOptions, + }; + } + + public IFeatureCollection Features { get; } + + public KestrelServerOptions Options => ServiceContext.ServerOptions; + + private ServiceContext ServiceContext { get; } + + private IKestrelTrace Trace => ServiceContext.Log; + + private AddressBindContext AddressBindContext { get; set; } + + public async Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) + { + try + { + if (!BitConverter.IsLittleEndian) + { + throw new PlatformNotSupportedException(CoreStrings.BigEndianNotSupported); + } + + ValidateOptions(); + + if (_hasStarted) + { + // The server has already started and/or has not been cleaned up yet + throw new InvalidOperationException(CoreStrings.ServerAlreadyStarted); + } + _hasStarted = true; + + ServiceContext.Heartbeat?.Start(); + + async Task OnBind(ListenOptions options) + { + // INVESTIGATE: For some reason, MsQuic needs to bind before + // sockets for it to successfully listen. It also seems racy. + if ((options.Protocols & HttpProtocols.Http3) == HttpProtocols.Http3) + { + if (_multiplexedTransportFactory is null) + { + throw new InvalidOperationException($"Cannot start HTTP/3 server if no {nameof(IMultiplexedConnectionListenerFactory)} is registered."); + } + + options.UseHttp3Server(ServiceContext, application, options.Protocols); + var multiplexedConnectionDelegate = ((IMultiplexedConnectionBuilder)options).Build(); + + // Add the connection limit middleware + multiplexedConnectionDelegate = EnforceConnectionLimit(multiplexedConnectionDelegate, Options.Limits.MaxConcurrentConnections, Trace); + + options.EndPoint = await _transportManager.BindAsync(options.EndPoint, multiplexedConnectionDelegate, options.EndpointConfig).ConfigureAwait(false); + } + + // Add the HTTP middleware as the terminal connection middleware + if ((options.Protocols & HttpProtocols.Http1) == HttpProtocols.Http1 + || (options.Protocols & HttpProtocols.Http2) == HttpProtocols.Http2 + || options.Protocols == HttpProtocols.None) // TODO a test fails because it doesn't throw an exception in the right place + // when there is no HttpProtocols in KestrelServer, can we remove/change the test? + { + if (_transportFactory is null) + { + throw new InvalidOperationException($"Cannot start HTTP/1.x or HTTP/2 server if no {nameof(IConnectionListenerFactory)} is registered."); + } + + options.UseHttpServer(ServiceContext, application, options.Protocols); + var connectionDelegate = options.Build(); + + // Add the connection limit middleware + connectionDelegate = EnforceConnectionLimit(connectionDelegate, Options.Limits.MaxConcurrentConnections, Trace); + + options.EndPoint = await _transportManager.BindAsync(options.EndPoint, connectionDelegate, options.EndpointConfig).ConfigureAwait(false); + } + } + + AddressBindContext = new AddressBindContext + { + ServerAddressesFeature = _serverAddresses, + ServerOptions = Options, + Logger = Trace, + CreateBinding = OnBind, + }; + + await BindAsync(cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + Trace.LogCritical(0, ex, "Unable to start Kestrel."); + Dispose(); + throw; + } + } + + // Graceful shutdown if possible + public async Task StopAsync(CancellationToken cancellationToken) + { + if (Interlocked.Exchange(ref _stopping, 1) == 1) + { + await _stoppedTcs.Task.ConfigureAwait(false); + return; + } + + _stopCts.Cancel(); + + // Don't use cancellationToken when acquiring the semaphore. Dispose calls this with a pre-canceled token. + await _bindSemaphore.WaitAsync().ConfigureAwait(false); + + try + { + await _transportManager.StopAsync(cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _stoppedTcs.TrySetException(ex); + throw; + } + finally + { + ServiceContext.Heartbeat?.Dispose(); + _configChangedRegistration?.Dispose(); + _stopCts.Dispose(); + _bindSemaphore.Release(); + } + + _stoppedTcs.TrySetResult(); + } + + // Ungraceful shutdown + public void Dispose() + { + StopAsync(new CancellationToken(canceled: true)).GetAwaiter().GetResult(); + } + + private async Task BindAsync(CancellationToken cancellationToken) + { + await _bindSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + if (_stopping == 1) + { + throw new InvalidOperationException("Kestrel has already been stopped."); + } + + IChangeToken reloadToken = null; + + _serverAddresses.InternalCollection.PreventPublicMutation(); + + if (Options.ConfigurationLoader?.ReloadOnChange == true && (!_serverAddresses.PreferHostingUrls || _serverAddresses.InternalCollection.Count == 0)) + { + reloadToken = Options.ConfigurationLoader.Configuration.GetReloadToken(); + } + + Options.ConfigurationLoader?.Load(); + + await AddressBinder.BindAsync(Options.ListenOptions, AddressBindContext).ConfigureAwait(false); + _configChangedRegistration = reloadToken?.RegisterChangeCallback(async state => await ((KestrelServerImpl)state).RebindAsync(), this); + } + finally + { + _bindSemaphore.Release(); + } + } + + private async Task RebindAsync() + { + await _bindSemaphore.WaitAsync(); + + IChangeToken reloadToken = null; + + try + { + if (_stopping == 1) + { + return; + } + + reloadToken = Options.ConfigurationLoader.Configuration.GetReloadToken(); + var (endpointsToStop, endpointsToStart) = Options.ConfigurationLoader.Reload(); + + Trace.LogDebug("Config reload token fired. Checking for changes..."); + + if (endpointsToStop.Count > 0) + { + var urlsToStop = endpointsToStop.Select(lo => lo.EndpointConfig.Url ?? ""); + Trace.LogInformation("Config changed. Stopping the following endpoints: '{endpoints}'", string.Join("', '", urlsToStop)); + + // 5 is the default value for WebHost's "shutdownTimeoutSeconds", so use that. + using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(_stopCts.Token, timeoutCts.Token); + + // TODO: It would be nice to start binding to new endpoints immediately and reconfigured endpoints as soon + // as the unbinding finished for the given endpoint rather than wait for all transports to unbind first. + var configsToStop = endpointsToStop.Select(lo => lo.EndpointConfig).ToList(); + await _transportManager.StopEndpointsAsync(configsToStop, combinedCts.Token).ConfigureAwait(false); + + foreach (var listenOption in endpointsToStop) + { + Options.OptionsInUse.Remove(listenOption); + _serverAddresses.InternalCollection.Remove(listenOption.GetDisplayName()); + } + } + + if (endpointsToStart.Count > 0) + { + var urlsToStart = endpointsToStart.Select(lo => lo.EndpointConfig.Url ?? ""); + Trace.LogInformation("Config changed. Starting the following endpoints: '{endpoints}'", string.Join("', '", urlsToStart)); + + foreach (var listenOption in endpointsToStart) + { + try + { + // TODO: This should probably be canceled by the _stopCts too, but we don't currently support bind cancellation even in StartAsync(). + await listenOption.BindAsync(AddressBindContext).ConfigureAwait(false); + } + catch (Exception ex) + { + Trace.LogCritical(0, ex, "Unable to bind to '{url}' on config reload.", listenOption.EndpointConfig.Url ?? ""); + } + } + } + } + catch (Exception ex) + { + Trace.LogCritical(0, ex, "Unable to reload configuration."); + } + finally + { + _configChangedRegistration = reloadToken?.RegisterChangeCallback(async state => await ((KestrelServerImpl)state).RebindAsync(), this); + _bindSemaphore.Release(); + } + } + + private void ValidateOptions() + { + if (Options.Limits.MaxRequestBufferSize.HasValue && + Options.Limits.MaxRequestBufferSize < Options.Limits.MaxRequestLineSize) + { + throw new InvalidOperationException( + CoreStrings.FormatMaxRequestBufferSmallerThanRequestLineBuffer(Options.Limits.MaxRequestBufferSize.Value, Options.Limits.MaxRequestLineSize)); + } + + if (Options.Limits.MaxRequestBufferSize.HasValue && + Options.Limits.MaxRequestBufferSize < Options.Limits.MaxRequestHeadersTotalSize) + { + throw new InvalidOperationException( + CoreStrings.FormatMaxRequestBufferSmallerThanRequestHeaderBuffer(Options.Limits.MaxRequestBufferSize.Value, Options.Limits.MaxRequestHeadersTotalSize)); + } + } + + private static ConnectionDelegate EnforceConnectionLimit(ConnectionDelegate innerDelegate, long? connectionLimit, IKestrelTrace trace) + { + if (!connectionLimit.HasValue) + { + return innerDelegate; + } + + return new ConnectionLimitMiddleware(c => innerDelegate(c), connectionLimit.Value, trace).OnConnectionAsync; + } + + private static MultiplexedConnectionDelegate EnforceConnectionLimit(MultiplexedConnectionDelegate innerDelegate, long? connectionLimit, IKestrelTrace trace) + { + if (!connectionLimit.HasValue) + { + return innerDelegate; + } + + return new ConnectionLimitMiddleware(c => innerDelegate(c), connectionLimit.Value, trace).OnConnectionAsync; + } + } +} diff --git a/src/Servers/Kestrel/Core/src/KestrelServer.cs b/src/Servers/Kestrel/Core/src/KestrelServer.cs index e38860ad4e..9ad15a1e94 100644 --- a/src/Servers/Kestrel/Core/src/KestrelServer.cs +++ b/src/Servers/Kestrel/Core/src/KestrelServer.cs @@ -1,397 +1,55 @@ // 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.Collections.Generic; -using System.IO.Pipelines; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; -using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; -using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Server.Kestrel.Core { public class KestrelServer : IServer { - private readonly ServerAddressesFeature _serverAddresses; - private readonly TransportManager _transportManager; - private readonly IConnectionListenerFactory _transportFactory; - private readonly IMultiplexedConnectionListenerFactory _multiplexedTransportFactory; - - private readonly SemaphoreSlim _bindSemaphore = new SemaphoreSlim(initialCount: 1); - private bool _hasStarted; - private int _stopping; - private readonly CancellationTokenSource _stopCts = new CancellationTokenSource(); - private readonly TaskCompletionSource _stoppedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - private IDisposable _configChangedRegistration; + private KestrelServerImpl _innerKestrelServer; public KestrelServer( IOptions options, IEnumerable transportFactories, ILoggerFactory loggerFactory) - : this(transportFactories, null, CreateServiceContext(options, loggerFactory)) - { - } - - public KestrelServer( - IOptions options, - IEnumerable transportFactories, - IEnumerable multiplexedFactories, - ILoggerFactory loggerFactory) - : this(transportFactories, multiplexedFactories, CreateServiceContext(options, loggerFactory)) { + _innerKestrelServer = new KestrelServerImpl(options, transportFactories, loggerFactory); } // For testing internal KestrelServer(IEnumerable transportFactories, ServiceContext serviceContext) - : this(transportFactories, null, serviceContext) { + _innerKestrelServer = new KestrelServerImpl(transportFactories, serviceContext); } - // For testing - internal KestrelServer( - IEnumerable transportFactories, - IEnumerable multiplexedFactories, - ServiceContext serviceContext) + public IFeatureCollection Features => _innerKestrelServer.Features; + + public KestrelServerOptions Options => _innerKestrelServer.Options; + + public Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) { - if (transportFactories == null) - { - throw new ArgumentNullException(nameof(transportFactories)); - } - - _transportFactory = transportFactories?.LastOrDefault(); - _multiplexedTransportFactory = multiplexedFactories?.LastOrDefault(); - - if (_transportFactory == null && _multiplexedTransportFactory == null) - { - throw new InvalidOperationException(CoreStrings.TransportNotFound); - } - - ServiceContext = serviceContext; - - Features = new FeatureCollection(); - _serverAddresses = new ServerAddressesFeature(); - Features.Set(_serverAddresses); - - _transportManager = new TransportManager(_transportFactory, _multiplexedTransportFactory, ServiceContext); - - HttpCharacters.Initialize(); - } - - private static ServiceContext CreateServiceContext(IOptions 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 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, - HttpParser = new HttpParser(trace.IsEnabled(LogLevel.Information)), - Scheduler = PipeScheduler.ThreadPool, - SystemClock = heartbeatManager, - DateHeaderValueManager = dateHeaderValueManager, - ConnectionManager = connectionManager, - Heartbeat = heartbeat, - ServerOptions = serverOptions, - }; - } - - public IFeatureCollection Features { get; } - - public KestrelServerOptions Options => ServiceContext.ServerOptions; - - private ServiceContext ServiceContext { get; } - - private IKestrelTrace Trace => ServiceContext.Log; - - private AddressBindContext AddressBindContext { get; set; } - - public async Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) - { - try - { - if (!BitConverter.IsLittleEndian) - { - throw new PlatformNotSupportedException(CoreStrings.BigEndianNotSupported); - } - - ValidateOptions(); - - if (_hasStarted) - { - // The server has already started and/or has not been cleaned up yet - throw new InvalidOperationException(CoreStrings.ServerAlreadyStarted); - } - _hasStarted = true; - - ServiceContext.Heartbeat?.Start(); - - async Task OnBind(ListenOptions options) - { - // INVESTIGATE: For some reason, MsQuic needs to bind before - // sockets for it to successfully listen. It also seems racy. - if ((options.Protocols & HttpProtocols.Http3) == HttpProtocols.Http3) - { - if (_multiplexedTransportFactory is null) - { - throw new InvalidOperationException($"Cannot start HTTP/3 server if no {nameof(IMultiplexedConnectionListenerFactory)} is registered."); - } - - options.UseHttp3Server(ServiceContext, application, options.Protocols); - var multiplexedConnectionDelegate = ((IMultiplexedConnectionBuilder)options).Build(); - - // Add the connection limit middleware - multiplexedConnectionDelegate = EnforceConnectionLimit(multiplexedConnectionDelegate, Options.Limits.MaxConcurrentConnections, Trace); - - options.EndPoint = await _transportManager.BindAsync(options.EndPoint, multiplexedConnectionDelegate, options.EndpointConfig).ConfigureAwait(false); - } - - // Add the HTTP middleware as the terminal connection middleware - if ((options.Protocols & HttpProtocols.Http1) == HttpProtocols.Http1 - || (options.Protocols & HttpProtocols.Http2) == HttpProtocols.Http2 - || options.Protocols == HttpProtocols.None) // TODO a test fails because it doesn't throw an exception in the right place - // when there is no HttpProtocols in KestrelServer, can we remove/change the test? - { - if (_transportFactory is null) - { - throw new InvalidOperationException($"Cannot start HTTP/1.x or HTTP/2 server if no {nameof(IConnectionListenerFactory)} is registered."); - } - - options.UseHttpServer(ServiceContext, application, options.Protocols); - var connectionDelegate = options.Build(); - - // Add the connection limit middleware - connectionDelegate = EnforceConnectionLimit(connectionDelegate, Options.Limits.MaxConcurrentConnections, Trace); - - options.EndPoint = await _transportManager.BindAsync(options.EndPoint, connectionDelegate, options.EndpointConfig).ConfigureAwait(false); - } - } - - AddressBindContext = new AddressBindContext - { - ServerAddressesFeature = _serverAddresses, - ServerOptions = Options, - Logger = Trace, - CreateBinding = OnBind, - }; - - await BindAsync(cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - Trace.LogCritical(0, ex, "Unable to start Kestrel."); - Dispose(); - throw; - } + return _innerKestrelServer.StartAsync(application, cancellationToken); } // Graceful shutdown if possible - public async Task StopAsync(CancellationToken cancellationToken) + public Task StopAsync(CancellationToken cancellationToken) { - if (Interlocked.Exchange(ref _stopping, 1) == 1) - { - await _stoppedTcs.Task.ConfigureAwait(false); - return; - } - - _stopCts.Cancel(); - - // Don't use cancellationToken when acquiring the semaphore. Dispose calls this with a pre-canceled token. - await _bindSemaphore.WaitAsync().ConfigureAwait(false); - - try - { - await _transportManager.StopAsync(cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - _stoppedTcs.TrySetException(ex); - throw; - } - finally - { - ServiceContext.Heartbeat?.Dispose(); - _configChangedRegistration?.Dispose(); - _stopCts.Dispose(); - _bindSemaphore.Release(); - } - - _stoppedTcs.TrySetResult(); + return _innerKestrelServer.StopAsync(cancellationToken); } // Ungraceful shutdown public void Dispose() { - StopAsync(new CancellationToken(canceled: true)).GetAwaiter().GetResult(); - } - - private async Task BindAsync(CancellationToken cancellationToken) - { - await _bindSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - if (_stopping == 1) - { - throw new InvalidOperationException("Kestrel has already been stopped."); - } - - IChangeToken reloadToken = null; - - _serverAddresses.InternalCollection.PreventPublicMutation(); - - if (Options.ConfigurationLoader?.ReloadOnChange == true && (!_serverAddresses.PreferHostingUrls || _serverAddresses.InternalCollection.Count == 0)) - { - reloadToken = Options.ConfigurationLoader.Configuration.GetReloadToken(); - } - - Options.ConfigurationLoader?.Load(); - - await AddressBinder.BindAsync(Options.ListenOptions, AddressBindContext).ConfigureAwait(false); - _configChangedRegistration = reloadToken?.RegisterChangeCallback(async state => await ((KestrelServer)state).RebindAsync(), this); - } - finally - { - _bindSemaphore.Release(); - } - } - - private async Task RebindAsync() - { - await _bindSemaphore.WaitAsync(); - - IChangeToken reloadToken = null; - - try - { - if (_stopping == 1) - { - return; - } - - reloadToken = Options.ConfigurationLoader.Configuration.GetReloadToken(); - var (endpointsToStop, endpointsToStart) = Options.ConfigurationLoader.Reload(); - - Trace.LogDebug("Config reload token fired. Checking for changes..."); - - if (endpointsToStop.Count > 0) - { - var urlsToStop = endpointsToStop.Select(lo => lo.EndpointConfig.Url ?? ""); - Trace.LogInformation("Config changed. Stopping the following endpoints: '{endpoints}'", string.Join("', '", urlsToStop)); - - // 5 is the default value for WebHost's "shutdownTimeoutSeconds", so use that. - using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); - using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(_stopCts.Token, timeoutCts.Token); - - // TODO: It would be nice to start binding to new endpoints immediately and reconfigured endpoints as soon - // as the unbinding finished for the given endpoint rather than wait for all transports to unbind first. - var configsToStop = endpointsToStop.Select(lo => lo.EndpointConfig).ToList(); - await _transportManager.StopEndpointsAsync(configsToStop, combinedCts.Token).ConfigureAwait(false); - - foreach (var listenOption in endpointsToStop) - { - Options.OptionsInUse.Remove(listenOption); - _serverAddresses.InternalCollection.Remove(listenOption.GetDisplayName()); - } - } - - if (endpointsToStart.Count > 0) - { - var urlsToStart = endpointsToStart.Select(lo => lo.EndpointConfig.Url ?? ""); - Trace.LogInformation("Config changed. Starting the following endpoints: '{endpoints}'", string.Join("', '", urlsToStart)); - - foreach (var listenOption in endpointsToStart) - { - try - { - // TODO: This should probably be canceled by the _stopCts too, but we don't currently support bind cancellation even in StartAsync(). - await listenOption.BindAsync(AddressBindContext).ConfigureAwait(false); - } - catch (Exception ex) - { - Trace.LogCritical(0, ex, "Unable to bind to '{url}' on config reload.", listenOption.EndpointConfig.Url ?? ""); - } - } - } - } - catch (Exception ex) - { - Trace.LogCritical(0, ex, "Unable to reload configuration."); - } - finally - { - _configChangedRegistration = reloadToken?.RegisterChangeCallback(async state => await ((KestrelServer)state).RebindAsync(), this); - _bindSemaphore.Release(); - } - } - - private void ValidateOptions() - { - if (Options.Limits.MaxRequestBufferSize.HasValue && - Options.Limits.MaxRequestBufferSize < Options.Limits.MaxRequestLineSize) - { - throw new InvalidOperationException( - CoreStrings.FormatMaxRequestBufferSmallerThanRequestLineBuffer(Options.Limits.MaxRequestBufferSize.Value, Options.Limits.MaxRequestLineSize)); - } - - if (Options.Limits.MaxRequestBufferSize.HasValue && - Options.Limits.MaxRequestBufferSize < Options.Limits.MaxRequestHeadersTotalSize) - { - throw new InvalidOperationException( - CoreStrings.FormatMaxRequestBufferSmallerThanRequestHeaderBuffer(Options.Limits.MaxRequestBufferSize.Value, Options.Limits.MaxRequestHeadersTotalSize)); - } - } - - private static ConnectionDelegate EnforceConnectionLimit(ConnectionDelegate innerDelegate, long? connectionLimit, IKestrelTrace trace) - { - if (!connectionLimit.HasValue) - { - return innerDelegate; - } - - return new ConnectionLimitMiddleware(c => innerDelegate(c), connectionLimit.Value, trace).OnConnectionAsync; - } - - private static MultiplexedConnectionDelegate EnforceConnectionLimit(MultiplexedConnectionDelegate innerDelegate, long? connectionLimit, IKestrelTrace trace) - { - if (!connectionLimit.HasValue) - { - return innerDelegate; - } - - return new ConnectionLimitMiddleware(c => innerDelegate(c), connectionLimit.Value, trace).OnConnectionAsync; + _innerKestrelServer.Dispose(); } } } diff --git a/src/Servers/Kestrel/Core/src/ListenOptions.cs b/src/Servers/Kestrel/Core/src/ListenOptions.cs index fb049d102a..ed573112b3 100644 --- a/src/Servers/Kestrel/Core/src/ListenOptions.cs +++ b/src/Servers/Kestrel/Core/src/ListenOptions.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; diff --git a/src/Servers/Kestrel/Core/src/Middleware/Http3ConnectionMiddleware.cs b/src/Servers/Kestrel/Core/src/Middleware/Http3ConnectionMiddleware.cs index dc4aa7b29a..b746197897 100644 --- a/src/Servers/Kestrel/Core/src/Middleware/Http3ConnectionMiddleware.cs +++ b/src/Servers/Kestrel/Core/src/Middleware/Http3ConnectionMiddleware.cs @@ -4,6 +4,7 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http3; diff --git a/src/Servers/Kestrel/Core/src/Middleware/HttpConnectionBuilderExtensions.cs b/src/Servers/Kestrel/Core/src/Middleware/HttpConnectionBuilderExtensions.cs index 09c1ce476c..c6e735c6f1 100644 --- a/src/Servers/Kestrel/Core/src/Middleware/HttpConnectionBuilderExtensions.cs +++ b/src/Servers/Kestrel/Core/src/Middleware/HttpConnectionBuilderExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal { diff --git a/src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs b/src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs index 3616679369..2d55f15497 100644 --- a/src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs +++ b/src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Hosting services.TryAddSingleton(); services.AddTransient, KestrelServerOptionsSetup>(); - services.AddSingleton(); + services.AddSingleton(); }); } diff --git a/src/Servers/Kestrel/Kestrel/test/WebHostBuilderKestrelExtensionsTests.cs b/src/Servers/Kestrel/Kestrel/test/WebHostBuilderKestrelExtensionsTests.cs index 6f2b8c9687..6ab785c979 100644 --- a/src/Servers/Kestrel/Kestrel/test/WebHostBuilderKestrelExtensionsTests.cs +++ b/src/Servers/Kestrel/Kestrel/test/WebHostBuilderKestrelExtensionsTests.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets; @@ -99,5 +100,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests Assert.IsType(hostBuilderReversed.Build().Services.GetService()); } + + [Fact] + public void ServerIsKestrelServerImpl() + { + var hostBuilder = new WebHostBuilder() + .UseSockets() + .UseKestrel() + .Configure(app => { }); + + Assert.IsType(hostBuilder.Build().Services.GetService()); + } } } diff --git a/src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionListener.cs b/src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionListener.cs index c6d50f0250..2184856774 100644 --- a/src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionListener.cs +++ b/src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionListener.cs @@ -9,6 +9,7 @@ using System.Net.Security; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Logging; diff --git a/src/Servers/Kestrel/Transport.Quic/src/QuicConnectionFactory.cs b/src/Servers/Kestrel/Transport.Quic/src/QuicConnectionFactory.cs index abc73c72c0..0a818f233a 100644 --- a/src/Servers/Kestrel/Transport.Quic/src/QuicConnectionFactory.cs +++ b/src/Servers/Kestrel/Transport.Quic/src/QuicConnectionFactory.cs @@ -9,6 +9,7 @@ using System.Net.Security; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic.Internal; using Microsoft.Extensions.Logging; @@ -16,7 +17,7 @@ using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic { - public class QuicConnectionFactory : IMultiplexedConnectionFactory + internal class QuicConnectionFactory : IMultiplexedConnectionFactory { private QuicTransportContext _transportContext; diff --git a/src/Servers/Kestrel/Transport.Quic/src/QuicTransportFactory.cs b/src/Servers/Kestrel/Transport.Quic/src/QuicTransportFactory.cs index 98b089c892..e95f46d41c 100644 --- a/src/Servers/Kestrel/Transport.Quic/src/QuicTransportFactory.cs +++ b/src/Servers/Kestrel/Transport.Quic/src/QuicTransportFactory.cs @@ -6,6 +6,7 @@ using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic.Internal; using Microsoft.Extensions.Logging; @@ -13,7 +14,7 @@ using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic { - public class QuicTransportFactory : IMultiplexedConnectionListenerFactory + internal class QuicTransportFactory : IMultiplexedConnectionListenerFactory { private QuicTrace _log; private QuicTransportOptions _options; @@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic _options = options.Value; } - public ValueTask BindAsync(EndPoint endpoint, IFeatureCollection features = null, CancellationToken cancellationToken = default) + public ValueTask BindAsync(EndPoint endpoint, IFeatureCollection features = null, CancellationToken cancellationToken = default) { var transport = new QuicConnectionListener(_options, _log, endpoint); return new ValueTask(transport); diff --git a/src/Servers/Kestrel/Transport.Quic/src/WebHostBuilderMsQuicExtensions.cs b/src/Servers/Kestrel/Transport.Quic/src/WebHostBuilderMsQuicExtensions.cs index 2c5ab8be37..d1a1d79cf6 100644 --- a/src/Servers/Kestrel/Transport.Quic/src/WebHostBuilderMsQuicExtensions.cs +++ b/src/Servers/Kestrel/Transport.Quic/src/WebHostBuilderMsQuicExtensions.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Servers/Kestrel/Transport.Sockets/src/AssemblyInfo.cs b/src/Servers/Kestrel/Transport.Sockets/src/AssemblyInfo.cs index effc0ed2ca..adb6da7aa8 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/AssemblyInfo.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/AssemblyInfo.cs @@ -5,3 +5,10 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Sockets.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Sockets.BindTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("http2cat, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.HttpSys.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("http2cat, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("IIS.NewShim.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("IIS.NewHandler.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("IISExpress.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("IIS.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Servers/Kestrel/Transport.Sockets/src/Client/SocketConnectionFactory.cs b/src/Servers/Kestrel/Transport.Sockets/src/Client/SocketConnectionFactory.cs index a3275335a6..d587b531b3 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/Client/SocketConnectionFactory.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/Client/SocketConnectionFactory.cs @@ -16,7 +16,7 @@ using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets { - public class SocketConnectionFactory : IConnectionFactory, IAsyncDisposable + internal class SocketConnectionFactory : IConnectionFactory, IAsyncDisposable { private readonly SocketTransportOptions _options; private readonly MemoryPool _memoryPool; diff --git a/src/Servers/Kestrel/samples/Http3SampleApp/Program.cs b/src/Servers/Kestrel/samples/Http3SampleApp/Program.cs index 7e37138aaf..364d93649e 100644 --- a/src/Servers/Kestrel/samples/Http3SampleApp/Program.cs +++ b/src/Servers/Kestrel/samples/Http3SampleApp/Program.cs @@ -28,7 +28,7 @@ namespace Http3SampleApp .UseQuic(options => { options.Certificate = cert; // Shouldn't need this either here. - options.Alpn = "h3-25"; // Shouldn't need to populate this as well. + options.Alpn = "h3-29"; // Shouldn't need to populate this as well. options.IdleTimeout = TimeSpan.FromHours(1); }) .ConfigureKestrel((context, options) => @@ -42,7 +42,7 @@ namespace Http3SampleApp { httpsOptions.ServerCertificate = cert; }); - listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; + listenOptions.Protocols = HttpProtocols.Http3; }); }) .UseStartup(); diff --git a/src/Servers/Kestrel/samples/QuicSampleApp/Program.cs b/src/Servers/Kestrel/samples/QuicSampleApp/Program.cs deleted file mode 100644 index ca3cc0e643..0000000000 --- a/src/Servers/Kestrel/samples/QuicSampleApp/Program.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Buffers; -using System.Net; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Connections; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace QuicSampleApp -{ - public class Startup - { - public void Configure(IApplicationBuilder app) - { - app.Run((httpContext) => - { - return Task.CompletedTask; - }); - } - - public static void Main(string[] args) - { - var hostBuilder = new HostBuilder() - .ConfigureWebHost(webHostBuilder => - { - webHostBuilder - .UseKestrel() - .UseQuic(options => - { - options.Certificate = null; - options.Alpn = "QuicTest"; - options.IdleTimeout = TimeSpan.FromHours(1); - }) - .ConfigureKestrel((context, options) => - { - var basePort = 5555; - - options.Listen(IPAddress.Any, basePort, listenOptions => - { - listenOptions.Protocols = HttpProtocols.Http3; - - async Task EchoServer(MultiplexedConnectionContext connection) - { - // For graceful shutdown - - while (true) - { - var stream = await connection.AcceptAsync(); - while (true) - { - var result = await stream.Transport.Input.ReadAsync(); - - if (result.IsCompleted) - { - break; - } - - await stream.Transport.Output.WriteAsync(result.Buffer.ToArray()); - - stream.Transport.Input.AdvanceTo(result.Buffer.End); - } - } - } - - ((IMultiplexedConnectionBuilder)listenOptions).Use(next => - { - return context => - { - return EchoServer(context); - }; - }); - }); - }) - .UseStartup(); - }) - .ConfigureLogging((_, factory) => - { - factory.SetMinimumLevel(LogLevel.Debug); - factory.AddConsole(); - }); - - hostBuilder.Build().Run(); - } - } -} diff --git a/src/Servers/Kestrel/samples/QuicSampleApp/QuicSampleApp.csproj b/src/Servers/Kestrel/samples/QuicSampleApp/QuicSampleApp.csproj deleted file mode 100644 index ac3e766cae..0000000000 --- a/src/Servers/Kestrel/samples/QuicSampleApp/QuicSampleApp.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - $(DefaultNetCoreTargetFramework) - true - false - - - - - - - - - - - true - - - - - - true - - - - diff --git a/src/Servers/Kestrel/samples/QuicSampleApp/appsettings.Development.json b/src/Servers/Kestrel/samples/QuicSampleApp/appsettings.Development.json deleted file mode 100644 index e203e9407e..0000000000 --- a/src/Servers/Kestrel/samples/QuicSampleApp/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/src/Servers/Kestrel/samples/QuicSampleApp/appsettings.json b/src/Servers/Kestrel/samples/QuicSampleApp/appsettings.json deleted file mode 100644 index d9d9a9bff6..0000000000 --- a/src/Servers/Kestrel/samples/QuicSampleApp/appsettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*" -} diff --git a/src/Servers/Kestrel/samples/QuicSampleClient/Program.cs b/src/Servers/Kestrel/samples/QuicSampleClient/Program.cs deleted file mode 100644 index 5ced2cc44b..0000000000 --- a/src/Servers/Kestrel/samples/QuicSampleClient/Program.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Buffers; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic; -using Microsoft.Extensions.Hosting; -using Microsoft.AspNetCore.Connections; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; - -namespace QuicSampleClient -{ - class Program - { - static async Task Main(string[] args) - { - var host = new HostBuilder() - .ConfigureLogging(loggingBuilder => - { - loggingBuilder.AddConsole(); - loggingBuilder.SetMinimumLevel(LogLevel.Error); - }) - .ConfigureServices(services => - { - services.AddSingleton(); - services.AddSingleton(); - services.AddOptions(); - services.Configure((options) => - { - options.Alpn = "QuicTest"; - options.Certificate = null; - options.IdleTimeout = TimeSpan.FromHours(1); - }); - }) - .Build(); - await host.Services.GetService().RunAsync(); - } - - private class QuicClientService - { - private readonly IMultiplexedConnectionFactory _connectionFactory; - private readonly ILogger _logger; - public QuicClientService(IMultiplexedConnectionFactory connectionFactory, ILogger logger) - { - _connectionFactory = connectionFactory; - _logger = logger; - } - - public async Task RunAsync() - { - Console.WriteLine("Starting"); - var connectionContext = await _connectionFactory.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 5555)); - var streamContext = await connectionContext.ConnectAsync(); - - Console.CancelKeyPress += new ConsoleCancelEventHandler((sender, args) => - { - streamContext.Transport.Input.CancelPendingRead(); - streamContext.Transport.Output.CancelPendingFlush(); - }); - - var input = "asdf"; - while (true) - { - try - { - //var input = Console.ReadLine(); - if (input.Length == 0) - { - continue; - } - var flushResult = await streamContext.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes(input)); - if (flushResult.IsCanceled) - { - break; - } - - var readResult = await streamContext.Transport.Input.ReadAsync(); - if (readResult.IsCanceled || readResult.IsCompleted) - { - break; - } - - if (readResult.Buffer.Length > 0) - { - Console.WriteLine(Encoding.ASCII.GetString(readResult.Buffer.ToArray())); - } - - streamContext.Transport.Input.AdvanceTo(readResult.Buffer.End); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - break; - } - } - - await streamContext.Transport.Input.CompleteAsync(); - await streamContext.Transport.Output.CompleteAsync(); - } - } - } -} diff --git a/src/Servers/Kestrel/samples/QuicSampleClient/QuicSampleClient.csproj b/src/Servers/Kestrel/samples/QuicSampleClient/QuicSampleClient.csproj deleted file mode 100644 index 38725e4cbb..0000000000 --- a/src/Servers/Kestrel/samples/QuicSampleClient/QuicSampleClient.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - Exe - $(DefaultNetCoreTargetFramework) - - - - - - - - - - - - true - - - - - - true - - - - diff --git a/src/Servers/Kestrel/samples/http2cat/http2cat.csproj b/src/Servers/Kestrel/samples/http2cat/http2cat.csproj index 14fcf4b5e7..4b701a6e5f 100644 --- a/src/Servers/Kestrel/samples/http2cat/http2cat.csproj +++ b/src/Servers/Kestrel/samples/http2cat/http2cat.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Servers/Kestrel/shared/TransportMultiplexedConnection.cs b/src/Servers/Kestrel/shared/TransportMultiplexedConnection.cs index 7dea0569b9..bdfa8e76bc 100644 --- a/src/Servers/Kestrel/shared/TransportMultiplexedConnection.cs +++ b/src/Servers/Kestrel/shared/TransportMultiplexedConnection.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO.Pipelines; using System.Net; using System.Threading; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Http.Features; namespace Microsoft.AspNetCore.Connections diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3TestBase.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3TestBase.cs index 07afb75f28..8837658b86 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3TestBase.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3TestBase.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Experimental; using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features;