Skip to content

Commit 2da3611

Browse files
ronagjasnell
authored andcommitted
net: add support for finished after .destroy()
Calling `finished(socket, cb)` would previously not invoked the callback if the socket was already detroyed. PR-URL: #36635 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Rich Trott <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 64a4001 commit 2da3611

File tree

4 files changed

+48
-7
lines changed

4 files changed

+48
-7
lines changed

lib/_http_incoming.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,8 @@ IncomingMessage.prototype._destroy = function _destroy(err, cb) {
174174
this.emit('aborted');
175175
}
176176

177-
// If aborted and the underlying socket is not already destroyed,
178-
// destroy it.
179-
// We have to check if the socket is already destroyed because finished
180-
// does not call the callback when this methdod is invoked from `_http_client`
181-
// in `test/parallel/test-http-client-spurious-aborted.js`
182-
if (this.socket && !this.socket.destroyed && this.aborted) {
177+
// If aborted destroy socket.
178+
if (this.socket && this.aborted) {
183179
this.socket.destroy(err);
184180
const cleanup = finished(this.socket, (e) => {
185181
cleanup();

lib/internal/streams/end-of-stream.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ const {
99
} = require('internal/errors').codes;
1010
const { once } = require('internal/util');
1111

12+
function isSocket(stream) {
13+
return (
14+
typeof stream.connect === 'function' &&
15+
typeof stream.setNoDelay === 'function' &&
16+
typeof stream.setKeepAlive === 'function'
17+
);
18+
}
19+
1220
function isRequest(stream) {
1321
return stream.setHeader && typeof stream.abort === 'function';
1422
}
@@ -75,7 +83,7 @@ function eos(stream, options, callback) {
7583
let willEmitClose = (
7684
state &&
7785
state.autoDestroy &&
78-
state.emitClose &&
86+
(state.emitClose || isSocket(stream)) &&
7987
state.closed === false &&
8088
isReadable(stream) === readable &&
8189
isWritable(stream) === writable

lib/net.js

+12
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,12 @@ Socket.prototype._destroy = function(exception, cb) {
664664

665665
this._handle.close(() => {
666666
debug('emit close');
667+
if (this._writableState) {
668+
this._writableState.closed = true;
669+
}
670+
if (this._readableState) {
671+
this._readableState.closed = true;
672+
}
667673
this.emit('close', isException);
668674
});
669675
this._handle.onread = noop;
@@ -1651,6 +1657,12 @@ Server.prototype._emitCloseIfDrained = function() {
16511657

16521658
function emitCloseNT(self) {
16531659
debug('SERVER: emit close');
1660+
if (self._writableState) {
1661+
self._writableState.closed = true;
1662+
}
1663+
if (self._readableState) {
1664+
self._readableState.closed = true;
1665+
}
16541666
self.emit('close');
16551667
}
16561668

test/parallel/test-net-finished.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
const common = require('../common');
3+
const net = require('net');
4+
const { finished } = require('stream');
5+
6+
const server = net.createServer(function(con) {
7+
con.on('close', common.mustCall());
8+
});
9+
10+
server.listen(0, common.mustCall(function() {
11+
const con = net.connect({
12+
port: this.address().port
13+
})
14+
.on('connect', () => {
15+
finished(con, common.mustCall());
16+
con.destroy();
17+
finished(con, common.mustCall());
18+
con.on('close', common.mustCall(() => {
19+
finished(con, common.mustCall(() => {
20+
server.close();
21+
}));
22+
}));
23+
})
24+
.end();
25+
}));

0 commit comments

Comments
 (0)