Skip to main content
Version: 1.0

HTTP Client

rustdocs

trillium-client is a full HTTP client that mirrors the server-side Conn design. It supports HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3, HTTPS, connection pooling, and WebSocket upgrades (including over h2).

The client is runtime-agnostic and uses the same connector pattern as the server adapters.

Basic usage

use trillium_client::Client;
use trillium_smol::ClientConfig;

async fn fetch() {
let client = Client::new(ClientConfig::default());

let body = client
.get("http://example.com/")
.await
.unwrap()
.success()
.unwrap()
.response_body()
.await
.unwrap();

println!("{body}");
}

ClientConfig comes from your chosen runtime crate. The success() method returns an error if the status is not 2xx.

HTTPS

Wrap ClientConfig with a TLS config:

use trillium_client::Client;
use trillium_rustls::RustlsConfig;
use trillium_smol::ClientConfig;

let client = Client::new(RustlsConfig::<ClientConfig>::default());
let conn = client.get("https://example.com/").await.unwrap();

trillium-native-tls and trillium-openssl can be used instead of trillium-rustls with the same pattern.

HTTP/2

Over https:// with a trillium-rustls connector, HTTP/2 is automatically negotiated when the server selects h2 in ALPN. No code changes are required — every example above already speaks h2 against an h2-capable server.

To opt out, drop h2 from the advertised ALPN list:

use trillium_client::Client;
use trillium_rustls::RustlsConfig;
use trillium_smol::ClientConfig;

let client = Client::new(RustlsConfig::<ClientConfig>::default().without_http2());

For TLS connectors that don't surface ALPN selection (trillium-native-tls at time of writing) or for cleartext h2c, set the per-request prior-knowledge hint:

use trillium_client::Version;

let conn = client
.get("http://localhost:8080/")
.with_http_version(Version::Http2)
.await
.unwrap();

Version::Http2 skips ALPN inspection and starts the h2 driver immediately — there is no fallback if the server doesn't speak h2. See the trillium_client rustdocs for the full prior-knowledge table.

HTTP/2 connections are pooled and multiplex concurrent requests over a single TCP+TLS connection. Client::with_h2_idle_timeout, with_h2_idle_ping_threshold, and with_h2_idle_ping_timeout tune idle and health-check behavior.

HTTP/3

When build using Client::new_with_quic, the client upgrades to HTTP/3 automatically when a server advertises support via Alt-Svc. The first request to a host uses HTTP/1.1; if the response includes Alt-Svc: h3=..., subsequent requests to that host use HTTP/3.

use trillium_client::Client;
use trillium_quinn::ClientQuicConfig;
use trillium_rustls::RustlsConfig;
use trillium_tokio::ClientConfig;

let client = Client::new_with_quic(
RustlsConfig::<ClientConfig>::default(),
ClientQuicConfig::with_webpki_roots(),
);

// Request 1: HTTP/1.1 (no Alt-Svc cached)
// Request 2+: HTTP/3 if the server advertised it
for _ in 0..3 {
let conn = client.get("https://cloudflare.com/").await.unwrap();
println!("{:?}", conn.http_version());
}

Making requests

The client has methods for each HTTP verb. Each returns a Conn that you can configure before sending:

let conn = client
.post("https://api.example.com/items")
.with_request_header("content-type", "application/json")
.with_body(r#"{"name":"widget"}"#)
.await
.unwrap();

println!("status: {}", conn.status().unwrap());

Connection pooling

Connections are pooled and reused automatically across requests to the same host. HTTP/1.1, HTTP/2, and HTTP/3 each have their own pool; HTTP/2 multiplexes concurrent requests over a single connection.

WebSocket client

With the websockets feature, the client can upgrade a connection to WebSocket:

let ws_conn = client
.get("wss://example.com/ws")
.await
.unwrap()
.into_websocket()
.await
.unwrap();

The resulting WebSocketConn exposes the same send/receive interface as the server-side WebSocket handler.