ListenerQUIC installed only a no-op bootstrap connection callback in the NEW_CONNECTION handler and deferred the real ClientQUIC callback to the ThreadPool, alongside per-connection onConnect setup. An HTTP/3 peer (notably Chromium) opens its control + QPACK + request streams the instant the QUIC handshake completes — potentially before that deferred task ran. Those early PEER_STREAM_STARTED events were delivered to the bootstrap and silently dropped, so the session never completed. Over the network this surfaced as an intermittent "WebTransport connection rejected" that cleared on retry. Construct the ClientQUIC (and thus install its real connection callback) synchronously inside NEW_CONNECTION, before the handler returns and before msquic delivers any further events. pendingAccepted now holds the constructed ClientQUIC*; the accept loops just dispatch it, and the destructor cleans up any peer accepted but never dispatched. Also park WT data streams that arrive before their CONNECT session is registered (the stream demux races the CONNECT handler) and drain them on registration, instead of dropping them. Tests: - New ShouldNotDropEarlyStreams reproduces the race deterministically by saturating the ThreadPool so onConnect is gated while the client opens its request stream; fails on the pre-fix build, passes after. - Give ShouldEchoWebTransport its own port (8085) so it no longer collides with ShouldSendRecieveKeepaliveHTTP (8083) under the parallel test runner. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| Crafter.Network-ClientHTTP-Browser.cpp | ||
| Crafter.Network-ClientHTTP.cpp | ||
| Crafter.Network-ClientQUIC-Browser.cpp | ||
| Crafter.Network-ClientQUIC.cpp | ||
| Crafter.Network-ClientTCP.cpp | ||
| Crafter.Network-ListenerHTTP.cpp | ||
| Crafter.Network-ListenerQUIC.cpp | ||
| Crafter.Network-ListenerTCP.cpp | ||
| Crafter.Network-WebTransport.cpp | ||