GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — quic: add QuicEndpoint.listening & QuicStream.destroy() and tests · nodejs/node@f697c55

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • doc/api
    • quic.md
  • lib/internal/quic
    • quic.js
  • test/parallel
    • test-quic-session-stream-lifecycle.mjs
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/quic.md‎

Copy file name to clipboardExpand all lines: doc/api/quic.md
+6Lines changed: 6 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ added: v23.8.0
204204

205205
True if `endpoint.destroy()` has been called. Read only.
206206

207+
### `endpoint.listening`
208+
209+
* Type: {boolean}
210+
211+
True if the endpoint is actively listening for incoming connections. Read only.
212+
207213
### `endpoint.setSNIContexts(entries[, options])`
208214

209215
<!-- YAML
Collapse file

‎lib/internal/quic/quic.js‎

Copy file name to clipboardExpand all lines: lib/internal/quic/quic.js
+27-2Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,25 @@ class QuicStream {
720720
}
721721

722722
/**
723-
* @param {ArrayBuffer|ArrayBufferView|Blob} outbound
723+
* Immediately destroys the stream. Any queued data is discarded. If an
724+
* error is given, the closed promise will be rejected with that error.
725+
* If no error is given, the closed promise will be resolved.
726+
* @param {any} error
727+
*/
728+
destroy(error) {
729+
if (this.destroyed) return;
730+
const handle = this.#handle;
731+
this[kFinishClose](error);
732+
handle.destroy();
733+
}
734+
735+
/**
736+
* Sets the outbound data source for the stream. This can only be called
737+
* once and must be called before any data will be sent. The body can be
738+
* an ArrayBuffer, a TypedArray or DataView, or a Blob. If the stream
739+
* is destroyed or already has an outbound data source, an error will
740+
* be thrown.
741+
* @param {ArrayBuffer|SharedArrayBuffer|ArrayBufferView|Blob} outbound
724742
*/
725743
setOutbound(outbound) {
726744
if (this.destroyed) {
@@ -1748,7 +1766,14 @@ class QuicEndpoint {
17481766
get closing() { return this.#isPendingClose; }
17491767

17501768
/** @type {boolean} */
1751-
get destroyed() { return this.#handle === undefined; }
1769+
get listening() {
1770+
return this.#listening;
1771+
}
1772+
1773+
/** @type {boolean} */
1774+
get destroyed() {
1775+
return this.#handle === undefined;
1776+
}
17521777

17531778
/**
17541779
* Forcefully terminates the endpoint by immediately destroying all sessions
Collapse file

‎test/parallel/test-quic-session-stream-lifecycle.mjs‎

Copy file name to clipboard
+98Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Flags: --experimental-quic --no-warnings
2+
3+
import { hasQuic, skip, mustCall } from '../common/index.mjs';
4+
import assert from 'node:assert';
5+
import * as fixtures from '../common/fixtures.mjs';
6+
7+
if (!hasQuic) {
8+
skip('QUIC is not enabled');
9+
}
10+
11+
// Import after the hasQuic check
12+
const quic = await import('node:quic');
13+
const { createPrivateKey } = await import('node:crypto');
14+
15+
const keys = createPrivateKey(fixtures.readKey('agent1-key.pem'));
16+
const certs = fixtures.readKey('agent1-cert.pem');
17+
18+
const serverDone = Promise.withResolvers();
19+
const clientDone = Promise.withResolvers();
20+
21+
// Create a server endpoint
22+
const serverEndpoint = await quic.listen(mustCall((serverSession) => {
23+
serverSession.opened.then((info) => {
24+
assert.ok(serverSession.endpoint !== null);
25+
assert.strictEqual(serverSession.destroyed, false);
26+
27+
const stats = serverSession.stats;
28+
assert.strictEqual(stats.isConnected, true);
29+
assert.ok(stats.handshakeCompletedAt > 0n);
30+
assert.ok(stats.handshakeConfirmedAt > 0n);
31+
assert.strictEqual(stats.closingAt, 0n);
32+
33+
serverDone.resolve();
34+
serverSession.close();
35+
}).then(mustCall());
36+
}), { sni: { '*': { keys, certs } } });
37+
38+
assert.strictEqual(serverEndpoint.busy, false);
39+
assert.strictEqual(serverEndpoint.closing, false);
40+
assert.strictEqual(serverEndpoint.destroyed, false);
41+
assert.strictEqual(serverEndpoint.listening, true);
42+
43+
assert.ok(serverEndpoint.address !== undefined);
44+
assert.strictEqual(serverEndpoint.address.family, 'ipv4');
45+
assert.strictEqual(serverEndpoint.address.address, '127.0.0.1');
46+
assert.ok(typeof serverEndpoint.address.port === 'number');
47+
assert.ok(serverEndpoint.address.port > 0);
48+
49+
const epStats = serverEndpoint.stats;
50+
assert.strictEqual(epStats.isConnected, true);
51+
assert.ok(epStats.createdAt > 0n);
52+
53+
// Connect with a client
54+
const clientSession = await quic.connect(serverEndpoint.address);
55+
56+
assert.strictEqual(clientSession.destroyed, false);
57+
assert.ok(clientSession.endpoint !== null);
58+
assert.strictEqual(clientSession.stats.isConnected, true);
59+
60+
clientSession.opened.then((clientInfo) => {
61+
assert.strictEqual(clientInfo.servername, 'localhost');
62+
assert.strictEqual(clientInfo.protocol, 'h3');
63+
assert.strictEqual(clientInfo.cipherVersion, 'TLSv1.3');
64+
assert.ok(clientInfo.local !== undefined);
65+
assert.ok(clientInfo.remote !== undefined);
66+
67+
const cStats = clientSession.stats;
68+
assert.strictEqual(cStats.isConnected, true);
69+
assert.ok(cStats.handshakeCompletedAt > 0n);
70+
assert.ok(cStats.bytesSent > 0n, 'Expected bytesSent > 0 after handshake');
71+
72+
clientDone.resolve();
73+
}).then(mustCall());
74+
75+
await Promise.all([serverDone.promise, clientDone.promise]);
76+
77+
// Open a bidirectional stream.
78+
const stream = await clientSession.createBidirectionalStream();
79+
80+
assert.strictEqual(stream.destroyed, false);
81+
assert.strictEqual(stream.direction, 'bidi');
82+
assert.strictEqual(stream.session, clientSession);
83+
assert.ok(stream.id !== null, 'Non-pending stream should have an id');
84+
assert.strictEqual(typeof stream.id, 'bigint');
85+
assert.strictEqual(stream.pending, false);
86+
assert.strictEqual(stream.stats.isConnected, true);
87+
assert.ok(stream.readable instanceof ReadableStream);
88+
89+
// Destroying the session should destroy it and the stream, and clear its properties.
90+
clientSession.destroy();
91+
assert.strictEqual(clientSession.destroyed, true);
92+
assert.strictEqual(clientSession.endpoint, null);
93+
assert.strictEqual(clientSession.stats.isConnected, false);
94+
95+
assert.strictEqual(stream.destroyed, true);
96+
assert.strictEqual(stream.session, null);
97+
assert.strictEqual(stream.id, null);
98+
assert.strictEqual(stream.direction, null);

0 commit comments

Comments
0 (0)
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.