GeezerVison is showing github.com — net: support abortSignal in server.listen · nodejs/node@02dbcc4
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/net.md +18Lines changed: 18 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -324,6 +324,9 @@ Listening on a file descriptor is not supported on Windows. | 324 | 324 | <!-- YAML | 325 | 325 | added: v0.11.14 | 326 | 326 | changes: | | 327 | + - version: REPLACEME | | 328 | + pr-url: https://github.com/nodejs/node/pull/36623 | | 329 | + description: AbortSignal support was added. | 327 | 330 | - version: v11.4.0 | 328 | 331 | pr-url: https://github.com/nodejs/node/pull/23798 | 329 | 332 | description: The `ipv6Only` option is supported. | @@ -344,6 +347,7 @@ changes: | 344 | 347 | * `ipv6Only` {boolean} For TCP servers, setting `ipv6Only` to `true` will | 345 | 348 | disable dual-stack support, i.e., binding to host `::` won't make | 346 | 349 | `0.0.0.0` be bound. **Default:** `false`. | | 350 | + * `signal` {AbortSignal} An AbortSignal that may be used to close a listening server. | 347 | 351 | * `callback` {Function} | 348 | 352 | functions. | 349 | 353 | * Returns: {net.Server} | @@ -375,6 +379,20 @@ Starting an IPC server as root may cause the server path to be inaccessible for | 375 | 379 | unprivileged users. Using `readableAll` and `writableAll` will make the server | 376 | 380 | accessible for all users. | 377 | 381 |
| | 382 | +If the `signal` option is enabled, calling `.abort()` on the corresponding | | 383 | +`AbortController` is similar to calling `.close()` on the server: | | 384 | + | | 385 | +```js | | 386 | +const controller = new AbortController(); | | 387 | +server.listen({ | | 388 | + host: 'localhost', | | 389 | + port: 80, | | 390 | + signal: controller.signal | | 391 | +}); | | 392 | +// Later, when you want to close the server. | | 393 | +controller.abort(); | | 394 | +``` | | 395 | + | 378 | 396 | #### `server.listen(path[, backlog][, callback])` | 379 | 397 | <!-- YAML | 380 | 398 | added: v0.1.90 | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/streams/add-abort-signal.js +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -9,7 +9,7 @@ const eos = require('internal/streams/end-of-stream'); | 9 | 9 | const { ERR_INVALID_ARG_TYPE } = codes; | 10 | 10 |
| 11 | 11 | // This method is inlined here for readable-stream | 12 | | -// It also does not allow for signal to not exist on the steam | | 12 | +// It also does not allow for signal to not exist on the stream | 13 | 13 | // https://github.com/nodejs/node/pull/36061#discussion_r533718029 | 14 | 14 | const validateAbortSignal = (signal, name) => { | 15 | 15 | if (typeof signal !== 'object' || | |
Collapse file Copy file name to clipboardExpand all lines: lib/net.js +18Lines changed: 18 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -109,6 +109,7 @@ const { | 109 | 109 | } = require('internal/errors'); | 110 | 110 | const { isUint8Array } = require('internal/util/types'); | 111 | 111 | const { | | 112 | + validateAbortSignal, | 112 | 113 | validateInt32, | 113 | 114 | validatePort, | 114 | 115 | validateString | @@ -1148,6 +1149,22 @@ function afterConnect(status, handle, req, readable, writable) { | 1148 | 1149 | } | 1149 | 1150 | } | 1150 | 1151 |
| | 1152 | +function addAbortSignalOption(self, options) { | | 1153 | + if (options?.signal === undefined) { | | 1154 | + return; | | 1155 | + } | | 1156 | + validateAbortSignal(options.signal, 'options.signal'); | | 1157 | + const { signal } = options; | | 1158 | + const onAborted = () => { | | 1159 | + self.close(); | | 1160 | + }; | | 1161 | + if (signal.aborted) { | | 1162 | + process.nextTick(onAborted); | | 1163 | + } else { | | 1164 | + signal.addEventListener('abort', onAborted); | | 1165 | + self.once('close', () => signal.removeEventListener('abort', onAborted)); | | 1166 | + } | | 1167 | +} | 1151 | 1168 |
| 1152 | 1169 | function Server(options, connectionListener) { | 1153 | 1170 | if (!(this instanceof Server)) | @@ -1398,6 +1415,7 @@ Server.prototype.listen = function(...args) { | 1398 | 1415 | listenInCluster(this, null, -1, -1, backlogFromArgs); | 1399 | 1416 | return this; | 1400 | 1417 | } | | 1418 | + addAbortSignalOption(this, options); | 1401 | 1419 | // (handle[, backlog][, cb]) where handle is an object with a fd | 1402 | 1420 | if (typeof options.fd === 'number' && options.fd >= 0) { | 1403 | 1421 | listenInCluster(this, null, null, null, backlogFromArgs, options.fd); | |
Collapse file Copy file name to clipboard +33Lines changed: 33 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | +const common = require('../common'); | | 3 | +const assert = require('assert'); | | 4 | +const net = require('net'); | | 5 | + | | 6 | +{ | | 7 | + // Test bad signal. | | 8 | + const server = net.createServer(); | | 9 | + assert.throws( | | 10 | + () => server.listen({ port: 0, signal: 'INVALID_SIGNAL' }), | | 11 | + { | | 12 | + code: 'ERR_INVALID_ARG_TYPE', | | 13 | + name: 'TypeError' | | 14 | + }); | | 15 | +} | | 16 | + | | 17 | +{ | | 18 | + // Test close. | | 19 | + const server = net.createServer(); | | 20 | + const controller = new AbortController(); | | 21 | + server.on('close', common.mustCall()); | | 22 | + server.listen({ port: 0, signal: controller.signal }); | | 23 | + controller.abort(); | | 24 | +} | | 25 | + | | 26 | +{ | | 27 | + // Test close with pre-aborted signal. | | 28 | + const server = net.createServer(); | | 29 | + const controller = new AbortController(); | | 30 | + controller.abort(); | | 31 | + server.on('close', common.mustCall()); | | 32 | + server.listen({ port: 0, signal: controller.signal }); | | 33 | +} |
|