Пример #1
0
    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);
    }
Пример #2
0
    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();
    }
Пример #3
0
    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();
    }
Пример #4
0
    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();
    }
Пример #5
0
    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();
    }
Пример #6
0
    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());
            }
    }
Пример #7
0
    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();
    }
Пример #8
0
    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());
        }
    }