PQ CRYPTA PLATFORM

๐Ÿ  Main

๐Ÿงช Interactive Apps

๐Ÿ“ฐ News

๐Ÿ›ก๏ธ PQ Crypta Proxy

๐Ÿ‘ค Account

โŸจ QUANTUM ERROR PORTAL โŸฉ

Navigate the Error Dimensions

PQ Crypta Logo

HTTP/3 Client Conformance

A server that misbehaves on purpose, so your client library can find out how it copes

The QUIC Interop Runner tests implementations against each other in a lab matrix. This is the other thing: a public service you can point a client library at to find out whether it handles the protocol's awkward corners.

Offering one requires a server that will misbehave on demand โ€” emit a reserved frame type, duplicate a SETTINGS identifier, open a control stream with the wrong frame. That is not something a CDN customer can arrange, because they do not own the implementation. We fork the QUIC stack, so we can.

27 tests
14 HTTP/3 layer
13 QUIC layer
4460–4486 UDP ports

Running it

Each test has its own UDP port. Connect to it, and the server records what your client did. Results are filed under a session started from your address, so the test connections need nothing special.

# start a session
SESSION=$(curl -sX POST https://conformance.pqcrypta.com/session \
  | sed 's/.*"id":"//;s/".*//')

# walk the catalogue
curl -s https://conformance.pqcrypta.com/catalog.json \
  | grep -o '"port": [0-9]*' | grep -o '[0-9]*' | while read PORT; do
      curl -s --http3-only --max-time 15 \
        "https://conformance.pqcrypta.com:$PORT/" -o /dev/null
    done

# read the result
curl -s https://conformance.pqcrypta.com/report/$SESSION.json

The report is also available as a page at /report/<session> and as an SVG badge at /badge/<session>.svg.

How a verdict is reached

The server is the judge. A library that crashes on an unknown frame is in no position to report on itself, so every verdict comes from what the server observed.

Every test ends with a liveness probe: after the anomaly, the server expects one ordinary request on the same connection. For the extensibility tests this is the whole game โ€” "ignored it" and "died on it" look identical on the wire up to that point, and without the probe a crashed client would read as compliant.

Extensibility

Ignore something unrecognised and carry on. Rejecting it is the failure โ€” that is how protocols ossify.

Correctness

Reject something invalid, with the specific error code the RFC names. Accepting it is the bug.

Interoperability

Correctly decode something valid but demanding โ€” Huffman-coded fields, a dynamic-table reference, trailers.

Resilience

Recover โ€” retry, re-probe, migrate โ€” rather than give up.

Discretionary

The RFC permits more than one answer. Both pass; the report says which yours chose.

Inconclusive

The run never put your client in the situation the test is about. It proves nothing either way, and says so.

Those last two exist because the model was wrong twice. Scoring a MAY as a MUST failed clients for making a legal choice, and scoring "the request never reached the window" as a failure accused clients of accepting violations that were never sent. A suite that wrongly accuses the thing it tests is worse than no suite, because nobody then believes the failures that are real.

The catalogue

Read live from the suite, so this table cannot drift from what is actually served. Every entry cites the clause it exercises.

HTTP/3 layer

Test Port Class Specification
h-grease-settings Reserved SETTINGS identifier (0x1fยทN+0x21) Ignore the unknown setting and complete the request. 4473 Extensibility RFC 9114 ยง7.2.4.1
h-grease-frame Reserved frame type on the response stream Skip the frame using its length and read the response that follows. 4474 Extensibility RFC 9114 ยง7.2.8
h-reserved-uni-stream Unidirectional stream with a reserved stream type Abort reading the stream or discard it โ€” ยง6.2.3 permits either. What it forbids is treating it as meaningful, or as fatal to the connection. 4475 Extensibility RFC 9114 ยง6.2.3
h-duplicate-setting SETTINGS containing the same identifier twice Either reject with H3_SETTINGS_ERROR or ignore the repeat โ€” the specification says a receiver MAY treat this as an error, so both are conformant. 4476 Discretionary RFC 9114 ยง7.2.4
h-control-frame-unexpected A DATA frame on the control stream Close the connection with H3_FRAME_UNEXPECTED. 4477 Correctness RFC 9114 ยง7.2.1
h-missing-settings Control stream whose first frame is not SETTINGS Close the connection with H3_MISSING_SETTINGS. 4478 Correctness RFC 9114 ยง6.2.1
h-second-control-stream A second control stream opened by the server Close the connection with H3_STREAM_CREATION_ERROR. 4479 Correctness RFC 9114 ยง6.2.1
h-qpack-dynamic-table Field lines referencing dynamic table insertions Apply the encoder-stream insertions and decode the headers correctly. 4480 Interoperability RFC 9204 ยง4.3.3, ยง4.5.2
h-qpack-huffman Huffman-coded field lines with maximal padding Decode without error. Padding of up to 7 bits is legal, not corruption. 4481 Interoperability RFC 9204 ยง4.1.2, RFC 7541 ยง5.2
h-oversized-field-section Field section larger than the client's advertised maximum Handle it as an error against that one request, not the whole connection. 4482 Interoperability RFC 9114 ยง4.2.2
h-trailers Trailing field section after the body Deliver the trailers to the application after the body completes. 4483 Interoperability RFC 9114 ยง4.1
h-early-hints 103 Early Hints before the final response Treat 103 as informational and keep reading for the final response. 4484 Resilience RFC 8297
h-goaway GOAWAY sent mid-connection Stop opening requests, finish those in flight, and retry idempotent ones elsewhere. 4485 Resilience RFC 9114 ยง5.2
h-max-push-id MAX_PUSH_ID sent by the server Reject with H3_FRAME_UNEXPECTED. MAX_PUSH_ID travels client to server only, so a server sending one is using a frame in a direction the specification does not allow. 4486 Correctness RFC 9114 ยง7.2.7

