Resources

How Browsers and Websites Negotiate the HTTP Version

HTTP version selection is no longer a single handshake. For HTTP/1.1 and HTTP/2, a browser opens one TCP connection and TLS ALPN decides the protocol inside it. HTTP/3 adds a decision in front of that: whether to try QUIC over UDP at all, made before any TLS handshake begins, using DNS HTTPS records, cached Alt-Svc headers, and browser-specific connection racing.

This article stays at that decision-flow level, from the perspective of SSE and Secure Web Gateway testing. The examples are based on observations made with SSE TestCenter in mid-2026; browser behavior in this area is still moving quickly, so read them as measured behavior at a point in time, not as permanent vendor guarantees — section 2 explains why.

1. Transport Selection Precedes Protocol Selection

If every connection ran over TCP, this would be a short article. TLS's ALPN extension (RFC 7301) lets the client and server agree on HTTP/1.1 or HTTP/2 during the handshake itself, and that is the entire negotiation:

ALPN: h2, http/1.1

The server picks one token from the client's list and the connection uses it from then on. There is no discovery problem, no caching, and no first-visit/repeat-visit distinction — every connection negotiates fresh, in-band, in the same round trip that establishes TLS.

Set this aside for a moment. ALPN is real, it is how H1 vs. H2 is decided on every TCP connection SSE TestCenter serves, and nothing below changes that. It simply cannot help with HTTP/3.

HTTP/3 also uses ALPN — its token is h3 — but that negotiation happens inside a QUIC connection, and QUIC runs over UDP, not TCP. A client that has already opened a TCP connection has nothing on that connection that can carry QUIC frames; there is no in-band way to renegotiate onto a different transport mid-connection. So the transport decision — TCP or UDP — has to be made before ALPN ever runs, using information gathered outside the connection itself. That is the actual subject of this article: not "which HTTP version," but "how does a browser decide, before opening anything, whether to try UDP at all."

2. Scope of This Article: A Fast-Moving Target

There is no single standardized algorithm yet for how a browser should make the TCP/UDP decision. There is an emerging one — the IETF HAPPY working group's Happy Eyeballs Version 3 draft (revision -04 as of July 2026, Standards Track) — which describes racing QUIC and TCP connection attempts concurrently rather than trying one and falling back to the other, preferring QUIC when both succeed, and folding DNS SVCB/HTTPS records into the same algorithm as the source of protocol hints. That is a good description of where browsers are heading. It is not yet a description of what any one of them reliably does today.

In practice, the behavior we could observe on SSE TestCenter varies by browser vendor, by version within the same vendor, by operating system running the identical browser version, and by feature flags a user or a device-management policy can set — sometimes all at once. The /etc/resolver story in the Chrome section below is a direct illustration: the identical Chrome build behaves differently on two otherwise-identical machines, purely because of a local DNS configuration difference. Nothing here should be read as "this is how Chrome works" so much as "this is how Chrome worked, on this build, on this platform, in mid-2026." Expect it to keep moving, generally in the direction the draft describes.

3. Three Discovery Mechanisms

With that caveat in place, the TCP/UDP decision today is controlled by some combination of three things:

Mechanism What it does When it applies
DNS HTTPS record Advertises supported protocols, and optionally ports, before any connection is opened Before the first packet — can enable H3 on the first connection
Alt-Svc Tells the browser an alternative service (H3) is available, via a response header on an already-open connection After a successful HTTP response — enables H3 on a later connection, or in Chrome's case, on later requests within the same page load
Direct probing The browser attempts a QUIC connection alongside, or instead of, a TCP one, and keeps whichever completes first Usually triggered by one of the two signals above; on some platforms and in some experimental configurations, browsers are starting to try QUIC with no prior signal at all

The first two are advertisements the server makes; the third is what the browser actually does in response, which is where Happy Eyeballs-style racing comes in. Section 4 introduces Alt-Svc and DNS HTTPS records; the racing behavior itself shows up throughout the per-browser notes in section 5, since it is currently the least standardized of the three.

