curlite
A small blocking HTTP client on top of libcurl. For programs that call HTTP
services and want to stay small: no async runtime, one libcurl handle per
thread with connection reuse, request bodies held in memory once, and
multipart/form-data in both directions.
use Multipart;
let response = post
.header
.multipart
.send?;
println!;
for part in response.parts?
Bodies are body(mime, bytes), form(pairs) or multipart(..); everything
else (query, header, timeout, follow_redirects) is on the builder.
Responses are read into memory and expose status(), headers(), body(),
text(), form() and parts().
The params module adds a parameter model for services that exchange named
values and files, where the body format follows from the parameters: one body
parameter is sent raw, several text parameters as a form, anything with a file
as multipart. Responses parse back into the same model. This is the interface
of the CPEE process engine, which curlite was written for.
TLS and linking
TLS comes from libcurl. By default the system libcurl is linked dynamically,
with whatever TLS library it was built against. The static-curl,
static-ssl and rustls features are passed through to the
curl crate to build and link libcurl
statically instead.
Where the memory goes
curlite is the client developed for the bachelor's thesis Where the Memory
Goes: Design and Evaluation of a Synchronous Rust HTTP Client for Process
Instances on Edge Devices (TUM, 2026). The thesis replaced the
reqwest/tokio stack of a Rust process engine with this client and measured
both on an Orange Pi Zero 2W, for one process instance and for up to 50
concurrent instances, in six build configurations that differ in the TLS
library and the linking.
Short version: the async runtime was not where the memory went.
| reqwest(rustls, vendored) | curlite(rustls, vendored) | curlite(OpenSSL, system) | curlite(wolfSSL, tiny libcurl) | |
|---|---|---|---|---|
| Peak RSS, one instance | 9.88 MiB | 9.69 MiB | 19.40 MiB | 7.97 MiB |
| Private memory per instance, 50 instances | 1.70 MiB | 2.00 MiB | 5.99 MiB | 1.95 MiB |
| Shipped to the device | 10.67 MiB | 10.04 MiB | (system libraries) | smallest |
| 16 MiB download, max RSS of the process | 50.7 MiB | 20.0 MiB |
- With many instances, everything except written pages amortizes across processes. What remains is dominated by the TLS library: OpenSSL costs 3–4 MiB of private memory per process more than wolfSSL or rustls. The HTTP client accounts for about 0.3 MiB, the Rust linking mode for another 0.3 MiB.
- For a single instance, the smallest footprint comes from a tiny libcurl
with wolfSSL, 1.4–1.9 MiB RSS below the
reqwestbaseline. Only a curl-based client makes that configuration available. curliteholds a request body once and a response once.reqwestpeaked at about three times the payload for a 16 MiB download.- Per request, both clients cost the same. The curl/rustls build pays a
one-time 0.47 s for the initialization of
aws-lc's entropy source.
The full measurements, including the heap profiles, are in the thesis; the original client and the measurement setup are in the Bachelor-Thesis repository.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.