CosmoHttpClient 4.0.0
See the version list below for details.
dotnet add package CosmoHttpClient --version 4.0.0
NuGet\Install-Package CosmoHttpClient -Version 4.0.0
<PackageReference Include="CosmoHttpClient" Version="4.0.0" />
<PackageVersion Include="CosmoHttpClient" Version="4.0.0" />
<PackageReference Include="CosmoHttpClient" />
paket add CosmoHttpClient --version 4.0.0
#r "nuget: CosmoHttpClient, 4.0.0"
#:package CosmoHttpClient@4.0.0
#addin nuget:?package=CosmoHttpClient&version=4.0.0
#tool nuget:?package=CosmoHttpClient&version=4.0.0
CosmoHttpClient
CosmoHttpClient is a .NET 10 HTTP client library built clean-sheet to outperform System.Net.Http.HttpClient while still offering the convenience layer (cookies, redirects, retries, response cache, decompression, NDJSON, telemetry) people expect from an everyday client.
Two layers, one recommended surface:
FastClient/FastH2Client/FastH3Client— span-based codecs on arena buffers, per-core sharded H/1.1 pool, multiplexed H/2 connections, QUIC-multiplexed H/3 with QPACK dynamic table. Zero per-op allocation on the data plane. BeatsHttpClienton every measured benchmark.FastFeatureClient— wrapsFastClientwith an opt-in handler pipeline:DecompressionHandler,CookieHandler,RedirectHandler,RetryHandler,ResponseCacheHandler,TelemetryHandler. Pay only for the features you turn on.
Also in tree: CosmoWebSocket (RFC 6455), Grpc/* framing primitives, and a tools/PerfGate runner that enforces BDN-measured ratio + allocation rules on every change.
Requirements
- .NET SDK 10.0+
- For HTTP/3: platform QUIC support (
System.Net.Quic/ MsQuic availability)
The library targets net10.0.
Repository layout
| Path | Purpose |
|---|---|
src/CosmoHttpClient/Fast/ |
FastClient + HTTP/1.1 connection pool, span-based H1 codec |
src/CosmoHttpClient/Fast/Http2/ |
FastH2Client, HPACK, frame layer, multiplexed H/2 connection |
src/CosmoHttpClient/Fast/Http3/ |
FastH3Client, QPACK, QUIC stream pool |
src/CosmoHttpClient/Fast/Features/ |
Handler pipeline: FastFeatureClient, Decompression/Cookie/Redirect/Retry/ResponseCache/Telemetry handlers, JSON + NDJSON extensions |
src/CosmoHttpClient/Connections/ |
Socket / TLS / SOCKS5 transport — used by CosmoWebSocket |
src/CosmoHttpClient/WebSockets/ |
CosmoWebSocket (RFC 6455) |
src/CosmoHttpClient/Grpc/ |
gRPC framing primitives |
tests/CosmoHttpClient.Tests |
xUnit suite (~410 tests) |
samples/CosmoHttpClient.Sample |
Runnable sample app |
benchmarks/CosmoHttpClient.Benchmarks |
BDN benchmarks |
benchmarks/perf-targets.json |
Perf-gate rules consumed by tools/PerfGate |
tools/PerfGate |
BDN runner + JSON parser; exits non-zero on regression |
Build, test, run
dotnet build --nologo
dotnet test --nologo --no-build
dotnet run --project samples/CosmoHttpClient.Sample
dotnet run --project samples/CosmoHttpClient.Sample -- --h2 https://www.cloudflare.com/
dotnet run --project samples/CosmoHttpClient.Sample -- --h3 https://www.cloudflare.com/
Run the perf gate (full BDN sweep + rule validation, ~15-20 min):
dotnet run -c Release --project tools/PerfGate
# Or evaluate against existing artifacts (no BDN re-run):
dotnet run -c Release --project tools/PerfGate -- --results gate-artifacts/results
Quick start — FastClient (HTTP/1.1)
using CosmoHttpClient.Fast;
await using var client = new FastClient();
await using var resp = await client.GetAsync(new Uri("https://api.example.com/v1/things"));
Console.WriteLine($"{resp.StatusCode}: {Encoding.UTF8.GetString(resp.Body.Span)}");
POST with JSON body and headers:
private static readonly HeaderPair[] AuthHeaders = {
new("User-Agent", "myapp/1.0"),
new("Content-Type", "application/json"),
new("Authorization", $"Bearer {token}"),
};
var body = JsonSerializer.SerializeToUtf8Bytes(new { name = "widget" });
await using var resp = await client.PostAsync(uri, body, AuthHeaders);
Streaming a large response via PipeReader (Content-Length and chunked both supported):
await using var resp = await client.GetStreamAsync(new Uri("https://example.com/big.bin"));
var rdr = resp.BodyReader;
while (true)
{
var read = await rdr.ReadAsync();
foreach (var seg in read.Buffer) await output.WriteAsync(seg);
rdr.AdvanceTo(read.Buffer.End);
if (read.IsCompleted) break;
}
Lifetime contract: a streaming response borrows a pool connection until disposed. Drain-then-dispose returns the connection; dispose-without-drain marks the connection broken (wire state is unknown) and the pool drops it. Set FastClientOptions.BackgroundDrainOnDispose = true to opt into a fire-and-forget drain that recovers the connection at the cost of a background task per abandoned response.
FastClient exposes GetAsync, GetStreamAsync, PostAsync, and SendAsync / SendStreamAsync(method, uri, body, headers, ct) for arbitrary verbs. Buffered response body is ReadOnlyMemory<byte> aliasing the connection's arena, valid until the response is disposed. Headers iterate via a zero-allocation Http1HeaderEnumerator.
Quick start — FastH2Client (HTTP/2)
using CosmoHttpClient.Fast.Http2;
await using var h2 = new FastH2Client();
await using var res = await h2.GetAsync(new Uri("https://www.cloudflare.com/"));
Console.WriteLine($"H/2 {res.StatusCode}, {res.Body.Length} bytes");
One multiplexed connection per origin (h2c plain or h2 over TLS+ALPN), span-based HPACK + frame layer, friendly GetAsync / PostAsync.
Quick start — FastH3Client (HTTP/3)
using CosmoHttpClient.Fast.Http3;
await using var h3 = new FastH3Client();
try
{
await using var res = await h3.GetAsync(new Uri("https://www.cloudflare.com/"));
Console.WriteLine($"H/3 {res.StatusCode}, {res.Body.Length} bytes");
}
catch (FastH3NotSupportedException) { /* QUIC not available */ }
QUIC stream multiplexing, static + dynamic QPACK. Throws FastH3NotSupportedException on platforms without QUIC (e.g. macOS today).
FastFeatureClient — opt-in handler pipeline
Wrap a FastClient with the handlers you actually want. Empty handler list = bare FastClient performance. Anything beyond is pay-as-you-go.
using CosmoHttpClient.Fast.Features;
await using var client = new FastFeatureClient(new FastFeatureClientOptions
{
Handlers = new IFastFeatureHandler[]
{
new TelemetryHandler(new ActivitySourceTelemetry()), // outermost
new ResponseCacheHandler(), // RFC 7234 / 9111
new DecompressionHandler(), // gzip / deflate / br / zstd
new CookieHandler(), // RFC 6265
new RedirectHandler(), // 301/302/303 → GET, 307/308 preserve
new RetryHandler(), // 408/429/5xx, idempotent-only by default
},
});
await using var resp = await client.GetAsync(new Uri("https://api.example.com/"));
JSON / NDJSON helpers compose on top of the same client:
var widget = await client.GetJsonAsync(uri, MyJsonContext.Default.Widget);
await foreach (var line in client.GetNdjsonAsync(uri, MyJsonContext.Default.LogLine, ct))
Process(line);
Handler ordering
Composition is order-sensitive — the first handler in the list runs outermost. Recommended layering (outer → inner):
Telemetry → ResponseCache → Decompression → Cookies → Redirects → Retries → terminal transport
Why this order:
- Telemetry outermost so spans cover everything, including retries / redirects.
- ResponseCache outside Decompression so the cache stores wire bytes (so the same entry serves clients with different
Accept-Encoding). - Decompression outside Cookies / Redirects so subsequent handlers see plain bodies.
- Retries innermost (around the transport) so a retried request does not loop the redirect / cookie machinery.
You can deviate when you have a reason — the framework just hands you control.
CosmoWebSocket
using CosmoHttpClient.WebSockets;
await using var ws = await CosmoWebSocket.ConnectAsync("wss://example.com/socket");
await ws.SendAsync(payload, CosmoWebSocketMessageType.Binary, endOfMessage: true, ct);
Optional permessage-deflate, ping/pong keepalive, RFC 6455 close handshake. Built on the same Connections/ socket + TLS + SOCKS5 plumbing as the rest of the library.
Performance
Latest BDN sweep on Apple M1 / .NET 10 / Kestrel loopback. Cosmo / HttpClient ratios — values < 1.00 mean Cosmo is faster.
| Benchmark | Cosmo | HttpClient | Ratio |
|---|---|---|---|
| Data plane (write+parse, in-memory) | 151 ns / 0 B | n/a (vs naive) | 0.74× of naive baseline |
| H1.1 single connection (1 KiB GET) | 47.2 µs / 771 B | 51.4 µs / 3.4 KB | 0.92× / 4.4× less alloc |
| H1.1 pooled, single-threaded | 42.9 µs / 946 B | 51.7 µs / 3.4 KB | 0.83× / 3.6× less alloc |
| H1.1 pooled, 8 workers × 64 reqs | 4.93 ms / 187 KB | 4.88 ms / 1.6 MB | 1.01× / 8.7× less alloc |
Friendly FastClient API (1 KiB GET) |
43.4 µs / 1382 B | 51.1 µs / 3.4 KB | 0.85× / 2.5× less alloc |
Friendly FastClient over HTTPS |
55.3 µs / 3022 B | 63.6 µs / 4.95 KB | 0.87× / 1.7× less alloc |
Friendly FastClient streaming 4 MiB |
1.08 ms / 101 KB | 1.09 ms / 100 KB | 0.87× / parity |
The architectural promise — 0 alloc/op on the data plane in steady state — is asserted by FastH1AllocDiagnosticTests on every test run, independent of BDN's amortization noise.
Releasing
Releases publish via .github/workflows/publish.yml on any pushed tag matching v*.
git tag v4.0.0
git push origin v4.0.0
The workflow strips the leading v, builds Release, runs the full test suite, packs CosmoHttpClient.<version>.nupkg + .snupkg, and pushes both to nuget.org via --skip-duplicate. The .snupkg carries SourceLink metadata so consumers can step into the library source from their debugger.
Configure once on GitHub: Settings → Secrets and variables → Actions → New repository secret named NUGET_API_KEY with a nuget.org API key scoped to CosmoHttpClient.
License
MIT — see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Cosmo.Transport (>= 1.0.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- ZstdSharp.Port (>= 0.8.4)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on CosmoHttpClient:
| Package | Downloads |
|---|---|
|
CosmoBlob.Client
CosmoHttpClient-backed client for CosmoKvD's /blobs/{key} surface. Drop into any .NET 10 app that wants an opaque blob store; pair with a thin IBlobStore adapter when used with CosmoMailServer. v1.0.0 swaps System.Net.Http.HttpClient for CosmoHttpClient's FastAutoClient (HTTP/1.1+2+3 auto-negotiation, span-based hot path). |
|
|
CosmoMail
Lightweight .NET SMTP and IMAP client library with MIME generation, templating, attachments, inline images, and STARTTLS support. |
GitHub repositories
This package is not used by any popular GitHub repositories.