A separate axis compounds the matrix: browsers race IP address families the same way they are starting to race transports. Given both an IPv4 and an IPv6 address, current Happy Eyeballs guidance is to interleave attempts with a preference for IPv6, on the reasoning that IPv6 paths tend to be more direct and less likely to traverse NAT or carrier-grade middleboxes. Put together with the transport race, the general direction a well-connected dual-stack client is heading toward is IPv6 + H3 (QUIC) where available, falling back through IPv6+H2, IPv4+H3, and IPv4+H2 roughly in that order of preference. We have not run a dedicated IPv4/IPv6 comparison on SSE TestCenter, so take this paragraph as general Happy Eyeballs behavior rather than a site-specific measurement.

Network conditions and intermediate devices can interrupt any leg of any of these races — a dropped UDP packet, a stripped DNS record, a proxy that terminates TLS itself — without the user necessarily noticing, since the browser simply falls back to whatever transport did work. Section 6 covers what that looks like from the gateway operator's side of the same race.

Two independent mechanisms let a server tell a browser that H3 is available, without relying on the TCP connection the browser may already be trying to open.

Alt-Svc (RFC 7838, extended for H3) is an HTTP response header. It only reaches the browser after a successful H1 or H2 response, so it can never help the very first connection of a session — but a browser that caches it will attempt QUIC on a later connection, and Chrome acts on it quickly enough to sometimes upgrade sub-resource requests within the same page load (section 3's racing behavior again). macOS Safari does not act on Alt-Svc at all — its H3 discovery runs through DNS HTTPS records only; see section 5 for the platform split we found here.

DNS HTTPS records (RFC 9460) move the same kind of information into DNS, queried alongside the ordinary A/AAAA lookup, before any connection is attempted. A browser that receives one and sees h3 in its ALPN list can attempt QUIC on the very first connection of a session — the only way a cold first visit can reach H3 at all. This is also the mechanism a gateway removes by omitting HTTPS records from its DNS responses: browsers that depend on it, notably Safari, fall back to H2 or H1 with no QUIC attempt, even on the first connection.

Both signals are cached — Alt-Svc via its ma max-age, the HTTPS record via its DNS TTL — and both can be present, absent, or overtaken by a slower DNS response that arrives after the browser has already committed to TCP. Section 5 covers how each browser resolves that in practice.

SSE TestCenter exposes these combinations directly in the Hostname Matrix. h2-h3-alt.sse-testcenter.org, for example, serves H2 and H3 but carries no DNS HTTPS record, so it advertises H3 through Alt-Svc alone — a useful host for isolating Alt-Svc behavior specifically, including the macOS/iPadOS Safari split covered in section 5.

This article stays at the decision-flow level. For the full Alt-Svc header syntax, the complete set of HTTPS record service parameters, a side-by-side comparison table, and dig commands for inspecting records directly, see DNS HTTPS Records and Alt-Svc.

5. Decision Flow: First Visit, Fallback, and Repeat Visit

Putting the three mechanisms together, a simplified decision flow looks like this:

  1. The browser looks up A/AAAA records and, if it supports them, queries DNS HTTPS records in parallel.
  2. A DNS HTTPS record advertising h3 that arrives before the browser commits to TCP lets it attempt QUIC immediately — the only path to H3 on a genuinely cold first visit.
  3. Otherwise the browser opens a TCP connection and negotiates H2 or H1 via ALPN. The response may carry Alt-Svc.
  4. A cached Alt-Svc entry, or a DNS HTTPS record cached from an earlier visit, lets a later connection attempt QUIC directly instead of starting over on TCP.
  5. If a QUIC attempt fails — UDP blocked, no listener, handshake timeout — the browser falls back to TCP when a TCP-capable alternative exists. A failed attempt may also cause the browser to temporarily de-prioritize the cached signal that triggered it, so the next visit retries TCP until a successful H3 connection re-establishes the cache.

Browser-specific behavior explored during testing

Safari

Safari sends the HTTPS record query before the A/AAAA query. When responses arrive in the same order, Safari has the protocol information before opening any connection and uses QUIC directly on the first visit. The failure mode arises at intermediate DNS servers: a nameserver in the path can reorder the responses and deliver the A record before the HTTPS record, sometimes with a delay of tens of milliseconds between the two. When that happens, Safari opens a TCP connection and negotiates H2; the HTTPS record arrives while or after the handshake, too late to change that connection's protocol; and the next reload, with the record now cached, uses QUIC directly.

macOS Safari

macOS Safari does not honor the Alt-Svc response header. A host that advertises H3 only via Alt-Svc — with no DNS HTTPS record — stays on H2 in macOS Safari regardless of how many responses carry the header. The one exception is connection coalescing: if Safari already holds an active H3 session to a different hostname at the same IP address, covered by the same TLS certificate, it may reuse that session for the new host without ever consulting Alt-Svc for it. See our DNS HTTPS Records and Alt-Svc page for the detailed coalescing example.

If the DNS HTTPS record carries a non-standard port for H2 or H3, macOS Safari connects to that port even when the URL does not specify it — conformant with RFC 9460 §7.2. Safari's recovery from a lost DNS race also appears faster than Chrome's: rather than waiting out the full A-record TTL, a reload typically recovers within a much shorter window, though the exact retry mechanism is not fully characterized.

iPadOS Safari

Cross-device testing found that iPadOS Safari genuinely differs from macOS Safari here — it does honor Alt-Svc. A controlled test (two physical devices, same network, the iPad with zero prior session state for the host under test — ruling out connection coalescing as an explanation) showed the classic Alt-Svc signature: the first request went out over H2 carrying no prior knowledge, the H2 response included alt-svc: h3=":443", and the very next connection attempt opened a fresh QUIC session and completed over H3. The likely underlying cause is a newer network loader Apple is rolling out unevenly across platforms — the kind of cross-version, cross-OS drift this whole article warns about in section 2. Any third-party iPad/iPhone browser built on WKWebView, which is mandatory for App Store apps, inherits this same behavior, since it shares Safari's network stack.

Chrome

Chrome also sends the HTTPS record query before A/AAAA, and the same intermediate-DNS reordering problem applies: if an intermediate nameserver delivers the A record first — delayed by tens of milliseconds relative to the HTTPS record — Chrome may open a TCP connection before learning that H3 is available. Chrome adds a client-side constraint that makes it especially sensitive to this delay: after the A record arrives, Chrome runs a short internal timeout (observed at 6–8 ms in testing) and aborts the outstanding HTTPS query if it has not arrived within that window. An intermediate that introduces even a small delay between the two responses is enough to consistently miss this window.

If Chrome establishes a TCP/H2 connection and the server's response includes an Alt-Svc header, Chrome acts on it within the same page load: it launches a QUIC session immediately and routes sub-resource requests and JS-initiated fetches over H3. This means H3 can appear on the "first visit" even though the initial document request went over H2.

If neither a timely HTTPS record nor an Alt-Svc header is available, Chrome has no H3 discovery signal and will not retry H3 until the DNS TTL expires. The failure is sticky: repeated reloads will not recover until a fresh DNS task delivers the HTTPS record within Chrome's timeout window. On a host where H3 is the only available protocol, a client that lost the DNS race may see a connection error on every attempt for up to the full A-record TTL — for example 300 seconds (5 minutes).

A separate scenario removes H3 discovery entirely: endpoint firewall and CASB agents commonly install per-domain resolver entries (for example via /etc/resolver on macOS) pointing to a loopback nameserver. Chrome detects a loopback nameserver and disables its internal DNS client — no HTTPS record queries are issued at all. We confirmed this directly: two otherwise-identical Macs on the same network, running the identical Chrome version, showed opposite behavior — one issuing HTTPS queries, the other not — and the only configuration difference was a set of /etc/resolver entries with a loopback nameserver added for endpoint firewall testing on the second machine. Removing those entries and restarting Chrome restored the HTTPS queries immediately. In that environment Chrome relies on Alt-Svc only and cannot reach H3 on a cold first visit.

Chrome ignores the DNS HTTPS port SvcParam when the value differs from the URL port: the endpoint metadata is discarded and Chrome connects to the standard port regardless. This is a non-conformance with RFC 9460 §7.2. A host deployed exclusively on a non-standard port via a DNS HTTPS record is reachable from Safari but not from Chrome. (Chrome behaves differently again when the URL itself contains an explicit non-standard port — see our DNS HTTPS Records and Alt-Svc page for that case, including a resolver-dependent Chrome bug we ran into and reported upstream.)

The flows above describe direct connections. A gateway in the path can alter any of these outcomes independently — suppressing HTTPS records removes first-visit H3 for both browsers; stripping Alt-Svc removes Chrome's upgrade path but has no effect on macOS Safari.

6. Why This Matters for SSE Gateways

A Security Service Edge gateway can affect all three mechanisms independently, and each intervention has distinct, observable consequences.

DNS interception — suppressing or modifying HTTPS records

Many SSE products act as the DNS resolver for managed clients. A gateway that does not forward or synthesize HTTPS records effectively removes early H3 discovery. Browsers that rely on DNS HTTPS records (notably Safari) will not attempt QUIC on the first visit; they fall back to TCP and negotiate H2. The gateway may never see a QUIC connection from the browser at all.

Alt-Svc stripping

A gateway that terminates the browser's TLS connection and re-originates a new upstream connection will receive the server's Alt-Svc header on the upstream side. Whether that header is forwarded to the browser is a product decision. Stripping it prevents Chrome and Firefox from learning about H3, keeping the browser on H2 regardless of what the origin supports.

ALPN on the browser side vs. the server side

A terminating gateway presents its own TLS handshake to the browser and a separate one to the origin. It can offer a different ALPN set on each side. A gateway that only offers http/1.1 to the browser will keep the browser on H1 even if it connects H2 or H3 upstream itself. Conversely, a gateway may offer H2 to the browser while using H1 upstream — the browser sees a modern protocol, but the upstream connection has no multiplexing.

QUIC/UDP blocking — what it actually costs

A common enterprise control is blocking outbound UDP/443, which prevents QUIC while leaving TCP/443 (H2, H1) intact. Because Chrome races a QUIC attempt and a TCP attempt concurrently whenever a DNS HTTPS record advertises h3 (section 3), blocked UDP packets are simply dropped in the background while the TCP/H2 handshake completes normally. In our testing this produced no perceptible delay for dual-stack hosts (H2+H3 on the same port): the TCP job typically completed in 100–200 ms while the QUIC job was still retransmitting, and was cancelled once TCP won.

The one case where blocking UDP/443 is not free is an H3-only host: there is no TCP fallback to race against, so the browser has to wait out QUIC's retransmission timeline in full — retries at roughly 300 ms, 600 ms, and 1200 ms after the initial attempt, then an idle-timeout failure around 4 seconds. That is the only scenario in which a UDP block produces a user-visible stall, and it reinforces the general point made throughout this article: an H3-only host is a poor choice for a production service, precisely because it removes the TCP fallback that makes every other part of this negotiation forgiving of a blocked or missing signal.

Blocking UDP/443 is consequently a low-impact way to force inspectable TCP traffic for the vast majority of real deployments. Pairing it with Alt-Svc stripping and DNS HTTPS suppression is defense in depth — not required to avoid user-visible delay, but it stops browsers from attempting QUIC on the wire at all, and closes the path by which a client could fall back to a cached H3 entry from before the block was put in place.

No single control is sufficient on its own: DNS HTTPS suppression prevents first-visit H3, Alt-Svc stripping prevents learned H3, and UDP blocking prevents QUIC even when a browser already holds a cached H3 entry from before any control was in place. Which combination is necessary depends on the gateway's architecture and whether it terminates TLS.

All of these effects are visible through the SSE TestCenter Hostname Matrix. The protocol widget on each page shows what actually reached the server, the peer IP identifies the connection source, and the strict per-hostname ALPN enforcement makes the gateway's upstream behavior observable directly.

For a deeper treatment of both mechanisms — complete Alt-Svc syntax, all HTTPS record service parameters, a side-by-side comparison table, and dig commands for inspecting records directly — see DNS HTTPS Records and Alt-Svc.