masque_racer (masque v0.7.0)

View Source

Transport race for MASQUE client connects.

Apple's MASQUE clients (Private Relay, Network.framework) prefer HTTP/3 but fall back to HTTP/2 on networks that block QUIC. They don't wait for an h3 timeout - they give h3 a short head start and then race h2 in parallel, using whichever handshake finishes first. HTTP/1.1 over classic HTTPS follows the same idea as a tertiary rung for networks where h2 is also refused or ALPN is stripped.

This module implements that logic for a single masque:connect/3 call. It runs in the caller's process; no extra supervision.

Flow for [T1, T2, T3] (T3 optional):

  1. Start T1 immediately with a shadow owner.
  2. After prefer_timeout_ms ms, start T2 in parallel.
  3. After another h1_prefer_timeout_ms ms (only if T3 is present), start T3 in parallel.
  4. First attempt to report ok on its handshake_await call wins. Shadow owner is flipped to the real owner via gen_statem:call(Pid, {set_owner, RealOwner}), losers are killed.

Note: the session modules already deliver to the owner set on start. To avoid a racey burst of messages going to the caller from losing attempts, each session is started with the racer as owner; on win we transfer owner via a session call. Since the race completes before any datagrams are sent (sessions only reach open on 2xx / 101), the owner swap happens on a quiet mailbox.

Summary

Functions

Race the listed transports and return the winning session.

Functions

checkout_pool(Transport, Opts)

-spec checkout_pool(masque:transport(), map()) -> {ok, map()} | {error, term()}.

race(Transports, Target, Opts, RealOwner)

-spec race([masque:transport()], masque:target(), map(), pid()) ->
              {ok, masque:session()} | {error, term()}.

Race the listed transports and return the winning session.