A minimal wrk-like HTTP load tester in Rust. Fires HTTP requests at a target for a fixed duration or request count, and reports RPS, full latency percentiles (via HDR histograms), status distribution, and error breakdown.
wrkis excellent but C and a pain to compile on a fresh box.heyis Go and doesn't give you p99 by default.ohais close to what I wanted but ships a TUI I don't need from a headless bench.
http-bench is ~900 lines of Rust across five source files, five dependencies (clap, tokio, reqwest with rustls, hdrhistogram, humantime), and ships as an 11.6 MB multi-stage Alpine container.
# Hit a local server for 10 seconds with 10 workers (all defaults).
http-bench http://localhost:8080/
# Fixed request count.
http-bench http://localhost:8080/ --requests 10000 --concurrency 50
# POST with a body and header.
http-bench http://localhost:8080/items \
--method post \
--header "Content-Type: application/json" \
--body '{"name":"x"}' \
--duration 30s
# Machine-readable output for CI dashboards.
http-bench http://localhost:8080/ --duration 5s --format jsondocker build -t http-bench .
# Private target, no flag needed.
docker run --rm --network host http-bench http://127.0.0.1:8080/ --duration 5s
# Public target — requires --allow-internet.
docker run --rm http-bench https://example.com \
--allow-internet --duration 2s --concurrency 2http-bench report
=================
Duration: 2.01 s
Concurrency: 2
Total: 393 requests
RPS: 195.73
Per-worker: min 97.62 / mean 97.89 / max 98.17 RPS
Status distribution
-------------------
2xx: 393
3xx: 0
4xx: 0
5xx: 0
Errors
------
connect: 0
timeout: 0
other: 0
Latency (successful requests)
-----------------------------
min: 8.69 ms
mean: 10.20 ms
p50: 9.93 ms
p90: 10.70 ms
p99: 18.29 ms
max: 48.09 ms
By default, http-bench refuses to hit a target that isn't obviously yours. Private, loopback, link-local, and *.local addresses are allowed without a flag; anything else requires --allow-internet. You can turn this off with one flag, but you can't turn it off by accident.
This is parallel to port-scanner's --allow-remote. Load tests against someone else's server can, depending on terms of service and jurisdiction, range from impolite to prosecutable; putting a one-word flag in front of that boundary feels like the right trade-off.
| Code | Meaning |
|---|---|
| 0 | Bench completed. HTTP 4xx and 5xx are not errors — they're recorded in the report. |
| 1 | Zero requests succeeded; every attempt failed at the connect layer. |
| 2 | Bad arguments, invalid URL, or safety gate refused the target. |
cargo build --release
cargo testTests include unit tests for the histogram, report formatter, CLI validator, and safety classifier, plus integration tests that spawn a hand-rolled tokio HTTP server on a random loopback port and run the binary against it.
MIT. See LICENSE.
