Skip to content

feat(httpnet): opt-in HTTP/3 retrieval PoC#1178

Draft
lidel wants to merge 1 commit into
mainfrom
feat/httpnet-http3
Draft

feat(httpnet): opt-in HTTP/3 retrieval PoC#1178
lidel wants to merge 1 commit into
mainfrom
feat/httpnet-http3

Conversation

@lidel

@lidel lidel commented Jun 17, 2026

Copy link
Copy Markdown
Member

Important

We have no HTTP/3 providers, so parking this until we have anything to test against.

bitswap/network/httpnet fetches raw blocks over HTTP, but only over HTTP/1.1 and HTTP/2. This adds optional HTTP/3 (QUIC) so the client can use the faster transport when a provider supports it.

How it works

You can't switch a live TCP connection to HTTP/3. The client has to learn that a host speaks HTTP/3, then open a separate QUIC connection. This PR uses Alt-Svc for that, which needs no change to provider records or multiaddrs:

  • Providers keep announcing their usual /tcp/443/tls/http address.
  • The first request to a host goes over HTTP/2. If the response carries an Alt-Svc: h3 header, the client remembers it and sends later requests over HTTP/3.
  • The client stores this per peer, so it survives reconnects.
  • If a QUIC attempt fails (UDP blocked, no HTTP/3 server, or a slow handshake), the client falls back to HTTP/2 and backs off from HTTP/3 for that host.

A version label (h2/h3) on the status metric lets operators compare HTTP/2 and HTTP/3 traffic.

Other ways to find HTTP/3 (future work)

We use Alt-Svc first because httpnet already makes an HTTP/2 probe during connect, so reading the header costs nothing extra, and it needs no change to providers, DNS, or multiaddrs. It is not the only option, and later PRs can add others alongside it:

  • HTTPS/SVCB DNS records (alpn=h3): tells the client up front, before it connects, so it can skip the first HTTP/2 request. Works for DNS-named endpoints only, and needs HTTPS-record lookups.
  • Connection racing (Happy Eyeballs): dial QUIC and TCP at the same time and keep the winner. Needs no prior knowledge, but sends speculative UDP to every host.
  • Explicit multiaddr signal (such as /quic-v1/http): the provider announces HTTP-over-QUIC directly. Deterministic, but needs a multiaddr convention and providers that announce it.

HTTP/3 in the ecosystem today

Few IPFS HTTP providers speak HTTP/3 yet.

Tested on 22026-06-18: of the providers currently announced for a sample CIDs through delegated-ipfs.dev (bafy...4yeq), all serve HTTP/2 and none advertise HTTP/3:

Provider HTTP/2 Alt-Svc: h3 HTTP/3-only HTTPS DNS RR Note
gateway-v1.devpinata.cloud ✅ 403 none ❌ refused (37ms) alpn="h2" Cloudflare, but h3 disabled for the zone
indexer.storacha.network ✅ 200 none ❌ ~10s timeout none
a-fil-http.aur.lu ✅ 200 none ❌ ~10s timeout none
f010479.twinquasar.io ✅ 200 none ❌ ~10s timeout none
p-fil-http.aur.lu ✅ 200 none ❌ ~10s timeout none
trustless.filebase.io ✅ 200 none ❌ ~10s timeout none

The gateways behind Cloudflare already do, though: trustless-gateway.link, dweb.link, and ipfs.io all negotiate HTTP/3 and advertise it through Alt-Svc.

So the upgrade path already works against real infrastructure, even while dedicated content providers catch up.

Opt-in for now

HTTP/3 is off by default. Turn it on with the WithHTTP3() option. It needs outbound UDP, and operators may need to raise the UDP buffer limits (net.core.rmem_max and wmem_max on Linux). This is an early prototype. We expect it to pay off as more HTTP providers start speaking HTTP/3, and feedback on how it behaves against real providers is welcome.

TODO

  • Park this PR until we have HTTP/3 providers
  • Repeat HTTP/3 signaling test and update this PR description, then move to A/B test below
  • A/B test in rainbow staging: enable WithHTTP3() on a canary and compare block-retrieval latency and throughput against an HTTP/2-only control. The version label confirms how much traffic actually went over HTTP/3. Compare the aggregate exchange_httpnet_request_duration_seconds, since that latency histogram can't carry a version label with the current metrics interface.
  • Update the Grafana dashboard to chart HTTP/2 vs HTTP/3 use, from the version label on exchange_httpnet_status. Example queries:
# HTTP/3 share of all HTTP requests
sum(rate(exchange_httpnet_status{version="h3"}[5m]))
  / sum(rate(exchange_httpnet_status{version=~"h2|h3"}[5m]))

# request rate split by version
sum by (version) (rate(exchange_httpnet_status[5m]))

# error rate per version (5xx + unclassified)
sum by (version) (rate(exchange_httpnet_status{status=~"500|502|504|other"}[5m]))
  / sum by (version) (rate(exchange_httpnet_status[5m]))

Add WithHTTP3() to opportunistically upgrade HTTP block retrieval to
HTTP/3 for hosts that advertise it via Alt-Svc, persisting the verdict
in the peerstore and falling back to HTTP/2 (with a per-host back-off)
when QUIC is unavailable. Off by default.

The httpnet status metric gains a version label (h2/h3) so HTTP/2 and
HTTP/3 traffic can be compared.
@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.79487% with 33 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.62%. Comparing base (a88ea29) to head (6d0f2a0).

Files with missing lines Patch % Lines
bitswap/network/httpnet/http3.go 86.20% 8 Missing and 4 partials ⚠️
bitswap/network/httpnet/httpnet.go 7.69% 7 Missing and 5 partials ⚠️
bitswap/network/httpnet/metrics.go 46.66% 8 Missing ⚠️
bitswap/network/httpnet/msg_sender.go 50.00% 1 Missing ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1178      +/-   ##
==========================================
+ Coverage   63.58%   63.62%   +0.04%     
==========================================
  Files         268      269       +1     
  Lines       26964    27072     +108     
==========================================
+ Hits        17144    17225      +81     
- Misses       8102     8124      +22     
- Partials     1718     1723       +5     
Files with missing lines Coverage Δ
bitswap/network/httpnet/msg_sender.go 60.85% <50.00%> (ø)
bitswap/network/httpnet/metrics.go 82.08% <46.66%> (-10.64%) ⬇️
bitswap/network/httpnet/http3.go 86.20% <86.20%> (ø)
bitswap/network/httpnet/httpnet.go 61.16% <7.69%> (-1.69%) ⬇️

... and 8 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@lidel lidel added the status/blocked Unable to be worked further until needs are met label Jun 17, 2026
@lidel lidel changed the title feat(httpnet): opt-in HTTP/3 retrieval feat(httpnet): opt-in HTTP/3 retrieval PoC Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status/blocked Unable to be worked further until needs are met

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant