Expand description
![]() |
§wrestWindows-native async HTTP client with a reqwest-compatible API. |
wrest is a drop-in replacement for the async API of
reqwest that uses the operating system’s built-in
HTTP stack
(WinHTTP)
instead of bundling its own and does not depend on the
tokio executor. TLS, proxy resolution,
authentication, content-encoding, and more are all handled by Windows.
§Why
reqwest is a battle-tested cross-platform HTTP client
built on top of tokio. wrest takes a different approach:
instead of linking a TLS library and driving sockets from user space, it delegates the
entire HTTP stack to the OS, acting as a thin ergonomic API surface on top
of OS primitives.
| reqwest | wrest | |
|---|---|---|
| HTTP stack | hyper (user-space) | WinHTTP (OS-provided) |
| TLS | User-space or SChannel | SChannel – always the OS certificate store |
| Proxy | Env vars + limited OS proxy settings | Env vars + All OS proxy settings |
| Async runtime | Requires tokio | Executor-agnostic – any runtime or block_on |
| Binary size | hyper, h2, … | Thin FFI layer over a system DLL |
If your application targets Windows and you want the platform’s native
networking – the same stack used by Windows itself – wrest lets you do
that without giving up the ergonomic reqwest API your code already uses.
§Quick start
// The API is intentionally identical to reqwest.
use wrest::Client;
let client = Client::builder()
.timeout(std::time::Duration::from_secs(30))
.build()?;
let body = client
.get("https://httpbin.org/get")
.header("x-custom", "value")
.send()
.await?
.text()
.await?;
println!("{body}");§Executor-agnostic
wrest returns standard Futures with no hidden dependency on
tokio,
smol, or any other runtime. Use it with
whichever executor you prefer:
// tokio
tokio::runtime::Runtime::new()?.block_on(do_request());
// futures-executor
futures_executor::block_on(do_request());
// smol
smol::block_on(do_request());wrest also ships a small Runtime abstraction that picks the minimal
executor for the native backend and the reqwest passthrough. On the
native backend it delegates to futures_executor::block_on; with reqwest
pass-through it wraps a single-threaded tokio::Runtime.
// One-shot -- creates a runtime, runs the future, returns the result.
let body = wrest::block_on(async {
wrest::Client::builder().build()?.get("https://httpbin.org/get").send().await
})?;
// Reusable runtime -- amortises creation cost across multiple calls.
let rt = wrest::runtime()?;
let a = rt.block_on(request_a());
let b = rt.block_on(request_b());§Cross-platform & A/B testing
On non-Windows platforms (Linux, macOS, etc.) wrest is a thin
passthrough to reqwest – every call
forwards directly, so the same code compiles everywhere.
To force the reqwest path on Windows – for example, to A/B test
against the native WinHTTP path – enable the always-reqwest
feature:
wrest = { version = "0.5", features = ["always-reqwest"] }Feature flags like json, gzip, stream, etc. forward to the
corresponding reqwest features automatically. Use
default-features = false to strip wrest and reqwest to their bare
minimum, then re-add only what you need.
§Features
| Feature | Default | Description |
|---|---|---|
charset | Yes | Improved text decoding. Native path has all 39 WHATWG encodings built-in (three rare ones – ISO-8859-10 (Latin-6 / Nordic), ISO-8859-14 (Latin-8 / Celtic), EUC-JP (Extended Unix Code for Japanese) – need Windows 10 1903+); forwards to reqwest/charset on the reqwest path |
http2 | Yes | HTTP/2 support. WinHTTP negotiates via ALPN automatically; forwards to reqwest/http2 |
default-tls | Yes | TLS via the OS stack (SChannel). Always-on natively; forwards to reqwest/default-tls |
native-tls | No | Explicit OS-native TLS selection. No-op natively (SChannel is always used); forwards to reqwest/native-tls |
system-proxy | Yes | Automatic system proxy detection. WinHTTP uses WPAD/PAC natively; forwards to reqwest/system-proxy |
json | No | RequestBuilder::json() and Response::json() (adds serde, serde_json) |
form | No | RequestBuilder::form() (adds serde, form_urlencoded) |
query | No | RequestBuilder::query() (adds serde, form_urlencoded) |
gzip | No | ClientBuilder::gzip() no-op toggle (WinHTTP always decompresses gzip); forwards to reqwest/gzip |
deflate | No | ClientBuilder::deflate() no-op toggle; forwards to reqwest/deflate |
brotli | No | ClientBuilder::brotli() no-op toggle; forwards to reqwest/brotli |
zstd | No | ClientBuilder::zstd() no-op toggle; forwards to reqwest/zstd |
stream | No | Stream-based body support. Always available natively; forwards to reqwest/stream |
tracing | No | Emit diagnostics via the tracing crate – request lifecycle, proxy resolution, charset decoding, and more |
noop-compat | No | Enables ~31 no-op reqwest stubs (connection pool, TCP options, HTTP/2 tuning, TLS backend selection, etc.) so reqwest-targeting code compiles without changes. Compression toggles require both this and the respective feature |
panicking-compat | No | Client::new() and impl Default for Client (these panic on failure – prefer Client::builder().build()) |
always-reqwest | No | Forces the reqwest path even on Windows – see Cross-platform & A/B testing |
Bold feature names are unique to wrest (not present in reqwest).
§Limitations
wrest covers the core reqwest API surface (~75 methods). A few reqwest features are not available because WinHTTP handles them internally or they haven’t been added yet:
- No blocking API – async only
- No cookies, multipart, or WebSocket – not yet implemented
- No custom DNS or TLS configuration – WinHTTP uses SChannel and
the OS certificate store (
tls_danger_accept_invalid_certsis supported) - No SOCKS proxies – WinHTTP only supports HTTP CONNECT
- Redirects –
Policy::limited()andPolicy::none()only;Policy::custom()is not available - Decompression – gzip/deflate always-on; brotli/zstd not available natively
remote_addr()always returnsNone- Charset decoding – three rare encodings (ISO-8859-10 (Latin-6 /
Nordic), ISO-8859-14 (Latin-8 / Celtic), EUC-JP (Extended Unix Code
for Japanese)) require Windows 10 1903+ (
icu.dll)
~31 additional reqwest builder stubs (pool tuning, TCP options, HTTP/2
knobs, etc.) are available as silent no-ops under the noop-compat
feature.
For a full API-by-API comparison, see docs/reqwest-parity.md.
§Minimum supported Rust version
Rust 1.90.
§License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Re-exports§
Modules§
- header
- Re-export the
http::headermodule for header name constants. HTTP header types - proxy
- Proxy configuration types. Proxy configuration from environment variables.
- redirect
- Redirect policy configuration. Redirect policy.
- retry
- Retry requests.
Structs§
- Body
- A request body.
- Client
- An async HTTP client backed by WinHTTP.
- Client
Builder - Builder for configuring and constructing a
Client. - Error
- The error type for wrest operations.
- Header
Map - A specialized multimap for header names and values.
- Method
- The Request Method (VERB)
- Request
- A fully-built HTTP request.
- Request
Builder - A builder for an HTTP request.
- Response
- An HTTP response.
- Runtime
- A lightweight executor handle.
- Status
Code - An HTTP status code (
status-codein RFC 9110 et al.). - Url
- A parsed URL.
- Version
- Represents a version of the HTTP spec.
Enums§
- Parse
Error - An error type for URL parsing failures.
Traits§
- IntoUrl
- A trait for types that can be converted to a validated URL.
Functions§
- block_
on - Create a
Runtimeand runfto completion on it. - get
- Shortcut method to quickly make a
GETrequest. - runtime
- Create a new
Runtime(native backend – infallible).
