Skip to content

fix(webtransport): cancel pending handshakes when frontend closes - #110

Open
soraxas wants to merge 1 commit into
aecsocket:mainfrom
soraxas:fix/cancel-pending-webtransport
Open

soraxas wants to merge 1 commit into
aecsocket:mainfrom
soraxas:fix/cancel-pending-webtransport

Conversation

@soraxas

@soraxas soraxas commented Oct 9, 2026

Copy link
Copy Markdown

Problem

Dropping the client frontend during a WebTransport handshake leaves the connection attempt running until it completes or times out. This can happen when falling back to other transport (eg implement auto fallback from QUIC to websocket).

Fix

Race the handshake against frontend-channel cancellation.

  • On native, cancellation drops the connection future and endpoint.

  • On WASM, a drop guard explicitly closes the pending browser transport, since dropping a Rust future doesn’t cancel a JavaScript promise.

Test

Start a handshake against a silent UDP endpoint, drop the frontend, and require cancellation within 500 ms rather than the configured five-second timeout.

added native-only Tokio dev dependency supports the regression test.

Copilot AI balanced review requested due to automatic review settings October 9, 2026 03:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new regression test builds a native wtransport config without installing a rustls CryptoProvider, so it will panic at runtime instead of validating the cancellation path.

1 open finding
What changed in this PR

This PR fixes a resource/lifecycle issue in the WebTransport client backend: when the client frontend is dropped during an in-progress handshake, the connection attempt previously kept running until it completed or hit the configured timeout (up to five seconds). This matters for use cases like auto-fallback from QUIC to WebSocket, where a quick cancellation is needed. The fix races the handshake against the oneshot sender's cancellation() signal, so dropping the frontend's receiver promptly aborts the attempt. On native, dropping the connecting future cancels the QUIC attempt; on WASM, a PendingWebTransport drop guard explicitly closes the browser transport because dropping a Rust future does not cancel the underlying JS promise.

Changes:

  • Add handshake cancellation by select-ing the connect future against tx_next.cancellation(), returning SessionError::FrontendClosed if the frontend closes first.
  • Introduce a WASM-only PendingWebTransport drop guard that closes the pending transport unless ownership passes to the session.
  • Add a native-only Tokio dev-dependency and a regression test asserting cancellation within 500 ms.
File Description
crates/​aeronet_webtransport/​src/​client/​backend.rs Wraps the connect logic in a future raced against frontend cancellation, adds the WASM drop guard, and adds a regression test.
crates/​aeronet_webtransport/​Cargo.toml Adds a native-only tokio dev-dependency (rt, net, time) for the new test.
Cargo.lock Records the new tokio dependency for aeronet_webtransport.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +138 to +143
let config = ClientConfig::builder()
.with_bind_default()
.with_native_certs()
.max_idle_timeout(Some(Duration::from_secs(5)))
.unwrap()
.build();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants