Skip to content

Commit b024c08

Browse files
PQCryptaBiagioFesta
authored andcommitted
fix: Handle race condition when close_reason() returns None
The functions `no_connect()` and `with_no_connection()` previously used `.expect()` on `quic_connection.close_reason()`, which panics when the connection is still alive. This race condition occurs when: 1. A QUIC connection is established to an HTTP/3 server 2. Server sends SETTINGS frame quickly (e.g., Akamai) 3. Driver thread processes incoming streams 4. Connection cleanup is triggered simultaneously 5. close_reason() returns None (connection still alive) 6. .expect() panics: "QUIC connection is still alive on close-cast" The fix replaces .expect() with match expressions that gracefully return ConnectionError::LocallyClosed when close_reason() is None. Affected: HTTP/3 client applications scanning sites protected by Akamai and similar CDNs with fast SETTINGS responses.
1 parent 0c49c18 commit b024c08

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

wtransport/src/error.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,15 @@ impl ConnectionError {
5353
}
5454

5555
pub(crate) fn no_connect(quic_connection: &quinn::Connection) -> Self {
56-
quic_connection
57-
.close_reason()
58-
.expect("QUIC connection is still alive on close-cast")
59-
.into()
56+
match quic_connection.close_reason() {
57+
Some(reason) => reason.into(),
58+
None => {
59+
// Connection still alive but driver reported NotConnected.
60+
// This race condition can occur when driver threads are processing
61+
// incoming streams while connection cleanup is triggered.
62+
ConnectionError::LocallyClosed
63+
}
64+
}
6065
}
6166

6267
pub(crate) fn local_h3_error(error_code: ErrorCode) -> Self {
@@ -116,12 +121,15 @@ pub enum ConnectingError {
116121

117122
impl ConnectingError {
118123
pub(crate) fn with_no_connection(quic_connection: &quinn::Connection) -> Self {
119-
ConnectingError::ConnectionError(
120-
quic_connection
121-
.close_reason()
122-
.expect("QUIC connection is still alive on close-cast")
123-
.into(),
124-
)
124+
ConnectingError::ConnectionError(match quic_connection.close_reason() {
125+
Some(reason) => reason.into(),
126+
None => {
127+
// Connection still alive but error reported.
128+
// This race condition can occur when driver threads are processing
129+
// incoming streams while connection cleanup is triggered.
130+
ConnectionError::LocallyClosed
131+
}
132+
})
125133
}
126134

127135
pub(crate) fn with_connect_error(error: quinn::ConnectError) -> Self {

0 commit comments

Comments
 (0)