squirrelscan
GitHub

HTTP/2 and HTTP/3: what the response headers can tell you

Whether the server advertises HTTP/2 or HTTP/3. squirrel reads Alt-Svc and the Server header, and says when it cannot tell.

What HTTP/2 and HTTP/3 change

HTTP/1.1 keeps connections alive but sends one request at a time on each, so a browser opens several per host and queues the rest, and a slow response holds up everything behind it on that connection. HTTP/2 multiplexes many requests over one connection and compresses headers, which removes the queueing and most of the per-request overhead. It requires HTTPS in every browser that implements it.

HTTP/3 runs the same semantics over QUIC, which is built on UDP. Its advantage is connection setup and recovery: no separate TCP and TLS handshakes, and a lost packet in one stream does not stall the others. A server advertises it with an Alt-Svc header naming h3.

What squirrel checks

The rule runs on every crawled page and reads the response headers. It emits one to three checks:

  • http-version: passes with the message HTTP/3 (QUIC) support advertised when Alt-Svc contains h3, or with HTTP/2 support advertised via Alt-Svc when it contains h2 and not h3.
  • http3-hint: emitted alongside the previous check when Alt-Svc names h2 but not h3, at info status with the message Consider enabling HTTP/3 (QUIC) — only HTTP/2 is advertised and the expectation Alt-Svc advertising h3.
  • http2-https-required: warns with the message HTTP/2 requires HTTPS and stops when the page URL is not https.
  • http2-likely: emitted only when nothing above fired, at info status with the message Server likely supports HTTP/2, when the Server or Via header contains cloudflare, cloudfront, fastly, akamai, google, nginx or h2o.
  • http2-unknown: at info status with the message HTTP/2 support cannot be determined from headers when nothing else applied.

An http URL that advertises only h2 produces all three of http-version, http3-hint and http2-https-required. The negotiated protocol is not a response header, so this rule infers rather than observes. Alt-Svc is an advertisement of what else is available, not a statement about the connection the response arrived on.

On a local or private-network host, such as localhost or 192.168.1.10, the rule is skipped and left out of the score, because a dev server is not the production edge. See Transport and delivery rules do not apply.

How to fix it

Most servers and every major CDN support HTTP/2 by default over HTTPS. On nginx it is a listen directive:

listen 443 ssl;
http2 on;

For HTTP/3, enable QUIC and advertise it:

listen 443 quic reuseport;
add_header Alt-Svc 'h3=":443"; ma=86400';

The common false positive is a site already on HTTP/2 that does not send Alt-Svc and runs behind a server string this rule does not recognise. It reports that it cannot tell, which is accurate and not a defect. Check with curl -I --http2 https://example.com.

Rule IDperf/http2
CategoryPerformance
ScopePer-page
Severityinfo
Weight3/10

Enable / disable

Disable this rule

[rules]
disable = ["perf/http2"]

Disable all Performance rules

[rules]
disable = ["perf/*"]

Enable only this rule

[rules]
enable = ["perf/http2"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

Performance findings ship in every audit next to the SEO, security and agent experience rules. See Core Web Vitals for how an agent works through a report.

References

Check your site

Run squirrel audit https://example.com and open the Performance section of the report. Each page reports what its headers advertised. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close