Skip to content

http3 feature: libcurl on ngtcp2 and nghttp3 with OpenSSL QUIC - #688

Open
CarloTUM wants to merge 3 commits into
sagebind:mainfrom
CarloTUM:http3
Open

CarloTUM wants to merge 3 commits into
sagebind:mainfrom
CarloTUM:http3

Conversation

@CarloTUM

@CarloTUM CarloTUM commented Oct 10, 2026 •

Copy link
Copy Markdown

Adds an http3 feature that builds libcurl with HTTP/3, so a static Rust binary gets QUIC with one line in Cargo.toml:

curl = { version = "0.4", features = ["http3", "static-ssl"] }
easy.http_version(HttpVersion::V3Only)?;   // HTTP/3 or fail, no fallback

How

libcurl's ngtcp2 backend on OpenSSL's own QUIC API (OPENSSL_QUIC_API2, OpenSSL 3.5+). ngtcp2 v1.25.0 and nghttp3 v1.18.0 come in as submodules under curl-sys/ and are compiled by the build script with cc, the same way libcurl itself is: version.h is generated from their cmake templates, the few HAVE_* defines their configure would find are set per platform. No cmake, no bindgen, no new dependency crates; the existing nghttp3-sys/ngtcp2-sys crates on crates.io are hard-wired to aws-lc and need bindgen, which did not fit this crate.

http3 implies ssl and static-curl. With rustls or on Windows the feature only prints a warning and does nothing, so --all-features (and the docs job) keeps building. An OpenSSL older than 3.5 fails the build with a message pointing at static-ssl; Ubuntu 24.04's 3.0 is such a case, which is why the CI job and the example use static-ssl.

Also

  • HttpVersion::V3Only / CURL_HTTP_VERSION_3ONLY: fail instead of falling back, so a test actually proves HTTP/3.
  • examples/http3.rs fetches https://cloudflare-quic.com/ with V3Only.
  • A CI job builds --features http3,static-ssl and runs the example.
  • The weekly update workflow now covers ngtcp2 and nghttp3 as a matrix next to curl, one PR per library, so the new submodules get the same treatment as curl itself.

Tested

Linux x86_64, OpenSSL 3.6.3 from openssl-src:

  • cargo run --example http3 --features http3,static-ssl prints the page and 200 over HTTP/3.
  • cargo test --features http3,static-ssl passes.
  • cargo check --no-default-features --features http3,rustls builds with the warning.

Not covered: macOS and the BSDs (the endian defines are set for them but untested), and HTTP/3 through a proxy. sendmmsg is left off because libcurl's mmsg path needs _GNU_SOURCE, which this build does not set; sendmsg is the portable path.

Related: #687 (rustls-ring, CA probing) is independent of this.

HTTP/3 through libcurl's ngtcp2 backend on OpenSSL's QUIC API, which
needs OpenSSL 3.5 or newer. ngtcp2 (v1.25.0) and nghttp3 (v1.18.0) come
in as submodules and are compiled with cc like libcurl itself: their
version.h is generated from the cmake template, the handful of HAVE_*
defines their cmake configure would find is set per platform. No cmake,
no bindgen, no new crates.

The feature implies ssl and static-curl. With rustls or on Windows it
only warns and does nothing, so --all-features keeps building. An
OpenSSL older than 3.5 stops the build with a message that points at
static-ssl.

sendmmsg stays off: libcurl's mmsg path needs _GNU_SOURCE for struct
mmsghdr and IOV_MAX, which this build does not define.

Also adds CURL_HTTP_VERSION_3ONLY.
HttpVersion::V3Only (CURL_HTTP_VERSION_3ONLY) fails instead of falling
back to HTTP/2 or 1.1, which is what makes an HTTP/3 test meaningful.
examples/http3.rs fetches cloudflare-quic.com that way; a CI job builds
the feature with static-ssl and runs the example.
The weekly job that bumps the curl submodule to the latest release now
runs as a matrix over curl, ngtcp2 and nghttp3, one pull request each,
so the http3 feature does not add a library that nobody updates.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant