Blocking HTTP/1.1 client for no_std + alloc. Cleartext HTTP; no async.
Design notes: philosophy.md.
MSRV: Rust 1.90 (rust-version in Cargo.toml; const APIs, ruzstd, and gungraun/bincode-next when building benches).
https:// needs [config::Config::assume_tls_socket] and a [BlockingSocket] that terminates TLS.
[OsBlockingSocket] is TCP only. Pairing it with assume_tls_socket returns
[Error::TlsNotConfigured].
fn main() -> Result<(), barehttp::Error> {
let response = barehttp::get("http://example.com").call()?;
println!("{} {}", response.status_code(), response.to_text()?);
Ok(())
}Primary names:
| Role | Primary | Compatibility alias |
|---|---|---|
| Client | [HttpClient] |
[Agent] (= HttpClient<OsBlockingSocket, OsDnsResolver>) |
| Request builder | [ClientRequestBuilder] |
[RequestBuilder] (same OS adapters) |
Cookie store (cookie-jar) |
[cookie_jar::CookieStore] |
[cookie_jar::CookieJar] |
| Status / body | [Response::status_code], [Response::body] |
deprecated [Response::status] / [Response::as_bytes] |
[Agent] / [RequestBuilder] / [cookie_jar::CookieJar] are documented ureq-like synonyms and are not deprecated. Prefer the primary names in new code. README and examples use primaries only.
[agent] builds a default-OS [HttpClient]. Free functions ([get], [post], …) return a builder; finish with [ClientRequestBuilder::call] or [ClientRequestBuilder::send]:
# fn main() -> Result<(), barehttp::Error> {
let response = barehttp::get("http://example.com").call()?;
let response = barehttp::post("http://example.com/api").send(b"{}")?;
# let _ = response;
# Ok(())
# }Hot types live at the crate root (HttpClient, Response, Error, Headers, …).
Optional / larger surfaces stay in modules: [config], [request_builder], and
(feature-gated) [cookie_jar] / [gzip]. The half-nesting is intentional.
- Buffered response bodies (no streaming
Readbody API). - Blocking I/O only (no async runtime).
- Public body accessors use
&[u8]/Vec<u8>/Stringonly (core/alloc).
- Custom [
BlockingSocket] / [DnsResolver] (connectgets the hostname for SNI) - Connection pooling (
Config::max_idle_per_hostdefault 3;0disables;max_idle_agedefault 15s) - Response body size limit (
Config::max_response_body_size, default ~10 MiB) - Optional Cargo features:
gzipexposesbarehttp::gzip(hand-rolled RFC 1951/1952);zstdis Accept-Encoding + decode only;cookie-jargates the cookie module - Runtime deps (always on, kept out of the public API):
bytes(internal body / wire buffers),phf(well-known header name map),compact_str(SSO header strings),hashbrown(header side-index / pool). Platform:libc/windows-sys. - Request builder:
.form/.bodythen.call(), or.send(bytes); per-request.timeout_read/.timeout_write/.timeout_connect
See CHANGELOG.md for release notes.
All examples use cleartext HTTP (http:// only):
cargo run --example basic # GET http://example.com
cargo run --example agent # shared client, headers + query
cargo run --example custom_adapters # logging DnsResolver + BlockingSocket over the OS stack
cargo run --example gzip --features gzip # http://httpbingo.org/gzip
cargo run --example cookies --features cookie-jar # httpbingo/postman-echo cookie endpoints
barehttp does not implement TLS. For https://:
- Use a [
BlockingSocket] whoseconnect/ read / write speak TLS (or wrap one that does).connectreceives the URI hostname for SNI. - Set
assume_tls_socketon [config::Config] so the client acceptshttps. Without that flag you get [Error::TlsNotConfigured].
use barehttp::config::Config;
use barehttp::HttpClient;
let config = Config::builder()
.assume_tls_socket(true)
.build();
// Pair with a TLS-capable BlockingSocket. OsBlockingSocket is cleartext
// and rejects this config.
let client = HttpClient::<MyTlsSocket, _>::with_adapters(my_dns, config);use barehttp::config::Config;
use barehttp::HttpClient;
use core::time::Duration;
# fn main() {
let config = Config::builder()
.timeout_read(Some(Duration::from_secs(30)))
.timeout_write(Some(Duration::from_secs(30)))
.max_redirects(5)
.user_agent("my-app/1.0")
.build();
let client = HttpClient::with_config(config);
# let _ = client;
# }use barehttp::config::Config;
use barehttp::{HttpClient, OsBlockingSocket};
let client: HttpClient<OsBlockingSocket, _> =
HttpClient::with_adapters(my_dns, Config::default());See examples/custom_adapters.rs for logging wrappers around [OsDnsResolver] / [OsBlockingSocket].
Use cargo-nextest:
cargo install cargo-nextest --locked
cargo nextest run --all-featuresCI runs nextest on push and pull requests. Details in CONTRIBUTING.md; fuzz targets in fuzz/README.md.
MIT OR Apache-2.0. Changes: CHANGELOG.md.