DEV Community

OnePassApps
OnePassApps

Posted on

We Advertised HTTP/3 and Never Tested It: 9 Answers Over QUIC, One More Server-Timing Line, and a Dropped Priority Header

I work on OnePassApps, the team behind app.onepassapps.com. Everything below was measured against our own site from outside the browser, signed out, on one machine, on one day.

When I wrote about the TLS layer under this site I said our host advertises HTTP/3 with alt-svc: h3=":443"; ma=86400, but that I could not tell you whether it actually works, because I had no HTTP/3 client. A later post repeated the same limit. This one closes it: I installed a QUIC client and asked the server directly.

What I used

The curl on this box is 8.18.0 and was built without HTTP/3 support - asking it for HTTP/3 answers "the installed libcurl version does not support this". So I installed aioquic 1.7.2 and drove the QUIC connection and the HTTP/3 framing myself.

Nine URLs: six on the app host (/, /guides, /studios/image, /apps/paperkit, /apps/movie-tracker, /terms) and three on the API host (/api/health, /api/products, /api/plans).

Both sides of the comparison used the same request shape - the same User-Agent, the same Accept header, and accept-encoding: identity. That matters, because an earlier post of ours measured that the answer changes shape with the request headers, so a comparison across two protocols with two different header sets would be worthless.

The short version: it works

All nine URLs answered 200 over QUIC on port 443, and the body length was the same over both protocols for every one of them.

URL HTTP/3 body HTTP/2 body
/ 25,011 bytes 25,011 bytes
/guides 61,760 bytes 61,760 bytes
/studios/image 17,232 bytes 17,232 bytes
/apps/paperkit 19,054 bytes 19,054 bytes
/apps/movie-tracker 19,311 bytes 19,311 bytes
/terms 74,862 bytes 74,862 bytes
/api/health 410 bytes 410 bytes
/api/products 15,650 bytes 15,650 bytes
/api/plans 4,020 bytes 4,020 bytes

The bytes themselves are not identical between two fetches of the same URL - that is the per-request key we published separately - so this post compares lengths, not bytes. The lengths were stable: three fetches over each protocol gave the same length every time.

One more Server-Timing line

Over HTTP/2 our host sends exactly two server-timing lines: cfCacheStatus;desc="DYNAMIC" and cfEdge;dur=N,cfOrigin;dur=M. That is our own published response-header layer.

Over HTTP/3 it sends three. The same two, plus a third line reading cfExtPri.

A priority header HTTP/2 dropped

The HTTP/3 answer also carries priority: u=3,i=?0 - the HTTP/3 priority field - and the HTTP/2 answer for the same URL carries no priority field at all.

Counting header lines as each client sees them: HTTP/3 gave 24 lines on the app-host pages and HTTP/2 gave 21. Three of that difference is accounted for: one is the :status pseudo-header that only the HTTP/3 framing carries, one is the priority field, one is the extra server-timing line. The API host shows the same three-line gap: 35 against 32 on /api/health, and 34 against 31 on /api/products and /api/plans.

Six URLs on one handshake

HTTP/3 multiplexes requests over a single connection, so the six app-host URLs were fetched over one QUIC connection and one handshake: the handshake took 0.0791 s and all six answers were complete 0.0837 s later. On the API host, three URLs on one connection: 0.0366 s for the handshake and all three answers 0.1659 s later.

The advertisement is still sent to the client already speaking HTTP/3

The HTTP/3 answers still carry alt-svc: h3=":443"; ma=86400, and cf-cache-status reads DYNAMIC on both protocols.

What I did not do

One build, one day, one machine, one network path, one region. Signed out, no cookies, no JavaScript, no browser - these are plain HTTPS and QUIC requests to the live host. Nine URLs, not the 56 in the sitemap. One QUIC client, so a different client could see different timings. I did not measure a rendered page, and I did not compare the browser's own HTTP/3 support.

The write-ups on the layers underneath this one are the TLS layer, the protocol layer and the two Server-Timing lines - the first two of them flagged that HTTP/3 was advertised here but not exercised. The per-request key that changes the bytes between two fetches is its own post.

If you want to see the apps themselves, the OnePassApps home page and the guides are the place to start.

Top comments (0)