QUIC layer

Test Port Class Specification
q-version-negotiation Version Negotiation offering a reserved version alongside v1 Abandon the connection attempt, or retry with a version both ends support. ยง6.2 requires a client that supports only one version to abandon it rather than persist. 4460 Correctness RFC 9000 ยง6
q-retry Retry packet for source-address validation Echo the Retry token in a second Initial packet and complete the handshake. 4461 Correctness RFC 9000 ยง8.1.2
q-reserved-transport-param Reserved transport parameter (31ยทN+27) Ignore the unknown parameter and complete the handshake normally. 4462 Extensibility RFC 9000 ยง18.1
q-reserved-frame Unknown frame type in a 1-RTT packet Close the connection with FRAME_ENCODING_ERROR. Unlike HTTP/3, QUIC reserves no ignorable frame types โ€” ยง12.4 makes an unknown frame a connection error, so ignoring it is the failure here. 4463 Correctness RFC 9000 ยง12.4
q-cid-rotation NEW_CONNECTION_ID followed by RETIRE_CONNECTION_ID Adopt the new connection ID, retire the old one, and stay connected. 4464 Resilience RFC 9000 ยง5.1
q-stateless-reset Stateless reset Recognise the token and close immediately. The packet cannot be authenticated, so there is nothing to reply with and nothing to report to the peer โ€” the connection simply ends. 4465 Correctness RFC 9000 ยง10.3
q-flow-control Deliberately tight MAX_DATA and MAX_STREAM_DATA Respect the limit. Announcing the stall with DATA_BLOCKED or STREAM_DATA_BLOCKED is a SHOULD in ยง4.1, not a MUST, so a client that stays silent is still conformant. 4466 Discretionary RFC 9000 ยง4
q-ack-frequency ACK Frequency extension offered Negotiate the extension, or ignore it. Either is correct; failing is not. 4467 Discretionary draft-ietf-quic-ack-frequency
q-ecn Packets marked ECT(0) Report the ECN counts back in ACK_ECN frames. 4468 Correctness RFC 9000 ยง13.4
q-pmtu-blackhole Path MTU black hole above a threshold Detect the black hole, probe down to a working size, and keep the connection. 4469 Resilience RFC 9000 ยง14, RFC 8899
q-path-challenge Server-initiated PATH_CHALLENGE Reply with PATH_RESPONSE carrying the identical 8-byte payload. 4470 Correctness RFC 9000 ยง8.2
q-zero-rtt-reject 0-RTT rejected after the client sends early data Reset the state of every stream, including application state bound to them. Section 4.6.2 requires the reset because a rejected 0-RTT means every assumed connection characteristic may have been wrong. It does not require retransmission, which is the application concern, not QUIC's. 4471 Resilience RFC 9001 ยง4.6.2
q-multipath A second path offered mid-connection Use the additional path, or decline it cleanly. Do not abort the connection. 4472 Discretionary draft-ietf-quic-multipath

What this cost to get right

Building it turned up more bugs in the suite than in any client. Every failure it reported during development was ours, and each would have produced a false verdict:

Every expected_code in the catalogue has since been checked against the published RFC text rather than recollection, and three tests are pinned to the sentence that requires them so a later edit cannot drift.

Status

This is new and openly incomplete. Tests whose anomaly is not yet implemented serve a correct control stream and record inconclusive โ€” never a pass, and never a failure for something that was not sent.

If your client scores a failure you believe is wrong, say so. Given the above, the suite is the more likely culprit, and a false accusation is a bug worth fixing quickly.