Allow more than one IConnectionListenerFactory (#17383)

This commit is contained in:
Stephen Halter 2019-11-25 14:19:25 -08:00 committed by GitHub
parent cf116a7815
commit b81c1a7954
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 84 additions and 40 deletions

View File

@ -559,7 +559,8 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
</data>
<data name="HttpParserTlsOverHttpError" xml:space="preserve">
<value>Detected a TLS handshake to an endpoint that does not have TLS enabled.</value>
</data> <data name="BadDeveloperCertificateState" xml:space="preserve">
</data>
<data name="BadDeveloperCertificateState" xml:space="preserve">
<value>The ASP.NET Core developer certificate is in an invalid state. To fix this issue, run the following commands 'dotnet dev-certs https --clean' and 'dotnet dev-certs https' to remove all existing ASP.NET Core development certificates and create a new untrusted developer certificate. On macOS or Windows, use 'dotnet dev-certs https --trust' to trust the new certificate.</value>
</data>
<data name="QPackErrorIndexOutOfRange" xml:space="preserve">
@ -574,4 +575,10 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
<data name="QPackStringLengthTooLarge" xml:space="preserve">
<value>Decoded string length of {length} octets is greater than the configured maximum length of {maxStringLength} octets.</value>
</data>
<data name="QuicTransportNotFound" xml:space="preserve">
<value>Quic transport not found when using HTTP/3.</value>
</data>
<data name="TransportNotFound" xml:space="preserve">
<value>Unable to resolve service for type 'Microsoft.AspNetCore.Connections.IConnectionListenerFactory' while attempting to activate 'Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer'.</value>
</data>
</root>

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
{
private readonly List<(IConnectionListener, Task)> _transports = new List<(IConnectionListener, Task)>();
private readonly IServerAddressesFeature _serverAddresses;
private readonly IEnumerable<IConnectionListenerFactory> _transportFactories;
private readonly List<IConnectionListenerFactory> _transportFactories;
private bool _hasStarted;
private int _stopping;
@ -42,7 +42,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
throw new ArgumentNullException(nameof(transportFactories));
}
_transportFactories = transportFactories;
_transportFactories = transportFactories.ToList();
if (_transportFactories.Count == 0)
{
throw new InvalidOperationException(CoreStrings.TransportNotFound);
}
ServiceContext = serviceContext;
Features = new FeatureCollection();
@ -143,19 +149,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
{
if (transportFactory is IMultiplexedConnectionListenerFactory)
{
// Don't break early. Always use the last registered factory.
factory = transportFactory;
break;
}
}
if (factory == null)
{
throw new Exception("Quic transport not found when using HTTP/3");
throw new InvalidOperationException(CoreStrings.QuicTransportNotFound);
}
}
else
{
factory = _transportFactories.Single();
factory = _transportFactories.Last();
}
var transport = await factory.BindAsync(options.EndPoint).ConfigureAwait(false);

View File

@ -204,22 +204,45 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var mockLoggerFactory = new Mock<ILoggerFactory>();
var mockLogger = new Mock<ILogger>();
mockLoggerFactory.Setup(m => m.CreateLogger(It.IsAny<string>())).Returns(mockLogger.Object);
new KestrelServer(Options.Create<KestrelServerOptions>(null), Mock.Of<IEnumerable<IConnectionListenerFactory>>(), mockLoggerFactory.Object);
new KestrelServer(Options.Create<KestrelServerOptions>(null), new List<IConnectionListenerFactory>() { new MockTransportFactory() }, mockLoggerFactory.Object);
mockLoggerFactory.Verify(factory => factory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel"));
}
[Fact]
public void StartWithNoTransportFactoryThrows()
public void ConstructorWithNullTransportFactoriesThrows()
{
var mockLoggerFactory = new Mock<ILoggerFactory>();
var mockLogger = new Mock<ILogger>();
mockLoggerFactory.Setup(m => m.CreateLogger(It.IsAny<string>())).Returns(mockLogger.Object);
var exception = Assert.Throws<ArgumentNullException>(() =>
new KestrelServer(Options.Create<KestrelServerOptions>(null), null, mockLoggerFactory.Object));
new KestrelServer(
Options.Create<KestrelServerOptions>(null),
null,
new LoggerFactory(new[] { new KestrelTestLoggerProvider() })));
Assert.Equal("transportFactories", exception.ParamName);
}
[Fact]
public void ConstructorWithNoTransportFactoriesThrows()
{
var exception = Assert.Throws<InvalidOperationException>(() =>
new KestrelServer(
Options.Create<KestrelServerOptions>(null),
new List<IConnectionListenerFactory>(),
new LoggerFactory(new[] { new KestrelTestLoggerProvider() })));
Assert.Equal(CoreStrings.TransportNotFound, exception.Message);
}
[Fact]
public void StartWithMultipleTransportFactoriesDoesNotThrow()
{
using var server = new KestrelServer(
Options.Create(CreateServerOptions()),
new List<IConnectionListenerFactory>() { new ThrowingTransportFactory(), new MockTransportFactory() },
new LoggerFactory(new[] { new KestrelTestLoggerProvider() }));
StartDummyApplication(server);
}
[Fact]
public async Task StopAsyncCallsCompleteWhenFirstCallCompletes()
{
@ -456,5 +479,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
return new ValueTask<IConnectionListener>(mock.Object);
}
}
private class ThrowingTransportFactory : IConnectionListenerFactory
{
public ValueTask<IConnectionListener> BindAsync(EndPoint endpoint, CancellationToken cancellationToken = default)
{
throw new InvalidOperationException();
}
}
}
}