Repository navigation
feat: make HTTP/3 opt-in in the Rust crate - #595
Merged
Merged
Conversation
reqwest's `http3` feature makes every client set up a QUIC endpoint (a UDP socket, a driver task and a receive buffer of at least 2 MB), even when HTTP/3 is never used. HTTP/3 support is now behind the `http3` feature of the `impit` crate, so clients without it skip that setup, and the crate builds without `--cfg reqwest_unstable`. The Node and Python bindings enable the feature, so their `http3` option works as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0148RYR4BTGyCYHENSRZjC3S
metalwarrior665
force-pushed
the
feat/http3-opt-in
branch
from
October 23, 2026 20:21
43f8b4c to
09b456d
Compare
There was a problem hiding this comment.
🟢 Approval recommended
The feature gates, binding configuration, documentation, and CI changes are consistent, with no blocking issues identified.
No open issues 🎉
What changed in this PR
Makes HTTP/3 opt-in for the Rust crate, avoiding unnecessary QUIC setup for default clients while preserving HTTP/3 support in the Node.js and Python bindings.
Changes:
- Adds an
http3Cargo feature and gates HTTP/3-specific code and dependencies. - Updates examples and documentation to reflect the new opt-in requirement.
- Adds feature-enabled CI tests and includes HTTP/3 APIs in generated documentation.
| File | Description |
|---|---|
| README.md | Documents HTTP/3 opt-in and simplifies the example. |
| impit/src/lib.rs | Gates the HTTP/3 module and updates crate documentation. |
| impit/src/impit.rs | Gates HTTP/3 functionality and tests default-disabled behavior. |
| impit/README.md | Updates feature requirements and the example. |
| impit/examples/basic.rs | Removes HTTP/3 from the default example. |
| impit/Cargo.toml | Defines the feature and makes supporting dependencies optional. |
| impit-python/Cargo.toml | Enables HTTP/3 for Python bindings. |
| impit-node/Cargo.toml | Enables HTTP/3 for Node.js bindings. |
| .github/workflows/format.yaml | Adds tests with HTTP/3 enabled. |
| .github/workflows/docs.yaml | Builds documentation with HTTP/3 enabled. |
Review effort: Balanced
metalwarrior665
marked this pull request as ready for review
October 24, 2026 08:09
barjin
approved these changes
Oct 26, 2026
barjin
left a comment
Member
There was a problem hiding this comment.
lgtm, thank you @metalwarrior665 !
barjin
added a commit
that referenced
this pull request
Oct 26, 2026
My agent got freaked by the weird http3 + proxy behavior. This is an attempt to clean it up so it returns an error and doesn't silently change behavior. ## AI Summary HTTP/3 through a proxy isn't supported, and the docs say so. That was decided in #246 and #364, documented in #373, and reqwest tracks it upstream as seanmonstar/reqwest#2833. This PR doesn't try to add that support. It makes the unsupported combination fail safe instead of quietly sending traffic from the machine's own IP address. The change only matters when **HTTP/3 is enabled and a proxy is set**, whether through `with_proxy` / `proxyUrl` or through `HTTPS_PROXY` / `ALL_PROXY`. Everything else behaves as before, including the default, where HTTP/3 is off. ## What `master` does with HTTP/3 and a proxy | Request | On `master` | |---|---| | `http3_prior_knowledge` | Every request goes straight to the target over QUIC from the real IP. The proxy is never used. | | Not forced, and the host advertises h3 in its DNS HTTPS record | `H3Engine` looks the record up directly at `8.8.8.8`, which already exposes the hostname from the real IP. The request then goes out over QUIC from the real IP too. | | Not forced, and the host advertises h3 only through `Alt-Svc` | The first request goes through the proxy. impit then caches the host as h3-capable, and every later request to it leaks. A quick one-request test looks fine. | None of these cases logs anything or returns an error. I reproduced this on `master` with a local logging CONNECT proxy and `https://www.google.com/`. The forced request never reached the proxy. strace showed QUIC packets going directly to `142.251.153.119:443`, and the DNS lookups going to `8.8.8.8` / `8.8.4.4`. ## With this PR - When the client is built with a proxy, HTTP/3 is disabled and a warning is logged. All traffic goes through the proxy over TCP (HTTP/2 or HTTP/1.1), and no lookups go directly to `8.8.8.8`. - A request with `http3_prior_knowledge` fails with `Http3Disabled`, whose message now mentions the proxy. It no longer goes out directly. - A proxy that comes only from `HTTPS_PROXY` / `ALL_PROXY` is covered too. On `master` it leaks the same way, and the docs don't mention it. The PR also removes `.with_http3()` from the `ImpitBuilder` doc example, which combined it with a proxy. ## Not changed - HTTP/3 still can't go through a proxy. That's blocked in reqwest. - `NO_PROXY` isn't considered. If any proxy is set, HTTP/3 is off for all hosts. That's a deliberately conservative choice. - I disable HTTP/3 rather than fail at build time, so existing `http3: true` + proxy setups keep working over HTTP/2. That's easy to flip to an error if you'd prefer. - The unused QUIC endpoint that reqwest sets up whenever the `http3` feature is compiled in is handled separately in #595. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0148RYR4BTGyCYHENSRZjC3S Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Jindřich Bär <jindrichbar@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found out about this during profiling my Rust Actors based on crawlee-rs. The feature in cargo.toml is causing this in reqwest
AI Summary
reqwest's
http3feature makes every client that usesuse_preconfigured_tlsbuild an HTTP/3 connector, even when HTTP/3 is never used. That means a quinn endpoint per client: a UDP socket, a driver task, and a zeroed receive buffer of at least 2 MB.In a CPU profile of a Rust Instagram scraper that builds one impit client per proxy session, this endpoint setup took ~6% of all CPU, for a protocol it never uses.
HTTP/3 support is now behind a new
http3feature of theimpitcrate:hickory-*andtokioaren't needed.--cfg reqwest_unstable.impit-nodeandimpit-pythonenable the feature, so theirhttp3option behaves as before.with_http3()now needsfeatures = ["http3"]. It's removed from the README and doc examples.CI now also runs
cargo test -p impit --features http3, and the docs are built with the feature on.The proxy fix that used to be part of this PR is now #598. Whichever of the two lands second needs
#[cfg(feature = "http3")]on #598's test, which callswith_http3().🤖 Generated with Claude Code
https://claude.ai/code/session_0148RYR4BTGyCYHENSRZjC3S