Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Align behavior on Unity to .NET runtime #78

Merged
merged 1 commit into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion YetAnotherHttpHandler.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{49D0877D-6B51-4A83-8B93-9DC19BAEABB4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerformanceCheck", "perf\PerformanceCheck\PerformanceCheck.csproj", "{BD12E8F7-E190-4B76-AFF5-62376CF0BD57}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceCheck", "perf\PerformanceCheck\PerformanceCheck.csproj", "{BD12E8F7-E190-4B76-AFF5-62376CF0BD57}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YetAnotherHttpHandler.StandaloneTestServer", "test\YetAnotherHttpHandler.StandaloneTestServer\YetAnotherHttpHandler.StandaloneTestServer.csproj", "{BD7A619A-91BB-48A9-AA79-A9724DB320DD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -39,13 +41,18 @@ Global
{BD12E8F7-E190-4B76-AFF5-62376CF0BD57}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD12E8F7-E190-4B76-AFF5-62376CF0BD57}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD12E8F7-E190-4B76-AFF5-62376CF0BD57}.Release|Any CPU.Build.0 = Release|Any CPU
{BD7A619A-91BB-48A9-AA79-A9724DB320DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD7A619A-91BB-48A9-AA79-A9724DB320DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD7A619A-91BB-48A9-AA79-A9724DB320DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD7A619A-91BB-48A9-AA79-A9724DB320DD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{22CFEF14-D36A-4E21-B51F-F31053C0E870} = {EDDCC9A6-BB1C-4AB9-A0C1-9AD888858442}
{BD12E8F7-E190-4B76-AFF5-62376CF0BD57} = {49D0877D-6B51-4A83-8B93-9DC19BAEABB4}
{BD7A619A-91BB-48A9-AA79-A9724DB320DD} = {EDDCC9A6-BB1C-4AB9-A0C1-9AD888858442}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0F200E0E-4EC0-4C1A-BF65-BA52D3291577}
Expand Down
14 changes: 14 additions & 0 deletions src/YetAnotherHttpHandler/YetAnotherHttpHttpContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,22 @@ protected override async Task SerializeToStreamAsync(Stream stream, TransportCon
protected async Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken)
#endif
{
#if UNITY_2021_1_OR_NEWER
// NOTE: Unity's Mono has older implementations of HttpClient and HttpContent.
// We need to wrap exceptions in HttpRequestException to align to the behavior of the .NET runtime.
try
{
await _pipeReader.CopyToAsync(stream, cancellationToken).ConfigureAwait(false);
await _pipeReader.CompleteAsync().ConfigureAwait(false);
}
catch (Exception e) when (e is IOException or ObjectDisposedException)
{
throw new HttpRequestException("Error while copying content to a stream.", e);
}
#else
await _pipeReader.CopyToAsync(stream, cancellationToken).ConfigureAwait(false);
await _pipeReader.CompleteAsync().ConfigureAwait(false);
#endif
}

protected override Task<Stream> CreateContentReadStreamAsync()
Expand Down
9 changes: 9 additions & 0 deletions test/YetAnotherHttpHandler.StandaloneTestServer/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using _YetAnotherHttpHandler.Test;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = TestServerForHttp1AndHttp2.BuildApplication(builder);

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5115",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\YetAnotherHttpHandler.Test\ITestServerBuilder.cs" Link="ITestServerBuilder.cs" />
<Compile Include="..\YetAnotherHttpHandler.Test\TestServerForHttp1AndHttp2.cs" Link="TestServerForHttp1AndHttp2.cs" />
<Compile Include="..\YetAnotherHttpHandler.Test\StreamExtensions.cs" Link="StreamExtensions.cs" />
</ItemGroup>

