Skip to content

Alt-Svc: advertised HTTP/3 port is parsed and stored but never used #24

Description

@passcod

🤖 AltSvcCache::should_use_h3 returns the advertised HTTP/3 port, but AltSvcMiddleware::handle only uses it as a boolean:

let trying_h3 = self.cache.should_use_h3(&url).is_some();

The port is parsed from the Alt-Svc header, stored in AltSvcEntry, threaded through record_alt_svc / add_hint / confirm_h3 — and then never used to route anything. The request URL is not rewritten, so faith only ever attempts HTTP/3 on the origin's own port.

Consequences:

  • A server advertising alt-svc: h3=":8443" on an origin served at :443 gets an h3 attempt on :443. If nothing listens on UDP :443, every attempt is futile — best case it fails fast and falls back, but it's wasted work on every request until the failure is cached.
  • Conversely, an origin at :8443 advertising h3=":443" gets h3 attempted on :8443, silently ignoring the advertisement.
  • This matters for split TCP/UDP frontends. The consumer who reported test: cover the HTTP/3 fallback that cancellation skips #23 also runs Envoy Gateway in Kubernetes, where the advertised h3 port need not match the origin port.

Note this is load-bearing by accident in some setups today: because the port is ignored, a server whose advertised port is unreachable from the client still gets h3 attempted on the working origin port.

Upstream constraint: reqwest keys its HTTP/3 pool on (scheme, authority) derived from the request URI (h3_client/pool.rs), and H3Connector::connect takes the port from that URI. Honouring a different advertised port means connecting to one endpoint while keeping the original origin's Host and TLS SNI — which is exactly what Alt-Svc means, but reqwest has no API for it. So this likely needs upstream work rather than a fix confined to alt_svc.rs.

Minimum viable improvement without upstream changes: only attempt h3 when the advertised port equals the origin port, and otherwise don't upgrade (rather than upgrading against the wrong port). That trades a silently-wrong attempt for a correctly-skipped one.

Found while investigating #23; not the cause of that bug.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions