Skip to main content

Crate wrest

Crate wrest 

Source
Expand description
wrest

§wrest

Windows-native async HTTP client with a reqwest-compatible API.

CI codecov Crates.io Documentation

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.

reqwestwrest
HTTP stackhyper (user-space)WinHTTP (OS-provided)
TLSUser-space or SChannelSChannel – always the OS certificate store
ProxyEnv vars + limited OS proxy settingsEnv vars + All OS proxy settings
Async runtimeRequires tokioExecutor-agnostic – any runtime or block_on
Binary sizehyper, 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

FeatureDefaultDescription
charsetYesImproved 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
http2YesHTTP/2 support. WinHTTP negotiates via ALPN automatically; forwards to reqwest/http2
default-tlsYesTLS via the OS stack (SChannel). Always-on natively; forwards to reqwest/default-tls
native-tlsNoExplicit OS-native TLS selection. No-op natively (SChannel is always used); forwards to reqwest/native-tls
system-proxyYesAutomatic system proxy detection. WinHTTP uses WPAD/PAC natively; forwards to reqwest/system-proxy
jsonNoRequestBuilder::json() and Response::json() (adds serde, serde_json)
formNoRequestBuilder::form() (adds serde, form_urlencoded)
queryNoRequestBuilder::query() (adds serde, form_urlencoded)
gzipNoClientBuilder::gzip() no-op toggle (WinHTTP always decompresses gzip); forwards to reqwest/gzip
deflateNoClientBuilder::deflate() no-op toggle; forwards to reqwest/deflate
brotliNoClientBuilder::brotli() no-op toggle; forwards to reqwest/brotli
zstdNoClientBuilder::zstd() no-op toggle; forwards to reqwest/zstd
streamNoStream-based body support. Always available natively; forwards to reqwest/stream
tracingNoEmit diagnostics via the tracing crate – request lifecycle, proxy resolution, charset decoding, and more
noop-compatNoEnables ~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-compatNoClient::new() and impl Default for Client (these panic on failure – prefer Client::builder().build())
always-reqwestNoForces 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_certs is supported)
  • No SOCKS proxies – WinHTTP only supports HTTP CONNECT
  • RedirectsPolicy::limited() and Policy::none() only; Policy::custom() is not available
  • Decompression – gzip/deflate always-on; brotli/zstd not available natively
  • remote_addr() always returns None
  • 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§

pub use proxy::NoProxy;
pub use proxy::Proxy;

Modules§

header
Re-export the http::header module 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.
ClientBuilder
Builder for configuring and constructing a Client.
Error
The error type for wrest operations.
HeaderMap
A specialized multimap for header names and values.
Method
The Request Method (VERB)
Request
A fully-built HTTP request.
RequestBuilder
A builder for an HTTP request.
Response
An HTTP response.
Runtime
A lightweight executor handle.
StatusCode
An HTTP status code (status-code in RFC 9110 et al.).
Url
A parsed URL.
Version
Represents a version of the HTTP spec.

Enums§

ParseError
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 Runtime and run f to completion on it.
get
Shortcut method to quickly make a GET request.
runtime
Create a new Runtime (native backend – infallible).

Type Aliases§

Result
A Result alias where the Err case is Error.