nox-h2: let a 1xx be interim, not the answer
on_headers took the first header block on a stream to be the response
whatever its status, so an interim 1xx filled the response slot and the
real response that followed was filed as trailers. The Eio adapter
resolves a call on the first Response event, so a server sending 103
Early Hints -- an ordinary deployed thing, not a hostile peer -- answered
the call with 103 and dropped the 200 carrying the result.
RFC 9113 sec 8.1 lets a server send any number of interim responses
before the final one, so the two are different events, not one event with
a status to squint at. Client.event gains Informational; interim blocks
arrive as that and leave the response slot empty, so Response now means
the one final response and a caller awaiting it cannot latch an interim
block. The adapter ignores Informational and leaves the promise pending.
That also closes the other half of the same sentence: a HEADERS bearing
END_STREAM with an informational status is malformed, which sec 8.1.1
makes a PROTOCOL_ERROR stream error. An interim response promises a
final one, so ending the stream promises a response that can never
arrive, and a caller would wait on a stream nobody will write to again.
The check runs through a new ROLE.malformed hook, applied after the
block is decoded rather than instead of it, so the HPACK context stays
in step on a connection the stream error leaves alive.
nox-h2: let a 1xx be interim, not the answer
on_headers took the first header block on a stream to be the response
whatever its status, so an interim 1xx filled the response slot and the
real response that followed was filed as trailers. The Eio adapter
resolves a call on the first Response event, so a server sending 103
Early Hints -- an ordinary deployed thing, not a hostile peer -- answered
the call with 103 and dropped the 200 carrying the result.
RFC 9113 sec 8.1 lets a server send any number of interim responses
before the final one, so the two are different events, not one event with
a status to squint at. Client.event gains Informational; interim blocks
arrive as that and leave the response slot empty, so Response now means
the one final response and a caller awaiting it cannot latch an interim
block. The adapter ignores Informational and leaves the promise pending.
That also closes the other half of the same sentence: a HEADERS bearing
END_STREAM with an informational status is malformed, which sec 8.1.1
makes a PROTOCOL_ERROR stream error. An interim response promises a
final one, so ending the stream promises a response that can never
arrive, and a caller would wait on a stream nobody will write to again.
The check runs through a new ROLE.malformed hook, applied after the
block is decoded rather than instead of it, so the HPACK context stays
in step on a connection the stream error leaves alive.