public async Task OnAuthentice_Available_Throws() { var builder = CreateHostBuilder(async context => { await context.Response.WriteAsync("Hello World"); }, configureKestrel: kestrelOptions => { kestrelOptions.ListenAnyIP(0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http3; listenOptions.UseHttps(httpsOptions => { httpsOptions.OnAuthenticate = (_, _) => { }; }); }); }); using var host = builder.Build(); using var client = HttpHelpers.CreateClient(); var exception = await Assert.ThrowsAsync <NotSupportedException>(() => host.StartAsync().DefaultTimeout()); Assert.Equal("The OnAuthenticate callback is not supported with HTTP/3.", exception.Message); }
public async Task ClientCertificate_AllowOrRequire_Available_Invalid_Refused(ClientCertificateMode mode, bool serverAllowInvalid) { var builder = CreateHostBuilder(async context => { var hasCert = context.Connection.ClientCertificate != null; await context.Response.WriteAsync(hasCert.ToString()); }, configureKestrel: kestrelOptions => { kestrelOptions.ListenAnyIP(0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http3; listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificate = TestResources.GetTestCertificate(); httpsOptions.ClientCertificateMode = mode; if (serverAllowInvalid) { httpsOptions.AllowAnyClientCertificate(); // The self-signed cert is invalid. Let it fail the default checks. } }); }); }); using var host = builder.Build(); using var client = HttpHelpers.CreateClient(includeClientCert: true); await host.StartAsync().DefaultTimeout(); var request = new HttpRequestMessage(HttpMethod.Get, $"https://127.0.0.1:{host.GetPort()}/"); request.Version = HttpVersion.Version30; request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; var sendTask = client.SendAsync(request, CancellationToken.None); if (!serverAllowInvalid) { // In .NET 6 there is a race condition between throwing HttpRequestException and QuicException. // Unable to test the exact error. var ex = await Assert.ThrowsAnyAsync <Exception>(() => sendTask).DefaultTimeout(); Logger.LogInformation(ex, "SendAsync successfully threw error."); } else { // Because we can't verify the exact error reason, check that the cert is the cause be successfully // making a call when invalid certs are allowed. var response = await sendTask.DefaultTimeout(); response.EnsureSuccessStatusCode(); } await host.StopAsync().DefaultTimeout(); }
public async Task TlsHandshakeCallbackOptions_Invoked() { var configuredState = new object(); object callbackState = null; var builder = CreateHostBuilder(async context => { await context.Response.WriteAsync("Hello World"); }, configureKestrel: kestrelOptions => { kestrelOptions.ListenAnyIP(0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http3; listenOptions.UseHttps(new TlsHandshakeCallbackOptions { OnConnection = (context) => { callbackState = context.State; return(ValueTask.FromResult(new SslServerAuthenticationOptions { ServerCertificate = TestResources.GetTestCertificate(), ApplicationProtocols = new List <SslApplicationProtocol> { SslApplicationProtocol.Http3 } })); }, OnConnectionState = configuredState }); }); }); using var host = builder.Build(); using var client = HttpHelpers.CreateClient(); await host.StartAsync().DefaultTimeout(); var request = new HttpRequestMessage(HttpMethod.Get, $"https://127.0.0.1:{host.GetPort()}/"); request.Version = HttpVersion.Version30; request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; request.Headers.Host = "testhost"; var response = await client.SendAsync(request, CancellationToken.None).DefaultTimeout(); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpVersion.Version30, response.Version); Assert.Equal("Hello World", result); Assert.Equal(configuredState, callbackState); await host.StopAsync().DefaultTimeout(); }
public async Task ServerCertificateSelector_Invoked() { var builder = CreateHostBuilder(async context => { await context.Response.WriteAsync("Hello World"); }, configureKestrel: kestrelOptions => { kestrelOptions.ListenAnyIP(0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http3; listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificateSelector = (context, host) => { Assert.Null(context); // The context isn't available durring the quic handshake. Assert.Equal("localhost", host); return(TestResources.GetTestCertificate()); }; }); }); }); using var host = builder.Build(); using var client = HttpHelpers.CreateClient(); await host.StartAsync().DefaultTimeout(); // Using localhost instead of 127.0.0.1 because IPs don't set SNI and the Host header isn't currently used as an override. var request = new HttpRequestMessage(HttpMethod.Get, $"https://localhost:{host.GetPort()}/"); request.Version = HttpVersion.Version30; request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; // https://github.com/dotnet/runtime/issues/57169 Host isn't used for SNI request.Headers.Host = "testhost"; var response = await client.SendAsync(request, CancellationToken.None).DefaultTimeout(); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpVersion.Version30, response.Version); Assert.Equal("Hello World", result); await host.StopAsync().DefaultTimeout(); }
public async Task ClientCertificate_AllowOrRequire_Available_Accepted(ClientCertificateMode mode) { var builder = CreateHostBuilder(async context => { var hasCert = context.Connection.ClientCertificate != null; await context.Response.WriteAsync(hasCert.ToString()); }, configureKestrel: kestrelOptions => { kestrelOptions.ListenAnyIP(0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http3; listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificate = TestResources.GetTestCertificate(); httpsOptions.ClientCertificateMode = mode; httpsOptions.AllowAnyClientCertificate(); }); }); }); using var host = builder.Build(); using var client = HttpHelpers.CreateClient(includeClientCert: true); await host.StartAsync().DefaultTimeout(); var request = new HttpRequestMessage(HttpMethod.Get, $"https://127.0.0.1:{host.GetPort()}/"); request.Version = HttpVersion.Version30; request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; var response = await client.SendAsync(request, CancellationToken.None).DefaultTimeout(); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpVersion.Version30, response.Version); Assert.Equal("True", result); await host.StopAsync().DefaultTimeout(); }
public async Task GET_NoTLS_Http11RequestToHttp2Endpoint_400Result() { // Arrange var builder = CreateHostBuilder(c => Task.CompletedTask, protocol: HttpProtocols.Http2, plaintext: true); using (var host = builder.Build()) using (var client = HttpHelpers.CreateClient()) { await host.StartAsync().DefaultTimeout(); var request = new HttpRequestMessage(HttpMethod.Get, $"http://127.0.0.1:{host.GetPort()}/"); request.Version = HttpVersion.Version11; request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; // Act var responseMessage = await client.SendAsync(request, CancellationToken.None).DefaultTimeout(); // Assert Assert.Equal(HttpStatusCode.BadRequest, responseMessage.StatusCode); Assert.Equal("An HTTP/1.x request was sent to an HTTP/2 only endpoint.", await responseMessage.Content.ReadAsStringAsync()); } }
public async Task ClientCertificate_Allow_NotAvailable_Optional() { var builder = CreateHostBuilder(async context => { var hasCert = context.Connection.ClientCertificate != null; await context.Response.WriteAsync(hasCert.ToString()); }, configureKestrel: kestrelOptions => { kestrelOptions.ListenAnyIP(0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http3; listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificate = TestResources.GetTestCertificate(); httpsOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate; httpsOptions.AllowAnyClientCertificate(); }); }); }); using var host = builder.Build(); using var client = HttpHelpers.CreateClient(includeClientCert: false); await host.StartAsync().DefaultTimeout(); var request = new HttpRequestMessage(HttpMethod.Get, $"https://127.0.0.1:{host.GetPort()}/"); request.Version = HttpVersion.Version30; request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; // https://github.com/dotnet/runtime/issues/57308, optional client certs aren't supported. var ex = await Assert.ThrowsAsync <HttpRequestException>(() => client.SendAsync(request, CancellationToken.None).DefaultTimeout()); Assert.StartsWith("Connection has been shutdown by transport.", ex.Message); await host.StopAsync().DefaultTimeout(); }
public async Task GET_RequestReturnsLargeData_GracefulShutdownDuringRequest_RequestGracefullyCompletes(bool hasTrailers) { // Enable client logging. // Test failure on CI could be from HttpClient bug. using var httpEventSource = new HttpEventSourceListener(LoggerFactory); // Arrange const int DataLength = 500_000; var randomBytes = Enumerable.Range(1, DataLength).Select(i => (byte)((i % 10) + 48)).ToArray(); var syncPoint = new SyncPoint(); ILogger logger = null; var builder = CreateHostBuilder( async c => { await syncPoint.WaitToContinue(); var memory = c.Response.BodyWriter.GetMemory(randomBytes.Length); logger.LogInformation($"Server writing {randomBytes.Length} bytes response"); randomBytes.CopyTo(memory); // It's important for this test that the large write is the last data written to // the response and it's not awaited by the request delegate. logger.LogInformation($"Server advancing {randomBytes.Length} bytes response"); c.Response.BodyWriter.Advance(randomBytes.Length); if (hasTrailers) { c.Response.AppendTrailer("test-trailer", "value!"); } }, protocol: HttpProtocols.Http2, plaintext: true); using var host = builder.Build(); logger = host.Services.GetRequiredService <ILoggerFactory>().CreateLogger("Test"); var client = HttpHelpers.CreateClient(); // Act await host.StartAsync().DefaultTimeout(); var longRunningTask = StartLongRunningRequestAsync(logger, host, client); logger.LogInformation("Waiting for request on server"); await syncPoint.WaitForSyncPoint().DefaultTimeout(); logger.LogInformation("Stopping server"); var stopTask = host.StopAsync(); syncPoint.Continue(); var(readData, trailers) = await longRunningTask.DefaultTimeout(); await stopTask.DefaultTimeout(); // Assert Assert.Equal(randomBytes, readData); if (hasTrailers) { Assert.Equal("value!", trailers.GetValues("test-trailer").Single()); } }