{"id":18283087,"url":"https://github.com/cysharp/yetanotherhttphandler","last_synced_at":"2025-05-15T22:02:50.181Z","repository":{"id":184395592,"uuid":"665407697","full_name":"Cysharp/YetAnotherHttpHandler","owner":"Cysharp","description":"YetAnotherHttpHandler brings the power of HTTP/2 (and gRPC) to Unity and .NET Standard.","archived":false,"fork":false,"pushed_at":"2025-03-19T06:47:38.000Z","size":482112,"stargazers_count":415,"open_issues_count":19,"forks_count":36,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-04-01T07:47:16.319Z","etag":null,"topics":["csharp","dotnet","grpc","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Cysharp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-12T06:23:27.000Z","updated_at":"2025-03-27T13:33:30.000Z","dependencies_parsed_at":"2023-10-02T11:28:33.645Z","dependency_job_id":"b035a463-6196-4b30-a38b-c55a81828fae","html_url":"https://github.com/Cysharp/YetAnotherHttpHandler","commit_stats":null,"previous_names":["cysharp/yetanotherhttphandler"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cysharp%2FYetAnotherHttpHandler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cysharp%2FYetAnotherHttpHandler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cysharp%2FYetAnotherHttpHandler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cysharp%2FYetAnotherHttpHandler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Cysharp","download_url":"https://codeload.github.com/Cysharp/YetAnotherHttpHandler/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247801175,"owners_count":20998339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dotnet","grpc","unity"],"created_at":"2024-11-05T13:07:17.531Z","updated_at":"2025-05-15T22:02:50.165Z","avatar_url":"https://github.com/Cysharp.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# YetAnotherHttpHandler\nYetAnotherHttpHandler brings the power of HTTP/2 to Unity and .NET Standard.\n\nThis library enables the use of HTTP/2, which Unity does not support. It allows you to use grpc-dotnet instead of the deprecated C-core gRPC library. It can also be used for asset downloading via HTTP/2, providing more functionality to your projects.\n\nThe library is implemented as a HttpHandler for HttpClient, so you can use the same API by just replacing the handler. (drop-in replacement)\n\n### Highlights\n- Unity support (including Apple Silicon support)\n- Compatible with gRPC (grpc-dotnet)\n- Leveraging `System.Net.Http.HttpClient` API\n\n### Under the hood\nThe handler is built on top of [hyper](https://hyper.rs/) and [Rustls](https://github.com/rustls/rustls). It is a binding library that brings the power of those libraries to Unity and .NET.\n\n## Supported platforms and runtimes\n\n- Unity 2021.3 (LTS) or later\n\nArchitecture/Platform | Windows | macOS | Linux | Android | iOS\n-- | -- | -- | -- | -- | --\n\u003cstrong\u003ex64 (x86_64)\u003c/strong\u003e | ✔ | ✔ | ☁ | ☁ | ☁\n\u003cstrong\u003earm64 (aarch64, Apple Silicon)\u003c/strong\u003e | ☁ | ✔ | 📆 | ✔ | ✔\n\u003cstrong\u003earmv7\u003c/strong\u003e | - | - | - | ☁ | -\n\n- ✔ (Tier 1): Verify that it works, and active development support.\n- ☁ (Tier 2): The build is available, but not confirmed to work.\n- 📆 (Planned): Currently, the build is not available yet.\n\n\u003c!--\n- Unity 2021.3 (LTS) or later\n\t- Editor\n\t\t- Windows (x64)\n\t\t- macOS (x64, Apple Silicon)\n\t- Standalone\n\t\t- Windows (x64)\n\t\t- macOS (x64, Apple Silicon)\n\t\t- Linux (x64)\n\t- Player\n\t\t- Windows (x64)\n\t\t- macOS (x64, Apple Silicon)\n\t\t- Linux (x64)\n\t\t- iOS (Arm64, x64)\n\t\t- Android (Armv7, Arm64, x64)\n--\u003e\n\n## Features\n- HTTP/1.0, HTTP/1.1\n- HTTP/2\n\t- Multiple streams on a single connection\n\t- Compatible with grpc-dotnet (Grpc.Net.Client)\n\t- HTTP/2 over cleartext\n\t- TLS 1.2/1.3 with ALPN\n\t\t- TLS support is powered by Rustls + webpki\n\t\t- Client certificate\n    - Unix Domain Socket (macOS, Linux)\n\n### Not supported yet\n- HTTP proxy support\n- Verification of certificates by security features built into the OS\n- More platform supports\n\t- Linux on Arm\n\n### Not supported (not planned)\n- NTLM and Kerberos authentication\n- Platforms\n\t- Unity 2021.2 or earlier\n\t- .NET 5+\n\t- 32bit architectures (x86)\n\t- tvOS, watchOS, Tizen\n        - WebGL\n\n## Installation\n### Unity\n\nThis library depends on the following additional libraries:\n\n- [System.IO.Pipelines](https://www.nuget.org/packages/System.IO.Pipelines) (netstandard2.1)\n- [System.Runtime.CompilerServices.Unsafe](https://www.nuget.org/packages/System.Runtime.CompilerServices.Unsafe) (netstandard2.1)\n\n#### Method 1: Using NuGetForUnity + GitHub\n\n1. Install [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity) to your Unity project\n2. Install the following NuGet packages via NuGetForUnity:\n    - System.IO.Pipelines\n    - System.Runtime.CompilerServices.Unsafe\n3. Specify the following URL in `Add package from git URL...` of Package Manager on Unity\n```\nhttps://github.com/Cysharp/YetAnotherHttpHandler.git?path=src/YetAnotherHttpHandler#{Version}\n```\n\n\u003e [!NOTE]\n\u003e Please replace `{Version}` with the version number you want to install (e.g. `1.8.0`). See [Releases](https://github.com/Cysharp/YetAnotherHttpHandler/releases) page.\n\n#### Method 2: Using UnityNuGet scope registry\n\n1. Add the [UnityNuget](https://github.com/xoofx/UnityNuGet) scope registry:\n\n```\nhttps://github.com/xoofx/UnityNuGet#add-scope-registry-manifestjson\n```\n\n2. Specify the following URL in `Add package from git URL...` of Package Manager on Unity. This is the package that resolves NuGet dependencies.\n\n```\nhttps://github.com/Cysharp/YetAnotherHttpHandler.git?path=src/YetAnotherHttpHandler.Dependencies#{Version}\n```\n\n3. Specify the following URL in `Add package from git URL...` of Package Manager on Unity. This is the main packagee.\n\n```\nhttps://github.com/Cysharp/YetAnotherHttpHandler.git?path=src/YetAnotherHttpHandler#{Version}\n```\n\n\u003e [!NOTE]\n\u003e Please replace `{Version}` with the version number you want to install (e.g. `1.8.0`). See [Releases](https://github.com/Cysharp/YetAnotherHttpHandler/releases) page.\n\n#### Method 3: Install from GitHub / Git repository\n\n1. Please download and install [Cysharp.Net.Http.YetAnotherHttpHandler.Dependencies.unitypackage\n from the dependency redistribution on the release page](https://github.com/Cysharp/YetAnotherHttpHandler/releases/tag/redist-20240111-01).\n\n2. Specify the following URL in `Add package from git URL...` of Package Manager on Unity.\n\n```\nhttps://github.com/Cysharp/YetAnotherHttpHandler.git?path=src/YetAnotherHttpHandler#{Version}\n```\n\n\u003e [!NOTE]\n\u003e Please replace `{Version}` with the version number you want to install (e.g. `1.8.0`). See [Releases](https://github.com/Cysharp/YetAnotherHttpHandler/releases) page.\n\n## Usage\n\nCreate an instance of YetAnotherHttpHandler and pass it to HttpClient.\n\n```csharp\nusing Cysharp.Net.Http;\n\nusing var handler = new YetAnotherHttpHandler();\nvar httpClient = new HttpClient(handler);\n\nvar result = await httpClient.GetStringAsync(\"https://www.example.com\");\n```\n\nWith these steps, your HttpClient is now compatible with HTTP/2.✨\n\n`YetAnotherHttpHandler` and `HttpClient` can be held following best practices and shared across multiple threads or requests.\n\nHowever, since it does not have features such as connection control by the number of streams, it is necessary to separate handler instances when explicitly creating different connections.\n\n### Using gRPC (grpc-dotnet) library\n\nTo use grpc-dotnet (Grpc.Net.Client), add the following additional libraries:\n \n- Grpc.Core.Api\n- Grpc.Net.Client\n- Grpc.Net.Common\n- Microsoft.Extensions.Logging.Abstractions\n- System.Diagnostics.DiagnosticSource\n\n#### Method 1: Using NuGetForUnity\n\n1. Install `Grpc.Net.Client` from NuGet via NuGetForUnity\n\n#### Method 2: Using UnityNuget scope registry\n\nTo use grpc-dotnet (Grpc.Net.Client), add the following additional library to `manifest.json`:\n\n```json\n{\n  \"dependencies\": {\n    \"org.nuget.grpc.net.client\": \"{version}\"\n  }\n}\n```\n\n\u003e [!NOTE]\n\u003e Replace `{version}` with the latest version available in NuGet: https://www.nuget.org/packages/Grpc.Net.Client#versions-body-tab\n\n#### Method 3: Install pre-built package or install the libraries manually.\n\nPlease download and install [Grpc.Net.Client.Dependencies.unitypackage\n from the dependency redistribution on the release page](https://github.com/Cysharp/YetAnotherHttpHandler/releases/tag/redist-20230728-01), or obtain the library from NuGet.\n\n\n#### Using GrpcChannel with YetAnotherHttpHandler\nCreate an instance of `YetAnotherHttpHandler` and pass it to `GrpcChannelOptions.HttpHandler` property.\n\n```csharp\nusing Cysharp.Net.Http;\n\nusing var handler = new YetAnotherHttpHandler();\nusing var channel = GrpcChannel.ForAddress(\"https://api.example.com\", new GrpcChannelOptions() { HttpHandler = handler });\nvar greeter = new GreeterClient(channel);\n\nvar result = await greeter.SayHelloAsync(new HelloRequest { Name = \"Alice\" });\n\n// -- OR --\n\nusing var channel = GrpcChannel.ForAddress(\"https://api.example.com\", new GrpcChannelOptions() { HttpHandler = new YetAnotherHttpHandler(), DisposeHttpClient = true });\nvar greeter = new GreeterClient(channel);\n\nvar result = await greeter.SayHelloAsync(new HelloRequest { Name = \"Alice\" });\n```\n\n## Configurations\nWhen creating a YetAnotherHttpHandler instance, you can configure the following HTTP client settings.\n\nOnce the handler sends a request, these settings become immutable and cannot be changed.\n\n|Property| Description |\n| -- | -- |\n|PoolIdleTimeout|Gets or sets an optional timeout for idle sockets being kept-alive. Default is 90 seconds.|\n|MaxIdlePerHost|Gets or sets the maximum idle connection per host allowed in the pool. Default is usize::MAX (no limit).|\n|Http2Only|Gets or sets a value that indicates whether to force the use of HTTP/2.|\n|SkipCertificateVerification|Gets or sets a value that indicates whether to skip certificate verification.|\n|OnVerifyServerCertificate|Gets or sets a custom handler that validates server certificates.|\n|RootCertificates|Gets or sets a custom root CA. By default, the built-in root CA (Mozilla's root certificates) is used. See also https://github.com/rustls/webpki-roots. |\n|OverrideServerName|Gets or sets a value that specifies subject alternative name (SAN) of the certificate.|\n|ClientAuthCertificates|Gets or sets a custom client auth key.|\n|ClientAuthKey|Gets or sets a custom client auth certificates.|\n|Http2InitialStreamWindowSize|Gets or sets the SETTINGS_INITIAL_WINDOW_SIZE option for HTTP2 stream-level flow control.|\n|Http2InitialConnectionWindowSize|Gets or sets the max connection-level flow control for HTTP2|\n|Http2AdaptiveWindow|Gets or sets whether to use an adaptive flow control. Enabling this will override the limits set in http2_initial_stream_window_size and http2_initial_connection_window_size.|\n|Http2MaxFrameSize|Gets or sets the maximum frame size to use for HTTP2.|\n|ConnectTimeout|Gets or sets timeout for TCP connection establishment. Pass null to never timeout. Default is never timeout.|\n|Http2KeepAliveInterval|Gets or sets an interval for HTTP2 Ping frames should be sent to keep a connection alive. Pass \u003cvalue\u003enull\u003c/value\u003e to disable HTTP2 keep-alive. Default is currently disabled.|\n|Http2KeepAliveTimeout|Gets or sets a timeout for receiving an acknowledgement of the keep-alive ping. If the ping is not acknowledged within the timeout, the connection will be closed. Does nothing if http2_keep_alive_interval is disabled. Default is 20 seconds.|\n|Http2KeepAliveWhileIdle|Gets or sets whether HTTP2 keep-alive should apply while the connection is idle. If disabled, keep-alive pings are only sent while there are open request/responses streams. If enabled, pings are also sent when no streams are active. Does nothing if http2_keep_alive_interval is disabled. Default is false.|\n|Http2MaxConcurrentResetStreams|Gets or sets the maximum number of HTTP2 concurrent locally reset streams. See the documentation of h2::client::Builder::max_concurrent_reset_streams for more details. The default value is determined by the h2 crate.|\n|Http2MaxSendBufferSize|Gets or sets the maximum write buffer size for each HTTP/2 stream. Default is currently 1MB, but may change.|\n|Http2InitialMaxSendStreams|Gets or sets the initial maximum of locally initiated (send) streams. This value will be overwritten by the value included in the initial SETTINGS frame received from the peer as part of a connection preface.|\n|UnixDomainSocketPath|Gets or sets the path to a Unix Domain Socket to be used as HTTP communication channel instead of the default TCP.|\n|ResponsePipeOptions|Gets or sets the options for the pipe used to receive the response body.|\n\nMost of them expose [hyper client settings](https://docs.rs/hyper-util/latest/hyper_util/client/legacy/struct.Builder.html), so please check those as well.\n\n## Advanced\n### Using HTTP/2 over cleartext (h2c)\ngRPC requires communication over HTTP/2, but when it's a non-HTTPS connection, it defaults to attempting a connection with HTTP/1, causing connection issues.\nIn this case, setting the `YetAnotherHttpHandle.Http2Only` property to `true` allows for connections via HTTP/2 over cleartext (h2c).\n\n```csharp\nusing var handler = new YetAnotherHttpHandler() { Http2Only = true };\n```\n\n### Using custom root certificates\nCurrently, YetAnotherHttpHandler uses Mozilla's root certificates derived from webpki as the root CA.\n\nIf you want to use a self-signed certificate or a certificate issued by your organization, you need to set a custom root CA. In this case, you can specify the root certificates in pem format to `RootCertificates` property.\n\n```csharp\nvar rootCerts = @\"\n-----BEGIN CERTIFICATE-----\nMIIE9TCCAt2gAwIBAgIUUQ33LbUPwlgKXmzA77KmDbV2uYkwDQYJKoZIhvcNAQEL\nBQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMDcyNTAzNDYzNFoXDTMzMDcy\nMjAzNDYzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF\nAAOCAg8AMIICCgKCAgEAyuyNn36Sv87u8q7UmB7nhuMe71w6geUstcYKhO5ZahYf\nd9I9mGZTKpUvThgm65nrIPT8zE7yRqrgagP+MtuRtwByt9w7lO8Y/lJda4iHaTXd\ne9Yq0lZGrv0CeZ7NJZCGfPG9GJHG8Bh4IjjhMwGcNea50vfky72nuZnCdLKLbr55\n037bIQ7R2bPfxqNTo0Lcij5ApI6/YlpJZ14vi0yHDSCyTAM9PUlgv6EsYdQ3vf1C\nbdg2VlnPiAyYI2f7TRZ3YBrrUU8/qcBSsPoTNYgCaBld35/3JizLZJlWukPWnbe3\nTuU9FwRv/Vh+UnD2cnv7p0+JW2coa/9Yrk/W7oSFxGoujg/fKm7O9j76JKD/04U7\nyGkizQG4uako3BTcIDgHRsDqyIp9MR2v/nbb8Xol2cHL9nE3+ovrgn9upIFvgZk+\nnAuRgAmB4IaBtMS5ih0QJnlLB5FqDj+PkJG+s8iqOphg4V3P07zAvOTk1J96VDLO\nlnQHpjwMGXoYaevWHRU+Vmm2rktpTyJVt5xtlqjoN/FBnCYbQpAosS5fciN7ghcs\nzCmKVKC0riCa7MwPUooVOa/TqDzv5rGPp2vFXTdKDova7OlTo2YofDd2grOwM5O7\nTQp7MHUs1gtnHSEYdMeKWi6fSbtx4Jru13blXV7MMUHaQCg2YpJIqofnXQ5+9FMC\nAwEAAaM/MD0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwIwYDVR0RBBwwGoINd3d3\nLmxvY2FsaG9zdIIJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4ICAQAByseWC2Fp\nK8S9c/6aHQRwJPgkq1CGMx20wid1XvD9e+F8xF//L5MPa21gx6TC/dRO3rC6Oyqt\nmR011vMIh0/DMOhF8eFg9bn8dGSkUiWanw8OKsewTGzJFkoq4cDgO0hjfQTLRNnf\nKlDMZLISsnPFSQnhRN7c71j0dXrG+flsazK4CFy9FtXJEePkiCyS5ZSBDkfBKerp\nfif6Wz2Zk4yLwmmw0c/sNsgHkRfj3q+Zf1RgpcuUYmYbPigHSI2qpsWbqMeQmIvS\n+s7Tap3sQFCYIGCvSmOV4STY2JqxeWOGgR/xLZBpfJgdllfy1mpe7dHpi0kVTEdE\ncC1pNeFDn8xYm2M61oGUYy+b035HqD9SfPsnHOFzwgwINuHdL4xjmT+HwAtW+WOj\n105d+aIK55gOaJPGa7Pc7UMYtN7Oc/9hWfYti0MXnsyYfCNx6Fl7jtKs1AG2BbQd\nsReZj7em23DBe75I4+DCcNWQg40HXsDo2h+z+Xk3SFb/gvHMtmzFudKCDIpD0PS5\ngEXEzkKRg/++6iXGF16eBibZ8PED6416rGJz1Bo1YpXSyYCZG6oWwXZTg9fvDZX5\nFfLnQACV02y2Gs74h23Yq+QmA30Ly5GPrR5SBRaNiCY1SS7gCAfRah9zJjvbXNGw\nh0Eq48Dlw12GaUww3y05/IoAJxtHxZigdQ==\n-----END CERTIFICATE-----\n\";\nusing var handler = new YetAnotherHttpHandler() { RootCertificates = rootCerts };\n```\n\n### Ignore certificate validation errors\nWe strongly not recommend this, but in some cases, you may want to skip certificate validation when connecting via HTTPS. In this scenario, you can ignore certificate errors by setting the `SkipCertificateVerification` property to `true`.\n\n### Handling server certificate verification\nYou can customize the server certificate verification process by setting the `OnVerifyServerCertificate` property.\n\nThe callback should return `true` or `false` based on the verification result. If the property is set, the root CA verification is not performed.\n\n```csharp\nusing var httpHandler = new YetAnotherHttpHandler()\n{\n    OnVerifyServerCertificate = (serverName, certificate, now) =\u003e\n    {\n        var cert = new X509Certificate2(certificate);\n        return serverName == \"api.example.com\" \u0026\u0026\n               cert.Subject == \"CN=api.example.com\";\n    }\n};\n```\n\n### Using Unix Domain Sockets as HTTP transport layer\n\nUnix Domain Sockets can be used as the HTTP transport layer for local usecases (e.g. IPC based on gRPC), instead of network-based TCP.\n\nSet the `UnixDomainSocketPath` property to enable UDS-based communication to a server listening at the given path:\n\n```csharp\nusing var handler = new YetAnotherHttpHandler() { Http2Only = true, UnixDomainSocketPath = \"/tmp/example.sock\" };\nusing var channel = GrpcChannel.ForAddress(\"http://localhost\", new GrpcChannelOptions() { HttpHandler = handler });\n```\n\nNote:\n- HTTPS is not supported over UDS. All HTTPS related configuration properties are ignored if UDS is enabled.\n- The grpc-dotnet library doesn't handle non-HTTP schemes (like \"unix://\"), so keep passing an HTTP URI to `GrpcChannel`, e.g. http://localhost.\n  The actual HTTP requests will be redirected to `UnixDomainSocketPath` by YetAnotherHttpHandler internally.\n- When using Kestrel on the server, you need to set the `KestrelServerOptions.AllowAlternateSchemes` option to `true`.\n\n### Specifying the number of worker threads\nYetAnotherHttpHandler's communication processing is run on worker threads of the tokio runtime. The number of worker threads is determined based on the number of CPU cores by default.\nYou can specify a number of worker threads using the `YetAnotherHttpHandler.SetWorkerThreads` method.\n\n## Development\n### Build \u0026 Tests\n\nTo debug run in your local environment, you first need to build the native library. Please specify the target as follows when building.\n\n```bash\ncargo build --target x86_64-pc-windows-msvc\n```\n\nWhen debugging or running unit tests, the native library is loaded from the following directory.\n\n- native/targets/{arch}-{os}-{toolchain}/{debug,release}/{lib}yaha_native.{dll,so}\n\nWhen creating a package, The following artifacts directory is used.\n\n- native/artifacts/{.NET RID}/{lib}yaha_native.{dll,so}\n\n```bash\n# Generate THIRD-PARTY-NOTICES using cargo-about\ncargo about generate about.hbs \u003e ../THIRD-PARTY-NOTICES\n```\n\n## License\nMIT License\n\nThis library depends on third-party components. Please refer to [THIRD-PARTY-NOTICES](./THIRD-PARTY-NOTICES) for their licenses.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcysharp%2Fyetanotherhttphandler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcysharp%2Fyetanotherhttphandler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcysharp%2Fyetanotherhttphandler/lists"}