<ItemGroup>
<Protobuf Include="..\YetAnotherHttpHandler.Test\Protos\greet.proto" GrpcServices="Both" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.49.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
21 changes: 21 additions & 0 deletions test/YetAnotherHttpHandler.StandaloneTestServer/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Kestrel": {
"Endpoints": {
"Http1ClearText": {
"Url": "http://localhost:5115",
"Protocols": "Http1"
},
"Http2ClearText": {
"Url": "http://localhost:5116",
"Protocols": "Http2"
}
}
},
"AllowedHosts": "*"
}
12 changes: 6 additions & 6 deletions test/YetAnotherHttpHandler.Test/ClientCertificateTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected Task<TestWebAppServer> LaunchServerAsync<T>(Action<WebApplicationBuild
public async Task NotSet()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new YetAnotherHttpHandler()
{
//ClientAuthCertificates = File.ReadAllText("./Certificates/client.crt"),
Expand All @@ -62,7 +62,7 @@ public async Task NotSet()
public async Task UseClientCertificate()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new YetAnotherHttpHandler()
{
ClientAuthCertificates = File.ReadAllText("./Certificates/client.crt"),
Expand All @@ -84,7 +84,7 @@ public async Task UseClientCertificate()
public async Task Invalid()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new YetAnotherHttpHandler()
{
ClientAuthCertificates = File.ReadAllText("./Certificates/client_unknown.crt"), // CN=unknown.example.com
Expand All @@ -105,7 +105,7 @@ public async Task Invalid()
public async Task Reference_SocketHttpHandler_NotSet()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new SocketsHttpHandler();
httpHandler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true;
var httpClient = new HttpClient(httpHandler);
Expand All @@ -122,7 +122,7 @@ public async Task Reference_SocketHttpHandler_NotSet()
public async Task Reference_SocketHttpHandler_UseClientCertificate()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new SocketsHttpHandler();
httpHandler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true;
httpHandler.SslOptions.ClientCertificates = new X509CertificateCollection()
Expand All @@ -144,7 +144,7 @@ public async Task Reference_SocketHttpHandler_UseClientCertificate()
public async Task Reference_SocketHttpHandler_Invalid()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new SocketsHttpHandler();
httpHandler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true;
httpHandler.SslOptions.ClientCertificates = new X509CertificateCollection()
Expand Down
20 changes: 13 additions & 7 deletions test/YetAnotherHttpHandler.Test/Http1Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,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<TestServerForHttp1>(TestWebAppServerListenMode.InsecureHttp1Only);
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>(TestWebAppServerListenMode.InsecureHttp1Only);

// Act
var ex = await Record.ExceptionAsync(async () => await httpClient.GetAsync($"http://localhost.exmample/"));
Expand All @@ -34,7 +34,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<TestServerForHttp1>(TestWebAppServerListenMode.InsecureHttp1Only);
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>(TestWebAppServerListenMode.InsecureHttp1Only);

// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/");
Expand All @@ -52,7 +52,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<TestServerForHttp1>(TestWebAppServerListenMode.InsecureHttp1Only);
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>(TestWebAppServerListenMode.InsecureHttp1Only);

// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/not-found");
Expand All @@ -70,14 +70,14 @@ 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<TestServerForHttp1>(TestWebAppServerListenMode.InsecureHttp1Only);
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>(TestWebAppServerListenMode.InsecureHttp1Only);

// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/response-headers");
var responseBody = await response.Content.ReadAsStringAsync();

// Assert
Assert.Equal(new string[] {"foo"}, response.Headers.GetValues("x-test"));
Assert.Equal(new string[] { "foo" }, response.Headers.GetValues("x-test"));
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("__OK__", responseBody);
}
Expand All @@ -88,7 +88,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<TestServerForHttp1>(TestWebAppServerListenMode.InsecureHttp1Only);
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>(TestWebAppServerListenMode.InsecureHttp1Only);

// Act
var response = await httpClient.GetAsync($"{server.BaseUri}/ハロー");
Expand All @@ -105,7 +105,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<TestServerForHttp1>(TestWebAppServerListenMode.InsecureHttp1Only);
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>(TestWebAppServerListenMode.InsecureHttp1Only);
var pipe = new Pipe();
var content = new StreamContent(pipe.Reader.AsStream());
var cts = new CancellationTokenSource();
Expand All @@ -118,6 +118,12 @@ public async Task Post_Cancel()

// Assert
Assert.NotNull(ex);
#if UNITY_2021_1_OR_NEWER
Assert.IsAssignableFrom<HttpRequestException>(ex);
Assert.IsAssignableFrom<OperationCanceledException>(ex.InnerException);
#else
// NOTE: .NET HttpClient throws HttpRequestException with OperationCanceledException if it contains an OperationCanceledException
Assert.IsAssignableFrom<OperationCanceledException>(ex);
#endif
}
}
6 changes: 3 additions & 3 deletions test/YetAnotherHttpHandler.Test/Http2Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected override Task<TestWebAppServer> LaunchServerAsyncCore<T>(Action<WebApp
public async Task SelfSignedCertificate_NotTrusted()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new YetAnotherHttpHandler() { SkipCertificateVerification = false }; // We need to verify server certificate.
var httpClient = new HttpClient(httpHandler);

Expand All @@ -62,7 +62,7 @@ public async Task SelfSignedCertificate_NotTrusted()
public async Task SelfSignedCertificate_NotTrusted_SkipValidation()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new YetAnotherHttpHandler() { SkipCertificateVerification = true };
var httpClient = new HttpClient(httpHandler);

Expand All @@ -79,7 +79,7 @@ public async Task SelfSignedCertificate_NotTrusted_SkipValidation()
public async Task SelfSignedCertificate_Trusted_CustomRootCA()
{
// Arrange
await using var server = await LaunchServerAsync<TestServerForHttp2>();
await using var server = await LaunchServerAsync<TestServerForHttp1AndHttp2>();
var httpHandler = new YetAnotherHttpHandler()
{
// We need to verify server certificate.
Expand Down
Loading
Loading