diff --git a/.github/workflows/build-natives.yaml b/.github/workflows/build-natives.yaml
index d6a8659..3afd5b1 100644
--- a/.github/workflows/build-natives.yaml
+++ b/.github/workflows/build-natives.yaml
@@ -49,6 +49,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- run: cargo build --target x86_64-pc-windows-msvc --profile ${{ env._RUST_BUILD_CONFIG == 'debug' && 'dev' || env._RUST_BUILD_CONFIG }}
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
@@ -73,6 +75,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- run: rustup target add aarch64-pc-windows-msvc
- run: |
@@ -100,6 +104,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- run: rustup toolchain install nightly-2024-07-10-x86_64-pc-windows-msvc
- run: rustup component add rust-src --toolchain nightly-2024-07-10-x86_64-pc-windows-msvc
@@ -154,9 +160,9 @@ jobs:
env:
DEBIAN_FRONTEND: noninteractive
- uses: Cysharp/Actions/.github/actions/checkout@main
- - uses: Cysharp/Actions/.github/actions/setup-dotnet@main
with:
- dotnet-version: 8.0.x
+ submodules: true
+ - uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
- run: cargo build --target x86_64-unknown-linux-gnu --profile ${{ env._RUST_BUILD_CONFIG == 'debug' && 'dev' || env._RUST_BUILD_CONFIG }}
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
@@ -181,6 +187,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- run: rustup target add x86_64-apple-darwin
- run: cargo build --target x86_64-apple-darwin --profile ${{ env._RUST_BUILD_CONFIG == 'debug' && 'dev' || env._RUST_BUILD_CONFIG }}
@@ -206,6 +214,9 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
+ - uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- run: rustup target add aarch64-apple-darwin
- run: cargo build --target aarch64-apple-darwin --profile ${{ env._RUST_BUILD_CONFIG == 'debug' && 'dev' || env._RUST_BUILD_CONFIG }}
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
@@ -228,6 +239,8 @@ jobs:
timeout-minutes: 30
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- uses: Cysharp/Actions/.github/actions/download-artifact@main
with:
path: native/artifacts
@@ -250,6 +263,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- run: rustup target add x86_64-apple-ios
- run: cargo build --target x86_64-apple-ios --profile ${{ env._RUST_BUILD_CONFIG == 'debug' && 'dev' || env._RUST_BUILD_CONFIG }}
env:
@@ -272,6 +287,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- run: rustup target add aarch64-apple-ios
- run: cargo build --target aarch64-apple-ios --profile ${{ env._RUST_BUILD_CONFIG == 'debug' && 'dev' || env._RUST_BUILD_CONFIG }}
env:
@@ -294,6 +311,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- run: rustup target add aarch64-apple-ios-sim
- run: cargo build --target aarch64-apple-ios-sim --profile ${{ env._RUST_BUILD_CONFIG == 'debug' && 'dev' || env._RUST_BUILD_CONFIG }}
env:
@@ -316,6 +335,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- name: Use latest Android NDK
run: |
echo "ANDROID_NDK=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV
@@ -343,6 +364,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- name: Use latest Android NDK
run: |
echo "ANDROID_NDK=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV
@@ -370,6 +393,8 @@ jobs:
working-directory: native
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
- name: Use latest Android NDK
run: |
echo "ANDROID_NDK=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV
@@ -407,6 +432,9 @@ jobs:
timeout-minutes: 30
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
+ with:
+ submodules: true
+ - uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- uses: Cysharp/Actions/.github/actions/download-artifact@main
with:
path: native/artifacts
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..6b94f3e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "external/HttpClientTestServer"]
+ path = external/HttpClientTestServer
+ url = https://github.com/Cysharp/HttpClientTestServer.git
diff --git a/YetAnotherHttpHandler.slnx b/YetAnotherHttpHandler.slnx
index f362572..39d1ec6 100644
--- a/YetAnotherHttpHandler.slnx
+++ b/YetAnotherHttpHandler.slnx
@@ -14,8 +14,12 @@
-
+
+
+
+
+
diff --git a/external/HttpClientTestServer b/external/HttpClientTestServer
new file mode 160000
index 0000000..0f8be71
--- /dev/null
+++ b/external/HttpClientTestServer
@@ -0,0 +1 @@
+Subproject commit 0f8be7153c4ee789e97b40ef6c303fdf0d636843
diff --git a/test/YetAnotherHttpHandler.StandaloneTestServer/Program.cs b/test/YetAnotherHttpHandler.StandaloneTestServer/Program.cs
deleted file mode 100644
index acc22b9..0000000
--- a/test/YetAnotherHttpHandler.StandaloneTestServer/Program.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using _YetAnotherHttpHandler.Test;
-
-var builder = WebApplication.CreateBuilder(args);
-
-builder.Services.AddGrpc();
-
-var app = TestServerForHttp1AndHttp2.BuildApplication(builder);
-
-app.Run();
diff --git a/test/YetAnotherHttpHandler.StandaloneTestServer/Properties/launchSettings.json b/test/YetAnotherHttpHandler.StandaloneTestServer/Properties/launchSettings.json
deleted file mode 100644
index 0b480f8..0000000
--- a/test/YetAnotherHttpHandler.StandaloneTestServer/Properties/launchSettings.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "$schema": "http://json.schemastore.org/launchsettings.json",
- "profiles": {
- "http": {
- "commandName": "Project",
- "dotnetRunMessages": true,
- "launchBrowser": true,
- "applicationUrl": "http://localhost:5115",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- }
- }
-}
diff --git a/test/YetAnotherHttpHandler.StandaloneTestServer/YetAnotherHttpHandler.StandaloneTestServer.csproj b/test/YetAnotherHttpHandler.StandaloneTestServer/YetAnotherHttpHandler.StandaloneTestServer.csproj
deleted file mode 100644
index 9f35951..0000000
--- a/test/YetAnotherHttpHandler.StandaloneTestServer/YetAnotherHttpHandler.StandaloneTestServer.csproj
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- net8.0
- enable
- enable
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/YetAnotherHttpHandler.StandaloneTestServer/appsettings.Development.json b/test/YetAnotherHttpHandler.StandaloneTestServer/appsettings.Development.json
deleted file mode 100644
index 0c208ae..0000000
--- a/test/YetAnotherHttpHandler.StandaloneTestServer/appsettings.Development.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
- }
- }
-}
diff --git a/test/YetAnotherHttpHandler.StandaloneTestServer/appsettings.json b/test/YetAnotherHttpHandler.StandaloneTestServer/appsettings.json
deleted file mode 100644
index 0b2039c..0000000
--- a/test/YetAnotherHttpHandler.StandaloneTestServer/appsettings.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
- }
- },
- "Kestrel": {
- "Endpoints": {
- "Http1ClearText": {
- "Url": "http://localhost:5115",
- "Protocols": "Http1"
- },
- "Http2ClearText": {
- "Url": "http://localhost:5116",
- "Protocols": "Http2"
- }
- }
- },
- "AllowedHosts": "*"
-}
diff --git a/test/YetAnotherHttpHandler.Test/BackPressureTest.cs b/test/YetAnotherHttpHandler.Test/BackPressureTest.cs
index 53c8fd2..03120d2 100644
--- a/test/YetAnotherHttpHandler.Test/BackPressureTest.cs
+++ b/test/YetAnotherHttpHandler.Test/BackPressureTest.cs
@@ -15,7 +15,7 @@ public async Task FlushTest(int size)
{
using var httpHandler = new YetAnotherHttpHandler();
using var client = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
var numRequests = Environment.ProcessorCount + 1; // more than the number of tokio worker threads
@@ -36,4 +36,4 @@ public async Task FlushTest(int size)
foreach (var stream in pendingStreams) await stream.DisposeAsync();
}
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/ClientCertificateTest.cs b/test/YetAnotherHttpHandler.Test/ClientCertificateTest.cs
index 0d45267..7ff8175 100644
--- a/test/YetAnotherHttpHandler.Test/ClientCertificateTest.cs
+++ b/test/YetAnotherHttpHandler.Test/ClientCertificateTest.cs
@@ -1,8 +1,6 @@
-using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.X509Certificates;
using Cysharp.Net.Http;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Server.Kestrel.Https;
+using HttpClientTestServer;
namespace _YetAnotherHttpHandler.Test;
@@ -12,34 +10,14 @@ public ClientCertificateTest(ITestOutputHelper testOutputHelper) : base(testOutp
{
}
- protected Task LaunchServerAsync(Action? configure = null)
- where T : ITestServerBuilder
- {
- return LaunchServerAsync(TestWebAppServerListenMode.SecureHttp1AndHttp2, builder =>
- {
- // Use self-signed certificate for testing purpose.
- builder.WebHost.ConfigureKestrel(options =>
- {
- options.ConfigureHttpsDefaults(options =>
- {
- options.ServerCertificate = new X509Certificate2("Certificates/localhost.pfx");
- options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
- options.ClientCertificateValidation = (certificate2, chain, policyError) =>
- {
- return certificate2.Subject == "CN=client.example.com";
- };
- });
- });
-
- configure?.Invoke(builder);
- });
- }
+ protected Task LaunchServerAsync()
+ => LaunchServerAsync(new TestServerOptions(ListenHttpProtocols.Http1AndHttp2, isSecure: true) { EnableClientCertificateValidation = true });
[Fact]
public async Task NotSet()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler()
{
//ClientAuthCertificates = File.ReadAllText("./Certificates/client.crt"),
@@ -61,7 +39,7 @@ public async Task NotSet()
public async Task UseClientCertificate()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler()
{
ClientAuthCertificates = File.ReadAllText("./Certificates/client.crt"),
@@ -78,12 +56,12 @@ public async Task UseClientCertificate()
// Assert
Assert.Equal("__OK__", result);
}
-
+
[Fact]
public async Task Invalid()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler()
{
ClientAuthCertificates = File.ReadAllText("./Certificates/client_unknown.crt"), // CN=unknown.example.com
@@ -104,7 +82,7 @@ public async Task Invalid()
public async Task Reference_SocketHttpHandler_NotSet()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new SocketsHttpHandler();
httpHandler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true;
var httpClient = new HttpClient(httpHandler);
@@ -121,7 +99,7 @@ public async Task Reference_SocketHttpHandler_NotSet()
public async Task Reference_SocketHttpHandler_UseClientCertificate()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new SocketsHttpHandler();
httpHandler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true;
httpHandler.SslOptions.ClientCertificates = new X509CertificateCollection()
@@ -143,7 +121,7 @@ public async Task Reference_SocketHttpHandler_UseClientCertificate()
public async Task Reference_SocketHttpHandler_Invalid()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new SocketsHttpHandler();
httpHandler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true;
httpHandler.SslOptions.ClientCertificates = new X509CertificateCollection()
@@ -159,4 +137,4 @@ public async Task Reference_SocketHttpHandler_Invalid()
// Assert
Assert.IsType(ex);
}
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/Helpers/TestServerHelper.cs b/test/YetAnotherHttpHandler.Test/Helpers/TestServerHelper.cs
deleted file mode 100644
index 5360d7c..0000000
--- a/test/YetAnotherHttpHandler.Test/Helpers/TestServerHelper.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System.Net;
-using System.Net.Sockets;
-
-namespace _YetAnotherHttpHandler.Test.Helpers;
-
-public class TestServerHelper
-{
- private static readonly HashSet _usedPortInSession = new HashSet();
-
- public static int GetUnusedEphemeralPort()
- {
- lock (_usedPortInSession)
- {
- var retryCount = 5;
- do
- {
- var port = GetUnusedEphemeralPortCore();
- if (!_usedPortInSession.Contains(port))
- {
- _usedPortInSession.Add(port);
- return port;
- }
- } while (retryCount-- > 0);
-
- throw new Exception("Cannot allocate unused port in this test session.");
- }
-
- static int GetUnusedEphemeralPortCore()
- {
- using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
- return ((IPEndPoint)socket.LocalEndPoint!).Port;
- }
- }
-}
\ No newline at end of file
diff --git a/test/YetAnotherHttpHandler.Test/Helpers/TestWebAppServer.cs b/test/YetAnotherHttpHandler.Test/Helpers/TestWebAppServer.cs
deleted file mode 100644
index f39238b..0000000
--- a/test/YetAnotherHttpHandler.Test/Helpers/TestWebAppServer.cs
+++ /dev/null
@@ -1,135 +0,0 @@
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Connections;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Server.Kestrel.Core;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-using TestWebApp;
-
-namespace _YetAnotherHttpHandler.Test.Helpers;
-
-public class TestWebAppServer : IAsyncDisposable
-{
- private readonly Task _appTask;
- private readonly IHostApplicationLifetime _appLifetime;
- private readonly TaskCompletionSource _waitForAppStarted;
- private readonly ConcurrentDictionary _activeConnectionsById = new();
- private int _activeConnections;
-
- public int Port { get; }
- public bool IsSecure { get; }
-
- public string BaseUri => $"{(IsSecure ? "https" : "http")}://localhost:{Port}";
-
- public int ActiveConnections => _activeConnections;
- public IReadOnlyList ActiveConnectionIds => _activeConnectionsById.Keys.ToArray();
-
- private TestWebAppServer(int port, TestWebAppServerListenMode listenMode, ITestOutputHelper? testOutputHelper, Func webAppBuilder, Action? configure)
- {
- Port = port;
- IsSecure = listenMode is TestWebAppServerListenMode.SecureHttp1Only or
- TestWebAppServerListenMode.SecureHttp2Only or
- TestWebAppServerListenMode.SecureHttp1AndHttp2;
-
- var builder = WebApplication.CreateBuilder(Array.Empty());
-
- configure?.Invoke(builder);
-
- builder.Services.AddGrpc();
-
- builder.WebHost.ConfigureKestrel(options =>
- {
- options.ListenLocalhost(port, listenOptions =>
- {
- listenOptions.Protocols = listenMode switch
- {
- TestWebAppServerListenMode.InsecureHttp1Only => HttpProtocols.Http1,
- TestWebAppServerListenMode.InsecureHttp2Only => HttpProtocols.Http2,
- TestWebAppServerListenMode.SecureHttp1Only => HttpProtocols.Http1,
- TestWebAppServerListenMode.SecureHttp2Only => HttpProtocols.Http2,
- TestWebAppServerListenMode.SecureHttp1AndHttp2 => HttpProtocols.Http1AndHttp2,
- _ => throw new NotSupportedException(),
- };
-
- if (IsSecure)
- {
- listenOptions.UseHttps();
- }
-
- listenOptions.Use(async (ctx, next) =>
- {
- try
- {
- Interlocked.Increment(ref _activeConnections);
- _activeConnectionsById.TryAdd(ctx.ConnectionId, true);
- await next();
- }
- finally
- {
- Interlocked.Decrement(ref _activeConnections);
- _activeConnectionsById.TryRemove(ctx.ConnectionId, out _);
- }
- });
- });
- });
- if (testOutputHelper is not null)
- {
- if (Debugger.IsAttached)
- {
- builder.Logging.SetMinimumLevel(LogLevel.Trace);
- }
- builder.Logging.AddProvider(new TestOutputLoggerProvider(testOutputHelper));
- }
-
- var app = webAppBuilder(builder);
-
- _waitForAppStarted = new TaskCompletionSource();
- _appLifetime = app.Services.GetRequiredService();
- _appLifetime.ApplicationStarted.Register(() => _waitForAppStarted.SetResult());
- _appTask = app.RunAsync();
- }
-
- public static async Task LaunchAsync(TestWebAppServerListenMode listenMode, ITestOutputHelper? testOutputHelper = null, CancellationToken shutdownToken = default, Action? configure = null)
- where T : ITestServerBuilder
- {
- var port = TestServerHelper.GetUnusedEphemeralPort();
- var server = new TestWebAppServer(port, listenMode, testOutputHelper, T.BuildApplication, configure);
- await server._waitForAppStarted.Task;
-
- shutdownToken.Register(() =>
- {
- server.Shutdown();
- });
-
- return server;
- }
-
- public void Shutdown()
- {
- _appLifetime.StopApplication();
- }
-
- public async ValueTask DisposeAsync()
- {
- _appLifetime.StopApplication();
- try
- {
- await _appTask.WaitAsync(TimeSpan.FromSeconds(1));
- }
- catch (TimeoutException)
- {
- }
- }
-}
-
-public enum TestWebAppServerListenMode
-{
- InsecureHttp1Only,
- InsecureHttp2Only,
- SecureHttp1Only,
- SecureHttp2Only,
- SecureHttp1AndHttp2,
-}
\ No newline at end of file
diff --git a/test/YetAnotherHttpHandler.Test/Http1Test.cs b/test/YetAnotherHttpHandler.Test/Http1Test.cs
index 86741a7..369ed9c 100644
--- a/test/YetAnotherHttpHandler.Test/Http1Test.cs
+++ b/test/YetAnotherHttpHandler.Test/Http1Test.cs
@@ -13,7 +13,7 @@ public async Task FailedToConnect()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
// Act
var ex = await Record.ExceptionAsync(async () => await httpClient.GetAsync($"http://localhost.exmample/"));
@@ -29,7 +29,7 @@ public async Task FailedToConnect_VersionMismatch()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler() { Http2Only = true };
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
// Act
var ex = await Record.ExceptionAsync(async () => (await httpClient.GetAsync($"{server.BaseUri}/")).EnsureSuccessStatusCode());
@@ -51,17 +51,7 @@ public async Task Request_Version_20_Http1OnlyServer_Secure()
RootCertificates = File.ReadAllText("./Certificates/localhost.crt")
};
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.SecureHttp1Only, builder =>
- {
- // Use self-signed certificate for testing purpose.
- builder.WebHost.ConfigureKestrel(options =>
- {
- options.ConfigureHttpsDefaults(options =>
- {
- options.ServerCertificate = new X509Certificate2("Certificates/localhost.pfx");
- });
- });
- });
+ await using var server = await LaunchServerAsync(TestServerListenMode.SecureHttp1Only);
var request = new HttpRequestMessage(HttpMethod.Get, $"{server.BaseUri}/")
{
Version = HttpVersion.Version20,
@@ -84,7 +74,7 @@ public async Task Request_Version_Downgrade()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
var request = new HttpRequestMessage(HttpMethod.Get, $"{server.BaseUri}/")
{
Version = HttpVersion.Version20,
@@ -107,7 +97,7 @@ public async Task Get_Ok()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/");
@@ -125,7 +115,7 @@ public async Task Get_NotOk()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/not-found");
@@ -143,7 +133,7 @@ public async Task Get_ResponseHeaders()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/response-headers");
@@ -161,7 +151,7 @@ public async Task Get_NonAsciiPath()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/ハロー");
@@ -178,7 +168,7 @@ public async Task Post_Cancel()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
var pipe = new Pipe();
var content = new StreamContent(pipe.Reader.AsStream());
var cts = new CancellationTokenSource();
@@ -201,7 +191,7 @@ public async Task Post_Timeout()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler();
var httpClient = new HttpClient(httpHandler) { Timeout = TimeSpan.FromSeconds(2) };
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp1Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp1Only);
var pipe = new Pipe();
var content = new StreamContent(pipe.Reader.AsStream());
var cts = new CancellationTokenSource();
@@ -227,17 +217,7 @@ public async Task Secure_Get_Ok()
RootCertificates = File.ReadAllText("./Certificates/localhost.crt")
};
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.SecureHttp1Only, builder =>
- {
- // Use self-signed certificate for testing purpose.
- builder.WebHost.ConfigureKestrel(options =>
- {
- options.ConfigureHttpsDefaults(options =>
- {
- options.ServerCertificate = new X509Certificate2("Certificates/localhost.pfx");
- });
- });
- });
+ await using var server = await LaunchServerAsync(TestServerListenMode.SecureHttp1Only);
// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/");
@@ -248,4 +228,4 @@ public async Task Secure_Get_Ok()
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("__OK__", responseBody);
}
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/Http2ClearTextTest.cs b/test/YetAnotherHttpHandler.Test/Http2ClearTextTest.cs
index 1c8ffbb..1b09f43 100644
--- a/test/YetAnotherHttpHandler.Test/Http2ClearTextTest.cs
+++ b/test/YetAnotherHttpHandler.Test/Http2ClearTextTest.cs
@@ -1,6 +1,6 @@
-using System.Net;
+using System.Net;
using Cysharp.Net.Http;
-using Microsoft.AspNetCore.Builder;
+using HttpClientTestServer;
namespace _YetAnotherHttpHandler.Test;
@@ -10,11 +10,9 @@ protected override YetAnotherHttpHandler CreateHandler()
{
return new YetAnotherHttpHandler() { Http2Only = true };
}
-
- protected override Task LaunchServerAsyncCore(Action? configure = null)
- {
- return LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp2Only, configure);
- }
+
+ protected override Task LaunchServerAsync()
+ => LaunchServerAsync(new TestServerOptions(ListenHttpProtocols.Http2, isSecure: false));
[Fact]
public async Task FailedToConnect_VersionMismatch()
@@ -22,7 +20,7 @@ public async Task FailedToConnect_VersionMismatch()
// Arrange
using var httpHandler = new Cysharp.Net.Http.YetAnotherHttpHandler() { Http2Only = false };
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var ex = await Record.ExceptionAsync(async () => (await httpClient.GetAsync($"{server.BaseUri}/")).EnsureSuccessStatusCode());
@@ -31,4 +29,4 @@ public async Task FailedToConnect_VersionMismatch()
Assert.IsType(ex);
Assert.Equal(HttpStatusCode.BadRequest, ((HttpRequestException)ex).StatusCode);
}
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/Http2Test.cs b/test/YetAnotherHttpHandler.Test/Http2Test.cs
index b0781ab..6cd314d 100644
--- a/test/YetAnotherHttpHandler.Test/Http2Test.cs
+++ b/test/YetAnotherHttpHandler.Test/Http2Test.cs
@@ -1,7 +1,6 @@
-using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.X509Certificates;
using Cysharp.Net.Http;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
+using HttpClientTestServer;
namespace _YetAnotherHttpHandler.Test;
@@ -17,29 +16,14 @@ protected override YetAnotherHttpHandler CreateHandler()
};
}
- protected override Task LaunchServerAsyncCore(Action? configure = null)
- {
- return LaunchServerAsync(TestWebAppServerListenMode.SecureHttp2Only, builder =>
- {
- // Use self-signed certificate for testing purpose.
- builder.WebHost.ConfigureKestrel(options =>
- {
- //options.Limits.Http2.MaxFrameSize = 1024 * 1024;
- options.ConfigureHttpsDefaults(options =>
- {
- options.ServerCertificate = new X509Certificate2("Certificates/localhost.pfx");
- });
- });
-
- configure?.Invoke(builder);
- });
- }
+ protected override Task LaunchServerAsync()
+ => LaunchServerAsync(new TestServerOptions(ListenHttpProtocols.Http2, isSecure: true));
[Fact]
public async Task SelfSignedCertificate_NotTrusted()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler() { SkipCertificateVerification = false }; // We need to verify server certificate.
var httpClient = new HttpClient(httpHandler);
@@ -55,7 +39,7 @@ public async Task SelfSignedCertificate_NotTrusted()
public async Task SelfSignedCertificate_NotTrusted_SkipValidation()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler() { SkipCertificateVerification = true };
var httpClient = new HttpClient(httpHandler);
@@ -72,7 +56,7 @@ public async Task SelfSignedCertificate_NotTrusted_SkipValidation()
public async Task SelfSignedCertificate_Trusted_CustomRootCA()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler()
{
// We need to verify server certificate.
@@ -94,7 +78,7 @@ public async Task SelfSignedCertificate_Trusted_CustomRootCA()
public async Task CustomCertificateVerificationHandler_Success()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler()
{
OnVerifyServerCertificate = (name, certificate, now) =>
@@ -118,7 +102,7 @@ public async Task CustomCertificateVerificationHandler_Success()
public async Task CustomCertificateVerificationHandler_Failure()
{
// Arrange
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler()
{
OnVerifyServerCertificate = (name, certificate, now) =>
@@ -142,7 +126,7 @@ public async Task CustomCertificateVerificationHandler_Certificate()
{
// Arrange
byte[] receivedCertificate = Array.Empty();
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var httpHandler = new YetAnotherHttpHandler()
{
OnVerifyServerCertificate = (name, certificate, now) =>
@@ -165,4 +149,4 @@ public async Task CustomCertificateVerificationHandler_Certificate()
Assert.Equal("143a97beaaf96af9cdbc8769f523251b7c60625b", cert.Thumbprint, StringComparer.OrdinalIgnoreCase);
Assert.Equal("3082020a0282020100caec8d9f7e92bfceeef2aed4981ee786e31eef5c3a81e52cb5c60a84ee596a161f77d23d9866532a952f4e1826eb99eb20f4fccc4ef246aae06a03fe32db91b70072b7dc3b94ef18fe525d6b88876935dd7bd62ad25646aefd02799ecd2590867cf1bd1891c6f018782238e133019c35e6b9d2f7e4cbbda7b999c274b28b6ebe79d37edb210ed1d9b3dfc6a353a342dc8a3e40a48ebf625a49675e2f8b4c870d20b24c033d3d4960bfa12c61d437bdfd426dd8365659cf880c982367fb4d1677601aeb514f3fa9c052b0fa1335880268195ddf9ff7262ccb649956ba43d69db7b74ee53d17046ffd587e5270f6727bfba74f895b67286bff58ae4fd6ee8485c46a2e8e0fdf2a6ecef63efa24a0ffd3853bc86922cd01b8b9a928dc14dc20380746c0eac88a7d311daffe76dbf17a25d9c1cbf67137fa8beb827f6ea4816f81993e9c0b91800981e08681b4c4b98a1d1026794b07916a0e3f8f9091beb3c8aa3a9860e15dcfd3bcc0bce4e4d49f7a5432ce967407a63c0c197a1869ebd61d153e5669b6ae4b694f2255b79c6d96a8e837f1419c261b429028b12e5f72237b82172ccc298a54a0b4ae209aeccc0f528a1539afd3a83cefe6b18fa76bc55d374a0e8bdaece953a366287c377682b3b03393bb4d0a7b30752cd60b671d211874c78a5a2e9f49bb71e09aeed776e55d5ecc3141da402836629248aa87e75d0e7ef4530203010001", cert.GetPublicKeyString(), StringComparer.OrdinalIgnoreCase);
}
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/Http2TestBase.cs b/test/YetAnotherHttpHandler.Test/Http2TestBase.cs
index fde6c7d..0feebd5 100644
--- a/test/YetAnotherHttpHandler.Test/Http2TestBase.cs
+++ b/test/YetAnotherHttpHandler.Test/Http2TestBase.cs
@@ -1,5 +1,4 @@
-using Microsoft.AspNetCore.Builder;
-using System.IO.Pipelines;
+using System.IO.Pipelines;
using System.Net;
using System.Net.Http.Headers;
using Cysharp.Net.Http;
@@ -12,10 +11,8 @@ namespace _YetAnotherHttpHandler.Test;
public abstract class Http2TestBase(ITestOutputHelper testOutputHelper) : UseTestServerTestBase(testOutputHelper)
{
protected abstract YetAnotherHttpHandler CreateHandler();
- protected abstract Task LaunchServerAsyncCore(Action? configure = null) where T : ITestServerBuilder;
- protected Task LaunchServerAsync(Action? configure = null) where T : ITestServerBuilder
- => LaunchServerAsyncCore(configure);
+ protected abstract Task LaunchServerAsync();
[Fact]
public async Task Get_Ok()
@@ -23,7 +20,7 @@ public async Task Get_Ok()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var request = new HttpRequestMessage(HttpMethod.Get, $"{server.BaseUri}/")
@@ -45,7 +42,7 @@ public async Task Get_NotOk()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var request = new HttpRequestMessage(HttpMethod.Get, $"{server.BaseUri}/not-found")
@@ -67,7 +64,7 @@ public async Task Post_Body()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var content = new ByteArrayContent(new byte[] { 1, 2, 3, 45, 67 });
@@ -93,7 +90,7 @@ public async Task Post_NotDuplex_Receive_ResponseHeaders_Before_ResponseBody()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var content = new ByteArrayContent(new byte[] { 0 });
@@ -113,7 +110,7 @@ public async Task Post_NotDuplex_Receive_ResponseHeaders_Before_ResponseBody()
Assert.Equal("foo", response.Headers.TryGetValues("x-header-1", out var values) ? string.Join(',', values) : null);
Assert.False(responseBodyTask.IsCompleted);
}
-
+
// NOTE: SocketHttpHandler waits for the completion of sending the request body before the response headers.
// https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L1980-L1988
// https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs#L343-L349
@@ -147,7 +144,7 @@ public async Task Post_NotDuplex_Body_StreamingBody()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var pipe = new Pipe();
@@ -188,7 +185,7 @@ public async Task Post_Duplex_Body_StreamingBody()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var pipe = new Pipe();
@@ -230,7 +227,7 @@ public async Task Post_ResponseTrailers()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var content = new ByteArrayContent(new byte[] { 1, 2, 3, 45, 67 });
@@ -256,7 +253,7 @@ public async Task AbortOnServer_Post_SendingBody()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var content = new ByteArrayContent(Enumerable.Range(0, 1024 * 1024).Select(x => (byte)(x % 255)).ToArray());
@@ -279,7 +276,7 @@ public async Task Cancel_Post_SendingBody()
using var httpHandler = CreateHandler();
//using var httpHandler = new SocketsHttpHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var pipe = new Pipe();
@@ -309,7 +306,7 @@ public async Task Cancel_Post_SendingBody_Duplex()
// Arrange
/*using*/ var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var pipe = new Pipe();
@@ -320,7 +317,7 @@ public async Task Cancel_Post_SendingBody_Duplex()
Version = HttpVersion.Version20,
Content = content,
};
-
+
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).WaitAsync(TimeoutToken);
var connectionId = response.Headers.TryGetValues("x-connection-id", out var values) ? string.Join(',', values) : string.Empty;
var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(500));
@@ -342,7 +339,14 @@ public async Task Cancel_Post_SendingBody_Duplex()
// Assert
var operationCanceledException = Assert.IsAssignableFrom(ex);
Assert.Equal(cts.Token, operationCanceledException.CancellationToken);
- Assert.DoesNotContain(connectionId, server.ActiveConnectionIds);
+
+ using var handler2 = CreateHandler();
+ using var httpClient2 = new HttpClient(handler2);
+ httpClient2.DefaultRequestVersion = HttpVersion.Version20;
+ httpClient2.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher;
+ var activeConnectionIdsCsv = await httpClient2.GetStringAsync($"{server.BaseUri}/connection-state/active-connections");
+ var activeConnectionIds = activeConnectionIdsCsv.Split(',');
+ Assert.Single(activeConnectionIds);
}
#endif
@@ -352,7 +356,7 @@ public async Task DisposeHttpResponseMessage_Post_SendingBody_Duplex()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var pipe = new Pipe();
@@ -382,16 +386,16 @@ public async Task Cancel_Get_BeforeReceivingResponseHeaders()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
var id = Guid.NewGuid().ToString();
// Act
var request = new HttpRequestMessage(HttpMethod.Get, $"{server.BaseUri}/slow-response-headers")
{
Version = HttpVersion.Version20,
- Headers = { { TestServerForHttp1AndHttp2.SessionStateHeaderKey, id } }
+ Headers = { { "x-test-session-id" /*SessionStateHeaderKey*/, id } }
};
-
+
// The server responds after one second. But the client cancels the request before receiving response headers.
var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(300));
var ex = await Record.ExceptionAsync(async () => await httpClient.SendAsync(request, cts.Token).WaitAsync(TimeoutToken));
@@ -413,7 +417,7 @@ public async Task Cancel_Post_BeforeRequest()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var pipe = new Pipe();
@@ -441,7 +445,7 @@ public async Task Grpc_Unary()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
var client = new Greeter.GreeterClient(GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpHandler = httpHandler }));
// Act
@@ -457,7 +461,7 @@ public async Task Grpc_Duplex()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
var client = new Greeter.GreeterClient(GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpHandler = httpHandler }));
// Act
@@ -495,7 +499,7 @@ public async Task Grpc_Duplex_Concurrency()
const int RequestCount = 10;
const int Concurrency = 10;
using var httpHandler = CreateHandler();
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var channel = GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpHandler = httpHandler });
// Act
@@ -544,7 +548,7 @@ public async Task Grpc_Duplex_Concurrency()
[Fact]
public async Task Grpc_ShutdownAndDispose()
{
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
for (var i = 0; i < 10; i++)
{
@@ -593,7 +597,7 @@ public async Task Grpc_Error_Status_ErrorCode()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
var client = new Greeter.GreeterClient(GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpHandler = httpHandler }));
// Act
@@ -626,7 +630,7 @@ public async Task Grpc_Error_TimedOut_With_HttpClientTimeout()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler) { Timeout = TimeSpan.FromSeconds(3) };
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
var client = new Greeter.GreeterClient(GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpClient = httpClient }));
// Act
@@ -635,11 +639,7 @@ public async Task Grpc_Error_TimedOut_With_HttpClientTimeout()
// Assert
Assert.IsType(ex);
Assert.Equal(StatusCode.Cancelled, ((RpcException)ex).StatusCode);
-#if UNITY_2021_1_OR_NEWER
Assert.IsType(((RpcException)ex).Status.DebugException);
-#else
- Assert.IsType(((RpcException)ex).Status.DebugException);
-#endif
}
[Fact]
@@ -648,7 +648,7 @@ public async Task Grpc_Error_TimedOut_With_Deadline()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
var client = new Greeter.GreeterClient(GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpClient = httpClient }));
// Act
@@ -665,7 +665,7 @@ public async Task Grpc_Error_TimedOut_With_CancellationToken()
// Arrange
using var httpHandler = CreateHandler();
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
var client = new Greeter.GreeterClient(GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpClient = httpClient }));
// Act
@@ -687,7 +687,7 @@ public async Task Enable_Http2KeepAlive()
httpHandler.Http2KeepAliveWhileIdle = true;
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
// Act
var request = new HttpRequestMessage(HttpMethod.Get, $"{server.BaseUri}/")
@@ -723,4 +723,4 @@ protected override bool TryComputeLength(out long length)
return false;
}
}
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/StressTest.cs b/test/YetAnotherHttpHandler.Test/StressTest.cs
index 6cf3958..3806d71 100644
--- a/test/YetAnotherHttpHandler.Test/StressTest.cs
+++ b/test/YetAnotherHttpHandler.Test/StressTest.cs
@@ -1,4 +1,4 @@
-#define ENABLE_STRESS_TEST
+#define ENABLE_STRESS_TEST
#if ENABLE_STRESS_TEST
using System.Security.Cryptography;
@@ -7,9 +7,13 @@
using Cysharp.Net.Http;
using Grpc.Core;
using Grpc.Net.Client;
+using HttpClientTestServer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
-using TestWebApp;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+using EchoRequest = TestWebApp.EchoRequest;
+using Greeter = TestWebApp.Greeter;
+using HelloRequest = TestWebApp.HelloRequest;
namespace _YetAnotherHttpHandler.Test;
@@ -31,27 +35,12 @@ protected HttpMessageHandler CreateHandler()
};
}
- protected Task LaunchServerAsyncCore(Action? configure = null)
- where T : ITestServerBuilder
- {
- return LaunchServerAsync(TestWebAppServerListenMode.SecureHttp2Only, builder =>
+ protected Task LaunchServerAsync()
+ => LaunchServerAsync(new TestServerOptions(ListenHttpProtocols.Http2, true).With(x =>
{
- // Use self-signed certificate for testing purpose.
- builder.WebHost.ConfigureKestrel(options =>
- {
- //options.Limits.Http2.MaxFrameSize = 1024 * 1024;
- options.ConfigureHttpsDefaults(options =>
- {
- options.ServerCertificate = new X509Certificate2("Certificates/localhost.pfx");
- });
- });
-
- configure?.Invoke(builder);
- });
- }
-
- protected Task LaunchServerAsync(Action? configure = null) where T : ITestServerBuilder
- => LaunchServerAsyncCore(configure);
+ x.IsSecure = true;
+ x.HttpProtocols = ListenHttpProtocols.Http2;
+ }));
[Fact]
public async Task Grpc_Duplex_Concurrency()
@@ -62,7 +51,7 @@ public async Task Grpc_Duplex_Concurrency()
var requestStringSuffix = CreateRandomString(1024 * 32 /* UTF-8 = 32KB */);
using var httpHandler = CreateHandler();
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var channel = GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpHandler = httpHandler });
// Act
@@ -120,7 +109,7 @@ public async Task Grpc_Duplex_Concurrency_CompleteFromServerWhileSendingData()
var data = CreateRandomString(1024 * 64 /* UTF-8 = 64KB */);
using var httpHandler = CreateHandler();
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var channel = GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpHandler = httpHandler });
// Act
@@ -181,7 +170,7 @@ public async Task Grpc_Duplex_Concurrency_AbortFromServerWhileSendingData()
var data = CreateRandomString(1024 * 64 /* UTF-8 = 64KB */);
using var httpHandler = CreateHandler();
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var channel = GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpHandler = httpHandler });
// Act
@@ -249,7 +238,7 @@ public async Task Grpc_Duplex_Large_Data()
var hash = SHA1.HashData(Encoding.UTF8.GetBytes(data));
using var httpHandler = CreateHandler();
- await using var server = await LaunchServerAsync();
+ await using var server = await LaunchServerAsync();
using var channel = GrpcChannel.ForAddress(server.BaseUri, new GrpcChannelOptions() { HttpHandler = httpHandler });
// Act
@@ -300,4 +289,4 @@ private static string CreateRandomString(int length) =>
}
});
}
-#endif
\ No newline at end of file
+#endif
diff --git a/test/YetAnotherHttpHandler.Test/TestServerForHttp1AndHttp2.cs b/test/YetAnotherHttpHandler.Test/TestServerForHttp1AndHttp2.cs
deleted file mode 100644
index 5845e64..0000000
--- a/test/YetAnotherHttpHandler.Test/TestServerForHttp1AndHttp2.cs
+++ /dev/null
@@ -1,278 +0,0 @@
-using System.Buffers;
-using System.Collections.Concurrent;
-using System.IO.Pipelines;
-using System.Net;
-using Grpc.Core;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Features;
-using Microsoft.Extensions.DependencyInjection;
-using TestWebApp;
-
-namespace _YetAnotherHttpHandler.Test;
-
-class TestServerForHttp1AndHttp2 : ITestServerBuilder
-{
- private const string SessionStateKey = "SessionState";
- public const string SessionStateHeaderKey = "x-yahatest-session-id";
-
- record SessionStateFeature(ConcurrentDictionary Items);
-
- public static WebApplication BuildApplication(WebApplicationBuilder builder)
- {
- builder.Services.AddKeyedSingleton(SessionStateKey, new ConcurrentDictionary>());
-
- var app = builder.Build();
-
- // ConnectionId header
- app.Use((ctx, next) =>
- {
- ctx.Response.Headers["x-connection-id"] = ctx.Connection.Id;
- return next(ctx);
- });
-
- // SessionState
- app.Use((ctx, next) =>
- {
- if (ctx.Request.Headers.TryGetValue(SessionStateHeaderKey, out var headerValues))
- {
- var sessionStates = ctx.RequestServices.GetRequiredKeyedService>>(SessionStateKey);
- var sessionStateItems = sessionStates.GetOrAdd(headerValues.ToString(), _ => new ConcurrentDictionary());
- ctx.Features.Set(new SessionStateFeature(sessionStateItems));
- }
- else
- {
- ctx.Features.Set(new SessionStateFeature(new ConcurrentDictionary()));
- }
-
- return next(ctx);
- });
- app.MapGet("/session-state", (HttpContext ctx, string id, string key) =>
- {
- var sessionStates = ctx.RequestServices.GetRequiredKeyedService>>(SessionStateKey);
- if (sessionStates.TryGetValue(id, out var items))
- {
- if (items.TryGetValue(key, out var value))
- {
- return Results.Content(value.ToString());
- }
- return Results.Content(string.Empty);
- }
-
- return Results.NotFound();
- });
-
- // HTTP/1 and HTTP/2
- app.MapGet("/", () => Results.Content("__OK__"));
- app.MapGet("/not-found", () => Results.Content("__Not_Found__", statusCode: 404));
- app.MapGet("/response-headers", (HttpContext httpContext) =>
- {
- httpContext.Response.Headers["x-test"] = "foo";
- return Results.Content("__OK__");
- });
- app.MapGet("/slow-response-headers", async (HttpContext httpContext) =>
- {
- using var _ = httpContext.RequestAborted.Register(() =>
- {
- httpContext.Features.GetRequiredFeature().Items["IsCanceled"] = true;
- });
-
- await Task.Delay(1000);
- httpContext.Response.Headers["x-test"] = "foo";
-
- return Results.Content("__OK__");
- });
- app.MapGet("/ハロー", () => Results.Content("Konnichiwa"));
- app.MapPost("/slow-upload", async (HttpContext ctx, PipeReader reader) =>
- {
- while (true)
- {
- await Task.Delay(1000);
- var readResult = await reader.ReadAsync();
- reader.AdvanceTo(readResult.Buffer.End);
- if (readResult.IsCompleted || readResult.IsCanceled) break;
- }
- return Results.Content("OK");
- });
- app.MapPost("/post-echo", async (HttpContext httpContext, Stream bodyStream) =>
- {
- httpContext.Response.Headers["x-request-content-type"] = httpContext.Request.ContentType;
-
- return Results.Bytes(await bodyStream.ToArrayAsync(), "application/octet-stream");
- });
- app.MapPost("/post-streaming", async (HttpContext httpContext, PipeReader reader) =>
- {
- // Send status code and response headers.
- httpContext.Response.Headers["x-header-1"] = "foo";
- httpContext.Response.StatusCode = (int)HttpStatusCode.OK;
- await httpContext.Response.BodyWriter.FlushAsync();
-
- var readLen = 0L;
- while (true)
- {
- var readResult = await reader.ReadAsync();
- readLen += readResult.Buffer.Length;
- reader.AdvanceTo(readResult.Buffer.End);
- if (readResult.IsCompleted || readResult.IsCanceled) break;
- }
-
- await httpContext.Response.WriteAsync(readLen.ToString());
-
- return Results.Empty;
- });
- app.MapPost("/post-response-trailers", (HttpContext httpContext) =>
- {
- httpContext.Response.AppendTrailer("x-trailer-1", "foo");
- httpContext.Response.AppendTrailer("x-trailer-2", "bar");
-
- return Results.Ok("__OK__");
- });
- app.MapPost("/post-response-headers-immediately", async (HttpContext httpContext, PipeReader reader) =>
- {
- // Send status code and response headers.
- httpContext.Response.Headers["x-header-1"] = "foo";
- httpContext.Response.StatusCode = (int)HttpStatusCode.Accepted;
- await httpContext.Response.BodyWriter.FlushAsync();
-
- await Task.Delay(100000);
- await httpContext.Response.WriteAsync("__OK__");
- return Results.Empty;
- });
- app.MapPost("/post-abort-while-reading", async (HttpContext httpContext, PipeReader reader) =>
- {
- var readResult = await reader.ReadAsync();
- reader.AdvanceTo(readResult.Buffer.End);
- httpContext.Abort();
-
- return Results.Empty;
- });
- app.MapPost("/post-null", async (HttpContext httpContext, PipeReader reader) =>
- {
- while (!httpContext.RequestAborted.IsCancellationRequested)
- {
- var readResult = await reader.ReadAsync();
- reader.AdvanceTo(readResult.Buffer.End);
- if (readResult.IsCompleted || readResult.IsCanceled) break;
- }
- return Results.Empty;
- });
- app.MapPost("/post-null-duplex", async (HttpContext httpContext, PipeReader reader) =>
- {
- // Send status code and response headers.
- httpContext.Response.Headers["x-header-1"] = "foo";
- httpContext.Response.StatusCode = (int)HttpStatusCode.OK;
- await httpContext.Response.BodyWriter.FlushAsync();
-
- while (!httpContext.RequestAborted.IsCancellationRequested)
- {
- var readResult = await reader.ReadAsync();
- reader.AdvanceTo(readResult.Buffer.End);
- if (readResult.IsCompleted || readResult.IsCanceled) break;
- }
- return Results.Empty;
- });
- app.MapPost("/post-never-read", async (HttpContext httpContext) =>
- {
- // Send status code and response headers.
- httpContext.Response.Headers["x-header-1"] = "foo";
- httpContext.Response.StatusCode = (int)HttpStatusCode.OK;
- await httpContext.Response.BodyWriter.FlushAsync();
-
- while (!httpContext.RequestAborted.IsCancellationRequested)
- {
- await Task.Delay(100);
- }
- return Results.Empty;
- });
- app.MapGet("/random", (int size) =>
- {
- var buffer = new byte[size];
- Random.Shared.NextBytes(buffer);
- return Results.Bytes(buffer, "application/octet-stream");
- });
-
- // HTTP/2
- app.MapGet("/error-reset", (HttpContext httpContext) =>
- {
- // https://learn.microsoft.com/ja-jp/aspnet/core/fundamentals/servers/kestrel/http2?view=aspnetcore-7.0#reset-1
- var resetFeature = httpContext.Features.Get();
- resetFeature!.Reset(errorCode: 2); // INTERNAL_ERROR
- return Results.Empty;
- });
-
- // gRPC
- app.MapGrpcService();
-
- return app;
- }
-
- class GreeterService : Greeter.GreeterBase
- {
-#pragma warning disable CS1998
- public override async Task SayHello(HelloRequest request, ServerCallContext context)
- {
- return new HelloReply { Message = $"Hello {request.Name}" };
- }
-
- public override async Task SayHelloSlow(HelloRequest request, ServerCallContext context)
- {
- await Task.Delay(TimeSpan.FromSeconds(30));
- return new HelloReply { Message = $"Hello {request.Name}" };
- }
-
- public override async Task SayHelloNever(HelloRequest request, ServerCallContext context)
- {
- await Task.Delay(-1);
- throw new NotImplementedException();
- }
-
- public override async Task SayHelloDuplex(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context)
- {
- await foreach (var request in requestStream.ReadAllAsync(context.CancellationToken))
- {
- await responseStream.WriteAsync(new HelloReply { Message = $"Hello {request.Name}" });
- }
- }
-
- public override async Task SayHelloDuplexCompleteRandomly(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context)
- {
- await foreach (var request in requestStream.ReadAllAsync(context.CancellationToken))
- {
- await responseStream.WriteAsync(new HelloReply { Message = request.Name });
- if (Random.Shared.Next(0, 9) == 0)
- {
- return;
- }
- }
- }
-
- public override async Task SayHelloDuplexAbortRandomly(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context)
- {
- await foreach (var request in requestStream.ReadAllAsync(context.CancellationToken))
- {
- await responseStream.WriteAsync(new HelloReply { Message = request.Name });
- if (Random.Shared.Next(0, 9) == 0)
- {
- context.GetHttpContext().Abort();
- return;
- }
- }
- }
-
- public override async Task ResetByServer(ResetRequest request, ServerCallContext context)
- {
- context.GetHttpContext().Features.GetRequiredFeature().Reset(errorCode: request.ErrorCode);
- return new ResetReply { };
- }
-
- public override async Task EchoDuplex(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context)
- {
- await foreach (var request in requestStream.ReadAllAsync(context.CancellationToken))
- {
- await responseStream.WriteAsync(new EchoReply() { Message = request.Message });
- }
- }
-#pragma warning restore CS1998
- }
-
-}
\ No newline at end of file
diff --git a/test/YetAnotherHttpHandler.Test/UdsTest.cs b/test/YetAnotherHttpHandler.Test/UdsTest.cs
index 6c87957..941a95d 100644
--- a/test/YetAnotherHttpHandler.Test/UdsTest.cs
+++ b/test/YetAnotherHttpHandler.Test/UdsTest.cs
@@ -1,8 +1,5 @@
-using System.Security.Cryptography.X509Certificates;
-using Cysharp.Net.Http;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Server.Kestrel.Core;
+using Cysharp.Net.Http;
+using HttpClientTestServer;
namespace _YetAnotherHttpHandler.Test;
@@ -19,25 +16,12 @@ protected override YetAnotherHttpHandler CreateHandler()
};
}
- protected override Task LaunchServerAsyncCore(Action? configure = null)
- {
- return LaunchServerAsync(TestWebAppServerListenMode.SecureHttp2Only, builder =>
+ protected override Task LaunchServerAsync()
+ => LaunchServerAsync(new TestServerOptions(ListenHttpProtocols.Http2, isSecure: true)
{
- builder.WebHost.ConfigureKestrel(options =>
- {
- options.ListenUnixSocket(_udsPath, listenOptions =>
- {
- listenOptions.Protocols = HttpProtocols.Http2;
- });
-
- // hyperlocal uses the 'unix' scheme and passes the URI to hyper. As a result, the ':scheme' header in the request is set to 'unix'.
- // By default, Kestrel does not accept non-HTTP schemes. To allow non-HTTP schemes, we need to set 'AllowAlternateSchemes' to true.
- options.AllowAlternateSchemes = true;
- });
-
- configure?.Invoke(builder);
+ UnixDomainSocketPath = _udsPath,
});
- }
+
}
[OSSkipCondition(OperatingSystems.MacOSX | OperatingSystems.Linux)]
@@ -59,4 +43,4 @@ await Assert.ThrowsAsync(async () =>
await httpClient.GetAsync("http://localhost/");
});
}
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/UseTestServerBase.cs b/test/YetAnotherHttpHandler.Test/UseTestServerBase.cs
index 73e3eaa..6121bbb 100644
--- a/test/YetAnotherHttpHandler.Test/UseTestServerBase.cs
+++ b/test/YetAnotherHttpHandler.Test/UseTestServerBase.cs
@@ -1,3 +1,4 @@
+using HttpClientTestServer.Launcher;
using Microsoft.AspNetCore.Builder;
namespace _YetAnotherHttpHandler.Test;
@@ -18,14 +19,23 @@ protected UseTestServerTestBase(ITestOutputHelper testOutputHelper)
});
}
- protected async Task LaunchServerAsync(TestWebAppServerListenMode listenMode, Action? configure = null)
- where T : ITestServerBuilder
+ protected virtual TestServerOptions ConfigureServerOptions(TestServerOptions options)
+ => options;
+
+ protected Task LaunchServerAsync(TestServerListenMode listenMode)
+ => LaunchServerAsync(ConfigureServerOptions(TestServerOptions.CreateFromListenMode(listenMode)));
+
+ protected async Task LaunchServerAsync(TestServerOptions serverOptions)
{
- return await TestWebAppServer.LaunchAsync(listenMode, TestOutputHelper, TimeoutToken, configure);
+ return await InProcessTestServer.LaunchAsync(
+ ConfigureServerOptions(serverOptions),
+ new TestOutputLoggerProvider(TestOutputHelper),
+ TimeoutToken
+ );
}
public void Dispose()
{
_tokenRegistration.Dispose();
}
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/Usings.cs b/test/YetAnotherHttpHandler.Test/Usings.cs
index 28c3087..e185109 100644
--- a/test/YetAnotherHttpHandler.Test/Usings.cs
+++ b/test/YetAnotherHttpHandler.Test/Usings.cs
@@ -1,3 +1,4 @@
global using Xunit;
global using _YetAnotherHttpHandler.Test.Helpers;
+global using HttpClientTestServer.Launcher;
diff --git a/test/YetAnotherHttpHandler.Test/VersionNegotiationTest.cs b/test/YetAnotherHttpHandler.Test/VersionNegotiationTest.cs
index fcf6fb1..6cc2530 100644
--- a/test/YetAnotherHttpHandler.Test/VersionNegotiationTest.cs
+++ b/test/YetAnotherHttpHandler.Test/VersionNegotiationTest.cs
@@ -16,14 +16,14 @@ public async Task Negotiate(NegotiationCriteria criteria)
var listenMode =
(serverIsHttp11 && serverIsHttp20)
- ? (serverIsHttps ? TestWebAppServerListenMode.SecureHttp1AndHttp2 : throw new InvalidOperationException("To listen to HTTP/1 and HTTP/2 on a single port, TLS is required."))
+ ? (serverIsHttps ? TestServerListenMode.SecureHttp1AndHttp2 : throw new InvalidOperationException("To listen to HTTP/1 and HTTP/2 on a single port, TLS is required."))
: serverIsHttp11
- ? (serverIsHttps ? TestWebAppServerListenMode.SecureHttp1Only : TestWebAppServerListenMode.InsecureHttp1Only)
+ ? (serverIsHttps ? TestServerListenMode.SecureHttp1Only : TestServerListenMode.InsecureHttp1Only)
: serverIsHttp20
- ? (serverIsHttps ? TestWebAppServerListenMode.SecureHttp2Only : TestWebAppServerListenMode.InsecureHttp2Only)
+ ? (serverIsHttps ? TestServerListenMode.SecureHttp2Only : TestServerListenMode.InsecureHttp2Only)
: throw new InvalidOperationException();
- await using var server = await LaunchServerAsync(listenMode);
+ await using var server = await LaunchServerAsync(listenMode);
using var httpHandler = new YetAnotherHttpHandler()
{
Http2Only = criteria.ClientHttp2Only,
@@ -92,4 +92,4 @@ public enum ServerListenHttpVersion
}
public record NegotiationCriteria(Version RequestVersion, ServerListenHttpVersion ServerListenVersions, Version ResponseVersion, bool ClientHttp2Only, bool IsHttps, bool ExpectsException);
-}
\ No newline at end of file
+}
diff --git a/test/YetAnotherHttpHandler.Test/YetAnotherHttpHandler.Test.csproj b/test/YetAnotherHttpHandler.Test/YetAnotherHttpHandler.Test.csproj
index 872d59a..993f896 100644
--- a/test/YetAnotherHttpHandler.Test/YetAnotherHttpHandler.Test.csproj
+++ b/test/YetAnotherHttpHandler.Test/YetAnotherHttpHandler.Test.csproj
@@ -9,10 +9,11 @@
false
true
_$(MSBuildProjectName.Replace(" ", "_"))
+ $(NoWarn);xUnit1051
-
+
Always
@@ -35,10 +36,12 @@
-
+
+
+
diff --git a/test/YetAnotherHttpHandler.Test/YetAnotherHttpHandlerTest.cs b/test/YetAnotherHttpHandler.Test/YetAnotherHttpHandlerTest.cs
index 87b2fb0..2363801 100644
--- a/test/YetAnotherHttpHandler.Test/YetAnotherHttpHandlerTest.cs
+++ b/test/YetAnotherHttpHandler.Test/YetAnotherHttpHandlerTest.cs
@@ -44,7 +44,7 @@ async Task RunAsync()
// Arrange
var httpHandler = new YetAnotherHttpHandler() { Http2Only = true };
var httpClient = new HttpClient(httpHandler);
- await using var server = await LaunchServerAsync(TestWebAppServerListenMode.InsecureHttp2Only);
+ await using var server = await LaunchServerAsync(TestServerListenMode.InsecureHttp2Only);
// Act
var pipe = new Pipe();
@@ -162,4 +162,4 @@ public async Task SetWorkerThreads()
Assert.Equal(0, NativeRuntime.Instance._refCount);
}
-}
\ No newline at end of file
+}
diff --git a/test/certs/README.md b/test/certs/README.md
deleted file mode 100644
index d6b7802..0000000
--- a/test/certs/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# Certificates for tests
-
-- localhost.{crt,key,pfx}: Server certifiacte (localhost)
-- client.{crt,key,pfx}: Client cerfiticate (CN=client.example.com)
-- client_unknown.{crt,key,pfx}: Client cerfiticate (CN=unknown.example.com)
-
-## To generate client certificates
-
-```bash
-openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out client.key
-openssl req -key client.key -config client.conf -new -out client.csr
-openssl x509 -req -in client.csr -CA localhost.crt -CAkey localhost.key -days 3650 -CAcreateserial -out client.crt
-openssl pkcs12 -export -in client.crt -inkey client.key -out client.pfx
-```
\ No newline at end of file
diff --git a/test/certs/client.conf b/test/certs/client.conf
deleted file mode 100644
index 0bbad16..0000000
--- a/test/certs/client.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-[client-cert]
-keyUsage = critical, digitalSignature, keyEncipherment
-extendedKeyUsage = clientAuth
-subjectAltName = @alt_name
-
-[req]
-distinguished_name = dn
-prompt = no
-
-[dn]
-CN = client.example.com
-
-[clnt_alt_name]
-email =
diff --git a/test/certs/client.crt b/test/certs/client.crt
deleted file mode 100644
index 9a9a210..0000000
--- a/test/certs/client.crt
+++ /dev/null
@@ -1,18 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIC7DCB1QIUNkpGguldG9R3BHelyLc4Gh1E8wQwDQYJKoZIhvcNAQELBQAwFDES
-MBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMTAzMTA5NTc1N1oXDTMzMTAyODA5NTc1
-N1owHTEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYI
-KoZIzj0DAQcDQgAEcKYOEMIsJpYKDME82T2PboLnzcCtQYJUMgZJK3Uyn4Cp+Z8Z
-8LXIZIic4uF3iNh/jU7+HX0IQSXRPLCZHSws0jANBgkqhkiG9w0BAQsFAAOCAgEA
-svonO0AshuqwE6Y+MBQWYSwwUz+kC9Ot6GywrUz1hxMDAeEKBPDnGFOR/qd5fMmj
-6LfVALJwze57eVgmsnhcaqyJlTHN3FvKDP1WaGX5FYvlnFwpj7yADvATe7p3lW2/
-IFv2Stq6KSBkkuqrB1QKCFmUtssYQ1QJXlrBTYuCUpg/6dd81N8bsjE6XYRpJtiT
-b4MuSJLENofVI2citdGgcdFD1Axckh+qIPwz2y1C5HzVx80bLgPxmo1hC6A4KGhP
-LScnAtp6GgdpkNvYTEJHeY90zM7k2LcNDEASjrspwQVZhWvT50lH4z2ZlCn7A8ZF
-C4cSNIR7eOs5lDkCf+z5x3vbp+uuidGEN8PfacJKf5nYepYBFZHEz0VCBnJjMZ6R
-buzoemjfeN1W8EB0bdMSUhKytzhV1NabI2vqxr1Qy2syTem4Hwenk7ivodWMWjSW
-WMknnDOMHVv+0AwdhZpuBdkf4ONHYszkqQQIrWpgEOfaI6YjUCvizgqJwdOE8ezf
-V59eKkgSyXwloswu80wEaCzolAaK0K5BiPYznhBIHROkHzpbtEXvpVOEgxYaxxHj
-PveAWmQ1FxLwjg4MXMOjp+nLu3HqNGk08446Qyo144bV3yExVfFBJS7NtBnqowcH
-0xZD3k/ydOjk9Bse1RGR2y7KdJjTNkYzNFBaIukczFo=
------END CERTIFICATE-----
diff --git a/test/certs/client.csr b/test/certs/client.csr
deleted file mode 100644
index 4139cca..0000000
--- a/test/certs/client.csr
+++ /dev/null
@@ -1,7 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIHXMH8CAQAwHTEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUuY29tMFkwEwYHKoZI
-zj0CAQYIKoZIzj0DAQcDQgAEcKYOEMIsJpYKDME82T2PboLnzcCtQYJUMgZJK3Uy
-n4Cp+Z8Z8LXIZIic4uF3iNh/jU7+HX0IQSXRPLCZHSws0qAAMAoGCCqGSM49BAMC
-A0gAMEUCIQD6K6X3oaCCBmYAYrjSQTKYxn3U93ImWHg0Xe94//bt0gIgMpHuH7tn
-iYiBRTQQP8aJAWmlz8CZRNUJu6C9JyPLDfQ=
------END CERTIFICATE REQUEST-----
diff --git a/test/certs/client.key b/test/certs/client.key
deleted file mode 100644
index 6881643..0000000
--- a/test/certs/client.key
+++ /dev/null
@@ -1,5 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg1t2JNg3f49/Hb5kt
-FrcW5rcCa30cCwz8e/JojjsGOnGhRANCAARwpg4QwiwmlgoMwTzZPY9ugufNwK1B
-glQyBkkrdTKfgKn5nxnwtchkiJzi4XeI2H+NTv4dfQhBJdE8sJkdLCzS
------END PRIVATE KEY-----
diff --git a/test/certs/client.pfx b/test/certs/client.pfx
deleted file mode 100644
index 2bfdf53..0000000
Binary files a/test/certs/client.pfx and /dev/null differ
diff --git a/test/certs/client_unknown.conf b/test/certs/client_unknown.conf
deleted file mode 100644
index 7f82176..0000000
--- a/test/certs/client_unknown.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-[client-cert]
-keyUsage = critical, digitalSignature, keyEncipherment
-extendedKeyUsage = clientAuth
-subjectAltName = @alt_name
-
-[req]
-distinguished_name = dn
-prompt = no
-
-[dn]
-CN = unknown.example.com
-
-[clnt_alt_name]
-email =
diff --git a/test/certs/client_unknown.crt b/test/certs/client_unknown.crt
deleted file mode 100644
index d73b7d7..0000000
--- a/test/certs/client_unknown.crt
+++ /dev/null
@@ -1,18 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIC7TCB1gIUNkpGguldG9R3BHelyLc4Gh1E8wUwDQYJKoZIhvcNAQELBQAwFDES
-MBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMTEwMTA1MDYxMVoXDTMzMTAyOTA1MDYx
-MVowHjEcMBoGA1UEAwwTdW5rbm93bi5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABHH2A8kl1b47Hr9JEc7HMi1DR25BPFiJw89zUcBV4onrCOxv
-zLrPSPgp8zGAQPaF7loJrPvxiN379UOmKOifSswwDQYJKoZIhvcNAQELBQADggIB
-AEiqRY2sNGQT8EHgHt9JCasI1XnyCpoUBr88vAYeeTaK1mgP6bF+NtLyPAraYZnR
-ZPAFIX8iQ25Rxz+goCa/svcnsJRB8EQd7qmoADIk2V+C00jo0fU/Bnj3l1Q7twr6
-1PnanN+znOLPoWUx+P+ssEWhM2Z4hZplw/ovJGjZfp1zc6yeA3fL+J7d6CXmdv9R
-DfWCPYch7GUTuXevH51ZQWUeoeaYcpVbygLCrPTG5M8Q+Aq4Ogg1VURYe2ZyVUcx
-wsFVVcm97pI6gG6zGPvKBuvVyISzRpNcUIQkkrpz6+qziHQF1PnyGSLDsgFDJEig
-9N3ZKnLaZu4e/vN6psd7JMX/DbqtYPSgxCxvVKbaJ/wWK85mkV9RGeP4c0wtn+aY
-eP3nV6NJQ9WXXtTmzhl1epjcYQM48vKWfXgOxAdClmXV3sBfIXPKHB5EM7otHaQe
-JJYYQb43SoQe48Dh5Q0SEC2LX46/Ik91AsO/jWAjf3pvwiLrypQSkOimFYuzvqfG
-7lo9ncVtCyFGxMt4fUEtt/u1zDB6apIluvFT2/Ak9imtQ6Rb41l+6L3XcamIHSV2
-/HTq8lPleXXl35WgWR6emxWNWcxcnb4UnE787UdUtnuIbQDoGQuHwpBPruefTu8t
-3sqIbJVu6TWNXcUI5LdcH2IAwjPE7fOQ7iOkD889qxc3
------END CERTIFICATE-----
diff --git a/test/certs/client_unknown.csr b/test/certs/client_unknown.csr
deleted file mode 100644
index 241abbf..0000000
--- a/test/certs/client_unknown.csr
+++ /dev/null
@@ -1,7 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIHaMIGAAgEAMB4xHDAaBgNVBAMME3Vua25vd24uZXhhbXBsZS5jb20wWTATBgcq
-hkjOPQIBBggqhkjOPQMBBwNCAARx9gPJJdW+Ox6/SRHOxzItQ0duQTxYicPPc1HA
-VeKJ6wjsb8y6z0j4KfMxgED2he5aCaz78Yjd+/VDpijon0rMoAAwCgYIKoZIzj0E
-AwIDSQAwRgIhAPuR2XZzQ06I9ynH5iFaFxdPmGgDJdg8y93TzPyy2jDSAiEAo2AM
-Xj13uVKmAof6BdF/9QLoDlSuQPCkFrDvYPzi71Q=
------END CERTIFICATE REQUEST-----
diff --git a/test/certs/client_unknown.key b/test/certs/client_unknown.key
deleted file mode 100644
index feb83a8..0000000
--- a/test/certs/client_unknown.key
+++ /dev/null
@@ -1,5 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgnA83PApWtXl3VWg5
-xi3Qb02/92/YbPJikLO8NU1yhWyhRANCAARx9gPJJdW+Ox6/SRHOxzItQ0duQTxY
-icPPc1HAVeKJ6wjsb8y6z0j4KfMxgED2he5aCaz78Yjd+/VDpijon0rM
------END PRIVATE KEY-----
diff --git a/test/certs/client_unknown.pfx b/test/certs/client_unknown.pfx
deleted file mode 100644
index 5a328b5..0000000
Binary files a/test/certs/client_unknown.pfx and /dev/null differ
diff --git a/test/certs/localhost.crt b/test/certs/localhost.crt
deleted file mode 100644
index fb72a6d..0000000
--- a/test/certs/localhost.crt
+++ /dev/null
@@ -1,29 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIE9TCCAt2gAwIBAgIUUQ33LbUPwlgKXmzA77KmDbV2uYkwDQYJKoZIhvcNAQEL
-BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMDcyNTAzNDYzNFoXDTMzMDcy
-MjAzNDYzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
-AAOCAg8AMIICCgKCAgEAyuyNn36Sv87u8q7UmB7nhuMe71w6geUstcYKhO5ZahYf
-d9I9mGZTKpUvThgm65nrIPT8zE7yRqrgagP+MtuRtwByt9w7lO8Y/lJda4iHaTXd
-e9Yq0lZGrv0CeZ7NJZCGfPG9GJHG8Bh4IjjhMwGcNea50vfky72nuZnCdLKLbr55
-037bIQ7R2bPfxqNTo0Lcij5ApI6/YlpJZ14vi0yHDSCyTAM9PUlgv6EsYdQ3vf1C
-bdg2VlnPiAyYI2f7TRZ3YBrrUU8/qcBSsPoTNYgCaBld35/3JizLZJlWukPWnbe3
-TuU9FwRv/Vh+UnD2cnv7p0+JW2coa/9Yrk/W7oSFxGoujg/fKm7O9j76JKD/04U7
-yGkizQG4uako3BTcIDgHRsDqyIp9MR2v/nbb8Xol2cHL9nE3+ovrgn9upIFvgZk+
-nAuRgAmB4IaBtMS5ih0QJnlLB5FqDj+PkJG+s8iqOphg4V3P07zAvOTk1J96VDLO
-lnQHpjwMGXoYaevWHRU+Vmm2rktpTyJVt5xtlqjoN/FBnCYbQpAosS5fciN7ghcs
-zCmKVKC0riCa7MwPUooVOa/TqDzv5rGPp2vFXTdKDova7OlTo2YofDd2grOwM5O7
-TQp7MHUs1gtnHSEYdMeKWi6fSbtx4Jru13blXV7MMUHaQCg2YpJIqofnXQ5+9FMC
-AwEAAaM/MD0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwIwYDVR0RBBwwGoINd3d3
-LmxvY2FsaG9zdIIJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4ICAQAByseWC2Fp
-K8S9c/6aHQRwJPgkq1CGMx20wid1XvD9e+F8xF//L5MPa21gx6TC/dRO3rC6Oyqt
-mR011vMIh0/DMOhF8eFg9bn8dGSkUiWanw8OKsewTGzJFkoq4cDgO0hjfQTLRNnf
-KlDMZLISsnPFSQnhRN7c71j0dXrG+flsazK4CFy9FtXJEePkiCyS5ZSBDkfBKerp
-fif6Wz2Zk4yLwmmw0c/sNsgHkRfj3q+Zf1RgpcuUYmYbPigHSI2qpsWbqMeQmIvS
-+s7Tap3sQFCYIGCvSmOV4STY2JqxeWOGgR/xLZBpfJgdllfy1mpe7dHpi0kVTEdE
-cC1pNeFDn8xYm2M61oGUYy+b035HqD9SfPsnHOFzwgwINuHdL4xjmT+HwAtW+WOj
-105d+aIK55gOaJPGa7Pc7UMYtN7Oc/9hWfYti0MXnsyYfCNx6Fl7jtKs1AG2BbQd
-sReZj7em23DBe75I4+DCcNWQg40HXsDo2h+z+Xk3SFb/gvHMtmzFudKCDIpD0PS5
-gEXEzkKRg/++6iXGF16eBibZ8PED6416rGJz1Bo1YpXSyYCZG6oWwXZTg9fvDZX5
-FfLnQACV02y2Gs74h23Yq+QmA30Ly5GPrR5SBRaNiCY1SS7gCAfRah9zJjvbXNGw
-h0Eq48Dlw12GaUww3y05/IoAJxtHxZigdQ==
------END CERTIFICATE-----
diff --git a/test/certs/localhost.key b/test/certs/localhost.key
deleted file mode 100644
index 311e33d..0000000
--- a/test/certs/localhost.key
+++ /dev/null
@@ -1,52 +0,0 @@
------BEGIN PRIVATE KEY-----
-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
-ThIs987FU8HXD54GnfB03s/HOCaUpozh
------END PRIVATE KEY-----
diff --git a/test/certs/localhost.pfx b/test/certs/localhost.pfx
deleted file mode 100644
index 8cb9579..0000000
Binary files a/test/certs/localhost.pfx and /dev/null differ
diff --git a/test/certs/localhost.srl b/test/certs/localhost.srl
deleted file mode 100644
index 91e02ab..0000000
--- a/test/certs/localhost.srl
+++ /dev/null
@@ -1 +0,0 @@
-364A4682E95D1BD4770477A5C8B7381A1D44F305