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;