HTTP/2, HTTP/3 and connection behaviour

curl · Expert · 12 min

Protocol-level differences explain performance results, proxy problems and bugs that only appear on one HTTP version.

For https:// URLs, a curl built with nghttp2 offers HTTP/2 during the TLS handshake via ALPN, and uses it if the server agrees; otherwise it falls back to HTTP/1.1. -w '%{http_version}' reports what was actually used.

Forcing versions for testing:

  • --http1.1 disables HTTP/2 negotiation, useful when a proxy or server misbehaves with h2.
  • --http2-prior-knowledge speaks HTTP/2 over plain http:// without upgrade (h2c), as used by some gRPC backends.
  • --http3 tries HTTP/3 over QUIC (UDP) and falls back to older versions if it fails; --http3-only does not fall back. Both require a curl built with HTTP/3 support (check the HTTP3 feature in curl -V).

Browsers discover HTTP/3 through the Alt-Svc response header. curl can do the same: --alt-svc cache.txt stores those headers and uses HTTP/3 on later requests.

Within one curl invocation, connections are kept and reused for later URLs to the same host; with HTTP/2 multiple parallel transfers (-Z) are multiplexed as streams over one connection. %{num_connects} shows how many new connections were made.

Head-of-line blocking is the reason HTTP/3 exists: in HTTP/2 a lost TCP packet stalls every stream, while QUIC streams are independent. Compare versions on a lossy link with -w '%{time_total}' to see it.

Example

curl -sS -o /dev/null -w '%{http_version}\n' https://www.google.com     # 2
curl -sS --http1.1 -o /dev/null -w '%{http_version}\n' https://www.google.com   # 1.1
curl -V | grep -o 'HTTP3'                         # is HTTP/3 compiled in?
curl -sS --http3 -o /dev/null -w '%{http_version}\n' https://cloudflare.com    # 3
curl -sS --http2-prior-knowledge http://localhost:50051/   # h2c, no TLS
curl -sSI https://cloudflare.com | grep -i alt-svc
# alt-svc: h3=":443"; ma=86400
curl -sS -o /dev/null -o /dev/null -w '%{num_connects} ' \
     https://example.com/ https://example.com/about   # 1 0  (second reused)

Remember

  • HTTPS negotiates HTTP/2 via ALPN; -w %{http_version} shows the result
  • --http1.1, --http2-prior-knowledge, --http3, --http3-only force versions
  • Connections are reused within one invocation; Alt-Svc advertises HTTP/3

Watch out for

  • Assuming --http3 works everywhere; many distro builds lack HTTP/3 support.

Check yourself

  1. How does curl discover that an HTTPS server supports HTTP/2?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: curl.se/docs/http3.html