| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3586,7 +3586,9 @@ class QuicSession { | |||
| 3586 | 3586 | ||
| 3587 | 3587 | if (error) { | |
| 3588 | 3588 | // If the session is still waiting to be closed, and error | |
| 3589 | - // is specified, reject the closed promise. | ||
| 3589 | + // is specified, reject the closed promise. Mark it handled first | ||
| 3590 | + // (as with opened) to silence errors if it's not actually awaited. | ||
| 3591 | + markPromiseAsHandled(inner.pendingClose.promise); | ||
| 3590 | 3592 | inner.pendingClose.reject?.(error); | |
| 3591 | 3593 | } else { | |
| 3592 | 3594 | inner.pendingClose.resolve?.(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,47 @@ | |||
| 1 | + // Flags: --experimental-quic --no-warnings | ||
| 2 | + | ||
| 3 | + // Regression test: destroying a session with an error while its `closed` | ||
| 4 | + // promise is not being observed must NOT surface as an unhandled rejection. | ||
| 5 | + | ||
| 6 | + import { hasQuic, skip, mustCall, mustNotCall } from '../common/index.mjs'; | ||
| 7 | + import { subscribe, unsubscribe } from 'node:diagnostics_channel'; | ||
| 8 | + import { setImmediate as tick } from 'node:timers/promises'; | ||
| 9 | + | ||
| 10 | + if (!hasQuic) { | ||
| 11 | + skip('QUIC is not enabled'); | ||
| 12 | + } | ||
| 13 | + | ||
| 14 | + const { listen, connect } = await import('../common/quic.mjs'); | ||
| 15 | + | ||
| 16 | + // Any unhandled rejection - e.g. an unobserved `closed` rejecting - fails. | ||
| 17 | + process.on('unhandledRejection', mustNotCall('unexpected unhandled rejection')); | ||
| 18 | + | ||
| 19 | + // We use the diagnostics channel to observe the error close without actually | ||
| 20 | + // observing session.closed (not listening is the whole point of the test): | ||
| 21 | + const serverErrored = Promise.withResolvers(); | ||
| 22 | + function onSessionError() { | ||
| 23 | + unsubscribe('quic.session.error', onSessionError); | ||
| 24 | + serverErrored.resolve(); | ||
| 25 | + } | ||
| 26 | + subscribe('quic.session.error', onSessionError); | ||
| 27 | + | ||
| 28 | + // The server session callback is left deliberately empty, so no response | ||
| 29 | + // is sent and closed remains unobserved: | ||
| 30 | + const serverEndpoint = await listen(mustCall()); | ||
| 31 | + | ||
| 32 | + const clientSession = await connect(serverEndpoint.address); | ||
| 33 | + await clientSession.opened; | ||
| 34 | + | ||
| 35 | + // Finish handshake before close: | ||
| 36 | + await tick(); | ||
| 37 | + | ||
| 38 | + // Cleanly close from the client with an error code, so the server | ||
| 39 | + // receives a peer error close: | ||
| 40 | + await clientSession.close({ code: 1 }); | ||
| 41 | + | ||
| 42 | + // Wait until the server has processed the error close, plus another tick | ||
| 43 | + // to ensure unobserved promise rejection doesn't fire anywhere: | ||
| 44 | + await serverErrored.promise; | ||
| 45 | + await tick(); | ||
| 46 | + | ||
| 47 | + await serverEndpoint.close(); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments