Add async ServerOptionsSelectionCallback UseHttps overload (#25390)
This commit is contained in:
parent
071a539ae5
commit
04f23ecfc4
|
|
@ -6,7 +6,6 @@ using System.IO;
|
|||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Https.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -209,7 +208,8 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure Kestrel to use HTTPS.
|
||||
/// Configure Kestrel to use HTTPS. This does not use default certificates or other defaults specified via config or
|
||||
/// <see cref="KestrelServerOptions.ConfigureHttpsDefaults(Action{HttpsConnectionAdapterOptions})"/>.
|
||||
/// </summary>
|
||||
/// <param name="listenOptions">The <see cref="ListenOptions"/> to configure.</param>
|
||||
/// <param name="httpsOptions">Options to configure HTTPS.</param>
|
||||
|
|
@ -230,12 +230,44 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
return listenOptions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure Kestrel to use HTTPS. This does not use default certificates or other defaults specified via config or
|
||||
/// <see cref="KestrelServerOptions.ConfigureHttpsDefaults(Action{HttpsConnectionAdapterOptions})"/>.
|
||||
/// </summary>
|
||||
/// <param name="listenOptions">The <see cref="ListenOptions"/> to configure.</param>
|
||||
/// <param name="serverOptionsSelectionCallback">Callback to configure HTTPS options.</param>
|
||||
/// <param name="state">State for the <paramref name="serverOptionsSelectionCallback"/>.</param>
|
||||
/// <returns>The <see cref="ListenOptions"/>.</returns>
|
||||
public static ListenOptions UseHttps(this ListenOptions listenOptions, ServerOptionsSelectionCallback serverOptionsSelectionCallback, object state)
|
||||
{
|
||||
return listenOptions.UseHttps(serverOptionsSelectionCallback, state, HttpsConnectionAdapterOptions.DefaultHandshakeTimeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure Kestrel to use HTTPS. This does not use default certificates or other defaults specified via config or
|
||||
/// <see cref="KestrelServerOptions.ConfigureHttpsDefaults(Action{HttpsConnectionAdapterOptions})"/>.
|
||||
/// </summary>
|
||||
/// <param name="listenOptions">The <see cref="ListenOptions"/> to configure.</param>
|
||||
/// <param name="serverOptionsSelectionCallback">Callback to configure HTTPS options.</param>
|
||||
/// <param name="state">State for the <paramref name="serverOptionsSelectionCallback"/>.</param>
|
||||
/// <param name="handshakeTimeout">Specifies the maximum amount of time allowed for the TLS/SSL handshake. This must be positive and finite.</param>
|
||||
/// <returns>The <see cref="ListenOptions"/>.</returns>
|
||||
public static ListenOptions UseHttps(this ListenOptions listenOptions, ServerOptionsSelectionCallback serverOptionsSelectionCallback, object state, TimeSpan handshakeTimeout)
|
||||
{
|
||||
// HttpsOptionsCallback is an internal delegate that is just the ServerOptionsSelectionCallback + a ConnectionContext parameter.
|
||||
// Given that ConnectionContext will eventually be replaced by System.Net.Connections, it doesn't make much sense to make the HttpsOptionsCallback delegate public.
|
||||
HttpsOptionsCallback adaptedCallback = (connection, stream, clientHelloInfo, state, cancellationToken) =>
|
||||
serverOptionsSelectionCallback(stream, clientHelloInfo, state, cancellationToken);
|
||||
|
||||
return listenOptions.UseHttps(adaptedCallback, state, handshakeTimeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure Kestrel to use HTTPS.
|
||||
/// </summary>
|
||||
/// <param name="listenOptions">The <see cref="ListenOptions"/> to configure.</param>
|
||||
/// <param name="httpsOptionsCallback">Callback to configure HTTPS options.</param>
|
||||
/// <param name="state">State for the <see cref="ServerOptionsSelectionCallback" />.</param>
|
||||
/// <param name="state">State for the <paramref name="httpsOptionsCallback"/>.</param>
|
||||
/// <param name="handshakeTimeout">Specifies the maximum amount of time allowed for the TLS/SSL handshake. This must be positive and finite.</param>
|
||||
/// <returns>The <see cref="ListenOptions"/>.</returns>
|
||||
internal static ListenOptions UseHttps(this ListenOptions listenOptions, HttpsOptionsCallback httpsOptionsCallback, object state, TimeSpan handshakeTimeout)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -109,15 +110,21 @@ namespace SampleApp
|
|||
|
||||
options.ListenAnyIP(basePort + 5, listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(httpsOptions =>
|
||||
var localhostCert = CertificateLoader.LoadFromStoreCert("localhost", "My", StoreLocation.CurrentUser, allowInvalid: true);
|
||||
|
||||
listenOptions.UseHttps((stream, clientHelloInfo, state, cancellationToken) =>
|
||||
{
|
||||
var localhostCert = CertificateLoader.LoadFromStoreCert("localhost", "My", StoreLocation.CurrentUser, allowInvalid: true);
|
||||
httpsOptions.ServerCertificateSelector = (features, name) =>
|
||||
// Here you would check the name, select an appropriate cert, and provide a fallback or fail for null names.
|
||||
if (clientHelloInfo.ServerName != null && clientHelloInfo.ServerName != "localhost")
|
||||
{
|
||||
// Here you would check the name, select an appropriate cert, and provide a fallback or fail for null names.
|
||||
return localhostCert;
|
||||
};
|
||||
});
|
||||
throw new AuthenticationException($"The endpoint is not configured for sever name '{clientHelloInfo.ServerName}'.");
|
||||
}
|
||||
|
||||
return new ValueTask<SslServerAuthenticationOptions>(new SslServerAuthenticationOptions
|
||||
{
|
||||
ServerCertificate = localhostCert
|
||||
});
|
||||
}, state: null);
|
||||
});
|
||||
|
||||
options
|
||||
|
|
|
|||
|
|
@ -123,6 +123,42 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandshakeDetailsAreAvailableAfterAsyncCallback()
|
||||
{
|
||||
void ConfigureListenOptions(ListenOptions listenOptions)
|
||||
{
|
||||
listenOptions.UseHttps(async (stream, clientHelloInfo, state, cancellationToken) =>
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
return new SslServerAuthenticationOptions
|
||||
{
|
||||
ServerCertificate = _x509Certificate2,
|
||||
};
|
||||
}, state: null);
|
||||
}
|
||||
|
||||
await using (var server = new TestServer(context =>
|
||||
{
|
||||
var tlsFeature = context.Features.Get<ITlsHandshakeFeature>();
|
||||
Assert.NotNull(tlsFeature);
|
||||
Assert.True(tlsFeature.Protocol > SslProtocols.None, "Protocol");
|
||||
Assert.True(tlsFeature.CipherAlgorithm > CipherAlgorithmType.Null, "Cipher");
|
||||
Assert.True(tlsFeature.CipherStrength > 0, "CipherStrength");
|
||||
Assert.True(tlsFeature.HashAlgorithm >= HashAlgorithmType.None, "HashAlgorithm"); // May be None on Linux.
|
||||
Assert.True(tlsFeature.HashStrength >= 0, "HashStrength"); // May be 0 for some algorithms
|
||||
Assert.True(tlsFeature.KeyExchangeAlgorithm >= ExchangeAlgorithmType.None, "KeyExchangeAlgorithm"); // Maybe None on Windows 7
|
||||
Assert.True(tlsFeature.KeyExchangeStrength >= 0, "KeyExchangeStrength"); // May be 0 on mac
|
||||
|
||||
return context.Response.WriteAsync("hello world");
|
||||
}, new TestServiceContext(LoggerFactory), ConfigureListenOptions))
|
||||
{
|
||||
var result = await server.HttpClientSlim.GetStringAsync($"https://localhost:{server.Port}/", validateCertificate: false);
|
||||
Assert.Equal("hello world", result);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequireCertificateFailsWhenNoCertificate()
|
||||
{
|
||||
|
|
@ -166,22 +202,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
[QuarantinedTest("https://github.com/dotnet/runtime/issues/40402")]
|
||||
public async Task ClientCertificateRequiredConfiguredInCallbackContinuesWhenNoCertificate()
|
||||
public async Task AsyncCallbackSettingClientCertificateRequiredContinuesWhenNoCertificate()
|
||||
{
|
||||
void ConfigureListenOptions(ListenOptions listenOptions)
|
||||
{
|
||||
listenOptions.UseHttps((connection, stream, clientHelloInfo, state, cancellationToken) =>
|
||||
listenOptions.UseHttps((stream, clientHelloInfo, state, cancellationToken) =>
|
||||
new ValueTask<SslServerAuthenticationOptions>(new SslServerAuthenticationOptions
|
||||
{
|
||||
ServerCertificate = _x509Certificate2,
|
||||
// From the API Docs: "Note that this is only a request --
|
||||
// if no certificate is provided, the server still accepts the connection request."
|
||||
// Not to mention this is equivalent to the test above.
|
||||
ClientCertificateRequired = true,
|
||||
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true,
|
||||
CertificateRevocationCheckMode = X509RevocationMode.NoCheck
|
||||
}), state: null, HttpsConnectionAdapterOptions.DefaultHandshakeTimeout);
|
||||
}), state: null);
|
||||
}
|
||||
|
||||
await using (var server = new TestServer(context =>
|
||||
|
|
@ -255,6 +287,39 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UsesProvidedAsyncCallback()
|
||||
{
|
||||
var selectorCalled = 0;
|
||||
void ConfigureListenOptions(ListenOptions listenOptions)
|
||||
{
|
||||
listenOptions.UseHttps(async (stream, clientHelloInfo, state, cancellationToken) =>
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
Assert.NotNull(stream);
|
||||
Assert.Equal("localhost", clientHelloInfo.ServerName);
|
||||
selectorCalled++;
|
||||
|
||||
return new SslServerAuthenticationOptions
|
||||
{
|
||||
ServerCertificate = _x509Certificate2
|
||||
};
|
||||
}, state: null);
|
||||
}
|
||||
|
||||
await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory), ConfigureListenOptions))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
var stream = OpenSslStream(connection.Stream);
|
||||
await stream.AuthenticateAsClientAsync("localhost");
|
||||
Assert.True(stream.RemoteCertificate.Equals(_x509Certificate2));
|
||||
Assert.Equal(1, selectorCalled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UsesProvidedServerCertificateSelectorEachTime()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Security;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
|
@ -13,7 +12,6 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Https.Internal;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.TestTransport;
|
||||
|
|
@ -21,13 +19,14 @@ using Microsoft.AspNetCore.Testing;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
||||
{
|
||||
public class HttpsTests : LoggedTest
|
||||
{
|
||||
private static X509Certificate2 _x509Certificate2 = TestResources.GetTestCertificate();
|
||||
|
||||
private KestrelServerOptions CreateServerOptions()
|
||||
{
|
||||
var serverOptions = new KestrelServerOptions();
|
||||
|
|
@ -41,8 +40,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
public void UseHttpsDefaultsToDefaultCert()
|
||||
{
|
||||
var serverOptions = CreateServerOptions();
|
||||
var defaultCert = TestResources.GetTestCertificate();
|
||||
serverOptions.DefaultCertificate = defaultCert;
|
||||
serverOptions.DefaultCertificate = _x509Certificate2;
|
||||
|
||||
serverOptions.ListenLocalhost(5000, options =>
|
||||
{
|
||||
|
|
@ -62,22 +60,51 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
Assert.False(serverOptions.IsDevCertLoaded);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UseHttpsWithAsyncCallbackDoeNotFallBackToDefaultCert()
|
||||
{
|
||||
var loggerProvider = new HandshakeErrorLoggerProvider();
|
||||
LoggerFactory.AddProvider(loggerProvider);
|
||||
|
||||
var testContext = new TestServiceContext(LoggerFactory);
|
||||
|
||||
await using (var server = new TestServer(context => Task.CompletedTask,
|
||||
testContext,
|
||||
listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps((stream, clientHelloInfo, state, cancellationToken) =>
|
||||
new ValueTask<SslServerAuthenticationOptions>(new SslServerAuthenticationOptions()), state: null);
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
using (var sslStream = new SslStream(connection.Stream, true, (sender, certificate, chain, errors) => true))
|
||||
{
|
||||
var ex = await Assert.ThrowsAnyAsync<Exception>(() =>
|
||||
sslStream.AuthenticateAsClientAsync("127.0.0.1", clientCertificates: null,
|
||||
enabledSslProtocols: SslProtocols.Tls,
|
||||
checkCertificateRevocation: false));
|
||||
}
|
||||
}
|
||||
|
||||
var errorException = Assert.Single(loggerProvider.ErrorLogger.ErrorExceptions);
|
||||
Assert.IsType<NotSupportedException>(errorException);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConfigureHttpsDefaultsNeverLoadsDefaultCert()
|
||||
{
|
||||
var serverOptions = CreateServerOptions();
|
||||
var testCert = TestResources.GetTestCertificate();
|
||||
serverOptions.ConfigureHttpsDefaults(options =>
|
||||
{
|
||||
Assert.Null(options.ServerCertificate);
|
||||
options.ServerCertificate = testCert;
|
||||
options.ServerCertificate = _x509Certificate2;
|
||||
options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
|
||||
});
|
||||
serverOptions.ListenLocalhost(5000, options =>
|
||||
{
|
||||
options.UseHttps(opt =>
|
||||
{
|
||||
Assert.Equal(testCert, opt.ServerCertificate);
|
||||
Assert.Equal(_x509Certificate2, opt.ServerCertificate);
|
||||
Assert.Equal(ClientCertificateMode.RequireCertificate, opt.ClientCertificateMode);
|
||||
});
|
||||
});
|
||||
|
|
@ -90,14 +117,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
public void ConfigureCertSelectorNeverLoadsDefaultCert()
|
||||
{
|
||||
var serverOptions = CreateServerOptions();
|
||||
var testCert = TestResources.GetTestCertificate();
|
||||
serverOptions.ConfigureHttpsDefaults(options =>
|
||||
{
|
||||
Assert.Null(options.ServerCertificate);
|
||||
Assert.Null(options.ServerCertificateSelector);
|
||||
options.ServerCertificateSelector = (features, name) =>
|
||||
{
|
||||
return testCert;
|
||||
return _x509Certificate2;
|
||||
};
|
||||
options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
|
||||
});
|
||||
|
|
@ -126,7 +152,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
new TestServiceContext(LoggerFactory),
|
||||
listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(TestResources.GetTestCertificate());
|
||||
listenOptions.UseHttps(_x509Certificate2);
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
|
|
@ -139,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
|
||||
Assert.Equal(1, loggerProvider.FilterLogger.LastEventId.Id);
|
||||
Assert.Equal(LogLevel.Debug, loggerProvider.FilterLogger.LastLogLevel);
|
||||
Assert.True(loggerProvider.ErrorLogger.TotalErrorsLogged == 0,
|
||||
Assert.True(loggerProvider.ErrorLogger.ErrorMessages.Count == 0,
|
||||
userMessage: string.Join(Environment.NewLine, loggerProvider.ErrorLogger.ErrorMessages));
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +180,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
new TestServiceContext(LoggerFactory),
|
||||
listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(TestResources.GetTestCertificate());
|
||||
listenOptions.UseHttps(_x509Certificate2);
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
|
|
@ -168,7 +194,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
|
||||
Assert.Equal(1, loggerProvider.FilterLogger.LastEventId.Id);
|
||||
Assert.Equal(LogLevel.Debug, loggerProvider.FilterLogger.LastLogLevel);
|
||||
Assert.True(loggerProvider.ErrorLogger.TotalErrorsLogged == 0,
|
||||
Assert.True(loggerProvider.ErrorLogger.ErrorMessages.Count == 0,
|
||||
userMessage: string.Join(Environment.NewLine, loggerProvider.ErrorLogger.ErrorMessages));
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +224,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
new TestServiceContext(LoggerFactory),
|
||||
listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(TestResources.GetTestCertificate());
|
||||
listenOptions.UseHttps(_x509Certificate2);
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
|
|
@ -242,7 +268,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
new TestServiceContext(LoggerFactory),
|
||||
listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(TestResources.GetTestCertificate());
|
||||
listenOptions.UseHttps(_x509Certificate2);
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
|
|
@ -273,7 +299,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
new TestServiceContext(LoggerFactory),
|
||||
listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(TestResources.GetTestCertificate());
|
||||
listenOptions.UseHttps(_x509Certificate2);
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
|
|
@ -299,7 +325,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
new TestServiceContext(LoggerFactory),
|
||||
listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(TestResources.GetTestCertificate());
|
||||
listenOptions.UseHttps(_x509Certificate2);
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
|
|
@ -316,10 +342,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
LoggerFactory.AddProvider(loggerProvider);
|
||||
|
||||
var testContext = new TestServiceContext(LoggerFactory);
|
||||
var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager);
|
||||
|
||||
var handshakeStartedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
TimeSpan handshakeTimeout = default;
|
||||
|
||||
await using (var server = new TestServer(context => Task.CompletedTask,
|
||||
testContext,
|
||||
|
|
@ -327,26 +349,47 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
{
|
||||
listenOptions.UseHttps(o =>
|
||||
{
|
||||
o.ServerCertificate = new X509Certificate2(TestResources.GetTestCertificate());
|
||||
o.OnAuthenticate = (_, __) =>
|
||||
{
|
||||
handshakeStartedTcs.SetResult();
|
||||
};
|
||||
|
||||
handshakeTimeout = o.HandshakeTimeout;
|
||||
o.ServerCertificate = new X509Certificate2(_x509Certificate2);
|
||||
o.HandshakeTimeout = TimeSpan.FromMilliseconds(100);
|
||||
});
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
// HttpsConnectionAdapter dispatches via Task.Run() before starting the handshake.
|
||||
// Wait for the handshake to start before advancing the system clock.
|
||||
await handshakeStartedTcs.Task.DefaultTimeout();
|
||||
Assert.Equal(0, await connection.Stream.ReadAsync(new byte[1], 0, 1).DefaultTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
// Min amount of time between requests that triggers a handshake timeout.
|
||||
testContext.MockSystemClock.UtcNow += handshakeTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1);
|
||||
heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow);
|
||||
await loggerProvider.FilterLogger.LogTcs.Task.DefaultTimeout();
|
||||
Assert.Equal(2, loggerProvider.FilterLogger.LastEventId);
|
||||
Assert.Equal(LogLevel.Debug, loggerProvider.FilterLogger.LastLogLevel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandshakeTimesOutAndIsLoggedAsDebugWithAsyncCallback()
|
||||
{
|
||||
var loggerProvider = new HandshakeErrorLoggerProvider();
|
||||
LoggerFactory.AddProvider(loggerProvider);
|
||||
|
||||
var testContext = new TestServiceContext(LoggerFactory);
|
||||
|
||||
await using (var server = new TestServer(context => Task.CompletedTask,
|
||||
testContext,
|
||||
listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(async (stream, clientHelloInfo, state, cancellationToken) =>
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
return new SslServerAuthenticationOptions
|
||||
{
|
||||
ServerCertificate = _x509Certificate2,
|
||||
};
|
||||
}, state: null, handshakeTimeout: TimeSpan.FromMilliseconds(100));
|
||||
}))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
Assert.Equal(0, await connection.Stream.ReadAsync(new byte[1], 0, 1).DefaultTimeout());
|
||||
}
|
||||
}
|
||||
|
|
@ -394,7 +437,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
var loggerProvider = new HandshakeErrorLoggerProvider();
|
||||
LoggerFactory.AddProvider(loggerProvider);
|
||||
|
||||
var testCert = TestResources.GetTestCertificate();
|
||||
var testCert = _x509Certificate2;
|
||||
var onAuthenticateCalled = false;
|
||||
|
||||
await using (var server = new TestServer(context => Task.CompletedTask,
|
||||
|
|
@ -430,7 +473,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
var loggerProvider = new HandshakeErrorLoggerProvider();
|
||||
LoggerFactory.AddProvider(loggerProvider);
|
||||
|
||||
var testCert = TestResources.GetTestCertificate();
|
||||
var testCert = _x509Certificate2;
|
||||
var onAuthenticateCalled = false;
|
||||
|
||||
await using (var server = new TestServer(context => Task.CompletedTask,
|
||||
|
|
@ -511,11 +554,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
|
||||
private class ApplicationErrorLogger : ILogger
|
||||
{
|
||||
private List<string> _errorMessages = new List<string>();
|
||||
|
||||
public IEnumerable<string> ErrorMessages => _errorMessages;
|
||||
|
||||
public int TotalErrorsLogged => _errorMessages.Count;
|
||||
public List<string> ErrorMessages => new List<string>();
|
||||
public List<Exception> ErrorExceptions { get; } = new List<Exception>();
|
||||
|
||||
public bool ObjectDisposedExceptionLogged { get; set; }
|
||||
|
||||
|
|
@ -524,7 +564,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
if (logLevel == LogLevel.Error)
|
||||
{
|
||||
var log = $"Log {logLevel}[{eventId}]: {formatter(state, exception)} {exception}";
|
||||
_errorMessages.Add(log);
|
||||
ErrorMessages.Add(log);
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
ErrorExceptions.Add(exception);
|
||||
}
|
||||
}
|
||||
|
||||
if (exception is ObjectDisposedException)
|
||||
|
|
|
|||
Loading…
Reference in New Issue