seanmonstar/reqwest
An easy and powerful Rust HTTP Client
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2d ago
- ✓38+ active contributors
- ✓Distributed ownership (top contributor 46% of recent commits)
Show all 6 evidence items →Show less
- ✓Apache-2.0 licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/seanmonstar/reqwest)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/seanmonstar/reqwest on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: seanmonstar/reqwest
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/seanmonstar/reqwest shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 2d ago
- 38+ active contributors
- Distributed ownership (top contributor 46% of recent commits)
- Apache-2.0 licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live seanmonstar/reqwest
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/seanmonstar/reqwest.
What it runs against: a local clone of seanmonstar/reqwest — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in seanmonstar/reqwest | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 32 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of seanmonstar/reqwest. If you don't
# have one yet, run these first:
#
# git clone https://github.com/seanmonstar/reqwest.git
# cd reqwest
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of seanmonstar/reqwest and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "seanmonstar/reqwest(\\.git)?\\b" \\
&& ok "origin remote is seanmonstar/reqwest" \\
|| miss "origin remote is not seanmonstar/reqwest (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/lib.rs" \\
&& ok "src/lib.rs" \\
|| miss "missing critical file: src/lib.rs"
test -f "src/async_impl/client.rs" \\
&& ok "src/async_impl/client.rs" \\
|| miss "missing critical file: src/async_impl/client.rs"
test -f "src/blocking/client.rs" \\
&& ok "src/blocking/client.rs" \\
|| miss "missing critical file: src/blocking/client.rs"
test -f "src/async_impl/request.rs" \\
&& ok "src/async_impl/request.rs" \\
|| miss "missing critical file: src/async_impl/request.rs"
test -f "src/error.rs" \\
&& ok "src/error.rs" \\
|| miss "missing critical file: src/error.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/seanmonstar/reqwest"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
reqwest is a high-level, ergonomic HTTP client library for Rust that provides both async and blocking APIs for making HTTP requests. It abstracts over hyper and adds batteries-included features like cookie stores, multipart forms, redirect policies, proxy support, and native TLS integration (rustls or system-native), making HTTP requests as simple as reqwest::get(url).await while remaining production-grade. Dual-implementation monolith: src/async_impl/ contains the async client with submodules for body, request, response, multipart, and H3 (HTTP/3) support; src/blocking/ mirrors this with blocking wrappers around async primitives. Core logic shared in src/config.rs, src/connect.rs, src/dns/, src/cookie.rs. Examples in examples/ demonstrate blocking, async, JSON, multipart, and WASM usage patterns.
👥Who it's for
Rust backend developers, CLI tool authors, and systems programmers who need to make HTTP requests without wrestling with low-level networking code. Users range from simple REST API consumers to complex applications requiring cookie persistence, multipart uploads, and custom TLS configurations.
🌱Maturity & risk
Highly mature and production-ready. The codebase shows 850KB+ of Rust (indicating substantial implementation), dual MIT/Apache-2.0 licensing, active CI/CD via GitHub Actions (.github/workflows/ci.yml), semantic versioning at 0.13.3, MSRV of 1.64.0, and extensive examples (blocking.rs, h3_simple.rs, wasm integration). Actively maintained by the Rust HTTP ecosystem.
Low to moderate risk. Single maintainer (seanmonstar) presents succession risk, but the library is battle-tested in production across the Rust ecosystem. Dependency surface is broad (hyper, tokio, rustls, h2, tower-http) creating some maintenance burden. Feature-gated compilation (17+ feature flags) adds complexity but reduces required dependencies. Breaking changes occur between major versions but follow semver discipline.
Active areas of work
Library is in maintenance mode for feature stability. Recent commits likely focus on dependency updates (via dependabot.yml), H3/HTTP/3 support maturation (evidenced by src/async_impl/h3_client/), and WASM compatibility (examples/wasm_github_fetch/). No breaking API churning visible; work is incremental.
🚀Get running
git clone https://github.com/seanmonstar/reqwest.git
cd reqwest
cargo build
cargo test
cargo run --example simple
Daily commands:
For async: cargo run --example simple (requires async runtime like Tokio externally). For blocking: cargo run --example blocking. For specific features: cargo run --example json_typed --features json. Tests: cargo test --all-features.
🗺️Map of the codebase
src/lib.rs— Main crate entry point; defines public API surfaces for async/blocking clients and re-exports core types.src/async_impl/client.rs— Core async HTTP Client implementation; handles request building, execution, pooling, and middleware logic.src/blocking/client.rs— Blocking Client wrapper around async implementation; essential for synchronous usage patterns.src/async_impl/request.rs— Request builder and execution; manages headers, body encoding, redirects, and pre-flight logic.src/error.rs— Unified error handling; all HTTP failures, timeouts, and network errors flow through this abstraction.src/connect.rs— Connection pool and TLS configuration; fundamental for network I/O, proxy routing, and cert validation.Cargo.toml— Feature matrix and dependency declarations; controls async runtime, TLS backend, compression, and platform support.
🛠️How to make changes
Add a new TLS feature or certificate validation option
- Define the new config field in ClientBuilder (e.g., cert_pinning, custom_roots) (
src/async_impl/client.rs) - Implement TLS setup logic in Connector::build_http or build_https (
src/connect.rs) - Add rustls/native-tls integration in src/tls.rs if it requires new certificate handling (
src/tls.rs) - Add integration test validating cert verification or pinning behavior (
tests/client.rs)
Add a new request body encoding format (e.g., Protocol Buffers, MessagePack)
- Create a new Body variant or builder method in Request (
src/async_impl/request.rs) - Implement serialization logic and set Content-Type header (
src/async_impl/body.rs) - Add optional feature gate in Cargo.toml for the encoding library (
Cargo.toml) - Test serialization round-trip with test server support in tests/support/server.rs (
tests/support/server.rs)
Add a new DNS resolver backend
- Implement Resolve trait in a new file (e.g., src/dns/custom_resolver.rs) (
src/dns/mod.rs) - Add resolver instantiation and selection logic in ClientBuilder (
src/async_impl/client.rs) - Add feature flag and conditional compilation in Cargo.toml (
Cargo.toml) - Test DNS lookup with both success and failure cases (
tests/client.rs)
Add a new middleware/connector layer (e.g., request logging, tracing)
- Implement tower::Layer and Service traits; wrap the inner connector (
src/connect.rs) - Expose middleware in ClientBuilder via add_layer method (
src/async_impl/client.rs) - Test middleware intercepts requests and responses correctly (
tests/connector_layers.rs)
🔧Why these technologies
- Tokio (async runtime) — Non-blocking I/O for high-concurrency workloads; reqwest layers async/await abstractions on top.
- Hyper (HTTP library) — Low-level HTTP/1.1 protocol handling; reqwest builds higher-level ergonomics and pooling on hyper.
- Rustls / native-tls — Modern TLS with optional system cert store support; rustls avoids OpenSSL dependency complexity.
- Tower (modular service layer) — Composable middleware/connector architecture; enables tracing, retry, and custom logic without forking.
- http-body (abstraction) — Unified Body type across streaming, buffered, and serialized payloads; decouples encoding from transport.
⚖️Trade-offs already made
-
Synchronous blocking API built on top of async
- Why: Satisfies both async/await users and blocking-only contexts (e.g., sync CLIs) without code duplication.
- Consequence: Blocking client requires tokio::block_on, which spawns/kills a runtime per request if no ambient runtime; slower for small requests but convenient.
-
Feature-gated TLS backends (rustls vs native-tls)
- Why: rustls is pure-Rust and auditable; native-tls leverages OS certs but adds platform-specific code.
- Consequence: Default is rustls; users must opt into native-tls and bundle/manage system roots, or download Mozilla certs at runtime.
-
Single global connection pool per Client, not per-domain
- Why: Simpler API and memory model; avoids fragmentation and per-domain state explosion.
- Consequence: Pool contention across domains; users must shard high-traffic services into multiple Clients.
-
Hyper-based HTTP/1.1 + optional HTTP/3 (h3 feature)
- Why: Hyper is mature and widely-used; h3 added later for cutting-edge perf (QUIC multiplexing).
- Consequence: HTTP/2 is not supported; must choose between HTTP/1.1 stability or HTTP/3 performance/latency.
-
WASM client uses browser Fetch API, not Hyper
- Why: Browsers do not expose raw TCP/TLS; Fetch is the only available primitive.
- Consequence: WASM client cannot customize TLS, proxy, or low-level socket behavior; no connection pooling in browser context.
🪤Traps & gotchas
Feature interactions: Enabling blocking requires tokio/sync and futures-channel; some features are mutually exclusive (e.g., default-tls vs native-tls). WASM context: Examples/wasm_github_fetch is a separate workspace; requires wasm-bindgen and Node.js toolchain, not standard Cargo. TLS defaults: Without explicit feature, uses rustls with system-native verification (rustls-platform-verifier), not OpenSSL; override via native-tls or native-tls-vendored. H3 immaturity: HTTP/3 client in h3_client/ is newer; DNS and connection pooling differ from HTTP/2 paths. Blocking timeout: Blocking client doesn't inherit async timeouts automatically; must set via ClientBuilder::timeout(). Cookie store not default: Cookies require cookies feature; off by default.
🏗️Architecture
💡Concepts to learn
- Connection pooling — reqwest reuses TCP connections across multiple requests via hyper's built-in pool; understanding TTL, idle timeouts, and max pool size directly impacts performance
- TLS provider abstraction — reqwest abstracts TLS behind feature flags (rustls, native-tls, native-tls-vendored) with different security guarantees and platform support; affects binary size, OS dependencies, and certificate validation behavior
- Blocking via futures-channel — The blocking client wraps async APIs using
futures_util::block_onwith a background Tokio runtime; synchronization via channels introduces latency and is unsuitable for hot loops - HTTP/3 and QUIC — reqwest's
h3_clientmodule implements HTTP/3 over QUIC, a modern transport offering connection migration and reduced latency; differs fundamentally from TCP-based HTTP/1.1 and HTTP/2 - Cookie store and session persistence — The
cookiesfeature uses cookie_store crate to track Set-Cookie headers and automatically inject Cookie headers; critical for stateful API interactions like login flows - Multipart form encoding — reqwest's
multipartfeature generates RFC 2388 compliant multipart/form-data bodies; essential for file uploads but adds serialization complexity and streaming requirements - Redirect policy and location following — reqwest implements configurable redirect policies (follow, deny, limit) to handle 301/302/307 responses; default follows up to 20 redirects but can leak auth headers if misconfigured
🔗Related repos
hyperium/hyper— Low-level HTTP protocol engine that reqwest wraps; understanding hyper's connection pooling and codec layer is essentialrustls/rustls— Default TLS provider (via rustls-platform-verifier); reqwest's TLS security posture depends on rustls internalstokio-rs/tokio— Async runtime dependency; reqwest's async behavior is bound to Tokio's task scheduling and I/O integrationhttp-rs/http— Shared HTTP primitives (Request, Response, HeaderMap) used throughout reqwest's public APIseanmonstar/http-body— Body trait abstraction; reqwest implements HttpBody for request bodies and consumes it in responses
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive HTTP/3 (h3) integration tests
The repo has h3_client implementation in src/async_impl/h3_client/ and an example (examples/h3_simple.rs), but tests/badssl.rs and tests/blocking.rs don't appear to include h3-specific test coverage. Given that h3 is a major feature alongside http2, adding dedicated tests would ensure compatibility across HTTP versions and catch regressions.
- [ ] Create tests/h3_integration.rs with test cases for basic h3 requests, redirects, and error handling
- [ ] Add h3-specific feature-gated tests in tests/badssl.rs to test h3 against real endpoints
- [ ] Document h3 test requirements (e.g., h3 server setup or test environment expectations) in a comment block
- [ ] Verify tests run in CI by checking if h3 feature is enabled in .github/workflows/ci.yml
Add WASM-specific integration tests with proper CI setup
The repo supports WASM (examples/wasm_github_fetch exists) and has src/wasm/ implementations, but there's no visible wasm-target test suite in tests/. The WASM example has its own package setup, but no automated tests in CI verify the core reqwest library works correctly when compiled to wasm32-unknown-unknown.
- [ ] Create tests/wasm.rs with feature-gated tests (#[cfg(target_arch = "wasm32")])
- [ ] Add a wasm32-unknown-unknown test target to .github/workflows/ci.yml with wasm-pack or appropriate testing framework
- [ ] Test key features: basic requests, JSON serialization, error handling in WASM context
- [ ] Document any WASM-specific limitations or setup in CHANGELOG.md or README.md
Add DNS resolver tests for hickory and gai implementations
The repo has two DNS implementations (src/dns/hickory.rs and src/dns/gai.rs) but no dedicated DNS resolver tests. This is a critical path for reliability, and testing both implementations separately would catch subtle bugs in DNS resolution behavior and ensure feature-flag correctness.
- [ ] Create tests/dns.rs with test cases for both hickory and gai resolvers (feature-gated)
- [ ] Test scenarios: successful resolution, NXDOMAIN errors, NOANSWER handling, IPv4/IPv6 preference
- [ ] Add a test that verifies the correct resolver is used based on feature flags
- [ ] Consider adding mock DNS server helpers if needed for reproducible test environment
🌿Good first issues
- Add integration tests for
src/async_impl/h3_client/dns.rsDNS resolution with HTTP/3—currently no explicit test file exists for H3 DNS fallback behavior - Document multipart streaming limits and backpressure behavior in
src/async_impl/multipart.rsdocstrings—feature is implemented but user-facing docs are sparse - Implement missing examples for cookie store persistence (e.g.,
examples/cookie_persistence.rs) demonstrating CookieStore serialization across requests—cookie feature exists but no runnable example
⭐Top contributors
Click to expand
Top contributors
- @seanmonstar — 46 commits
- @0x676e67 — 10 commits
- @dependabot[bot] — 3 commits
- @ducaale — 3 commits
- @passcod — 2 commits
📝Recent commits
Click to expand
Recent commits
4b813a8— feat: add tls_sslkeylogfile builder method (#2923) (passcod)c86f860— fix: do not lose the url in error when decoding json (#3026) (Dushistov)5b5ac17— fix(tls): improve rustls-no-provider panic message and add module docs (#3021) (smythg4)a9a88c4— v0.13.3 (seanmonstar)f3f6d9d— docs(retry): include ReqRep in docsrs (#3020) (seanmonstar)5f9c231— fix rustls CRL PEM parsing (#3013) (Threated)11d835d— use wasm-bindgen ecosystem only for wasm32-unknown-* target (#3000) (Ludea)1f72916— Upgrade rustls-platform-verifier (#3010) (jplatte)5d5bf35— [HTTP/3] Optimize IPv6 fallback and enforce HTTPS scheme #2911 (#3006) (lyuzichong)93dc1b2— docs: more accurate about default HTTP2 window sizes (#3007) (seanmonstar)
🔒Security observations
The reqwest codebase demonstrates good security practices overall. It is a well-maintained HTTP client library with proper licensing, CI/CD pipelines, and multiple TLS implementation options. The primary concern is an incomplete Cargo.toml feature definition that requires immediate attention. Secondary concerns include ensuring cryptographic test materials are properly managed and maintaining vigilance with transitive dependencies, particularly for the JavaScript/WASM components. No evidence of hardcoded secrets, injection vulnerabilities, or critical misconfigurations was identified based on the file structure and metadata provided.
- Medium · Incomplete Cargo.toml Feature Definition —
Cargo.toml (features section). The Cargo.toml file appears to have a truncated feature definition for 'multipart'. The line 'multipart = ["dep:mime_gu' is incomplete and cuts off mid-string. This could indicate parsing issues or incomplete configuration that might affect dependency resolution and feature flags. Fix: Complete the truncated feature definition. It should likely be 'multipart = ["dep:mime_guess", ...]'. Ensure all feature flags are properly defined and tested. - Low · Test Support Files Include Cryptographic Material —
tests/support/crl.pem. The test support directory contains 'crl.pem' (Certificate Revocation List) file which is cryptographic material. While this is expected for tests, it should be verified that no private keys or sensitive credentials are accidentally committed. Fix: Ensure no private keys, certificates with private components, or other sensitive cryptographic material are in the repository. Add patterns to .gitignore to prevent accidental commits of sensitive files (*.key, *.pem for private keys, etc.). - Low · WASM Example Package Dependencies —
examples/wasm_github_fetch/package.json. The WASM example includes package.json with npm dependencies. npm/JavaScript dependencies may contain vulnerabilities and require regular auditing. The osv-scanner.toml file suggests awareness of this, but continuous monitoring is needed. Fix: Regularly run 'npm audit' and 'cargo audit' to check for known vulnerabilities. Keep dependencies up to date. Consider using automated dependency scanning in CI/CD pipeline. - Low · TLS Implementation Flexibility —
Cargo.toml (rustls, native-tls features and src/tls.rs). The crate supports multiple TLS providers (rustls, native-tls) with various feature combinations. While this provides flexibility, it increases the attack surface and requires careful configuration by users. Misconfiguration could lead to insecure TLS setups. Fix: Document TLS configuration best practices clearly. Ensure default features use secure TLS settings. Add warnings in documentation about non-default TLS configurations. Consider security audits of TLS integrations.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.