net: autoDestroy Socket
Refactors net.Socket into using autoDestroy functionality of streams. PR-URL: https://github.com/nodejs/node/pull/31806 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Denys Otrishko <shishugi@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This commit is contained in:
parent
882b61a7ee
commit
efefdd668d
36
lib/net.js
36
lib/net.js
@ -285,20 +285,15 @@ function Socket(options) {
|
|||||||
else
|
else
|
||||||
options = { ...options };
|
options = { ...options };
|
||||||
|
|
||||||
const { allowHalfOpen } = options;
|
// Default to *not* allowing half open sockets.
|
||||||
|
options.allowHalfOpen = Boolean(options.allowHalfOpen);
|
||||||
// Prevent the "no-half-open enforcer" from being inherited from `Duplex`.
|
|
||||||
options.allowHalfOpen = true;
|
|
||||||
// For backwards compat do not emit close on destroy.
|
// For backwards compat do not emit close on destroy.
|
||||||
options.emitClose = false;
|
options.emitClose = false;
|
||||||
options.autoDestroy = false;
|
options.autoDestroy = true;
|
||||||
// Handle strings directly.
|
// Handle strings directly.
|
||||||
options.decodeStrings = false;
|
options.decodeStrings = false;
|
||||||
stream.Duplex.call(this, options);
|
stream.Duplex.call(this, options);
|
||||||
|
|
||||||
// Default to *not* allowing half open sockets.
|
|
||||||
this.allowHalfOpen = Boolean(allowHalfOpen);
|
|
||||||
|
|
||||||
if (options.handle) {
|
if (options.handle) {
|
||||||
this._handle = options.handle; // private
|
this._handle = options.handle; // private
|
||||||
this[async_id_symbol] = getNewAsyncId(this._handle);
|
this[async_id_symbol] = getNewAsyncId(this._handle);
|
||||||
@ -416,28 +411,18 @@ Socket.prototype._final = function(cb) {
|
|||||||
const err = this._handle.shutdown(req);
|
const err = this._handle.shutdown(req);
|
||||||
|
|
||||||
if (err === 1 || err === UV_ENOTCONN) // synchronous finish
|
if (err === 1 || err === UV_ENOTCONN) // synchronous finish
|
||||||
return afterShutdown.call(req, 0);
|
return cb();
|
||||||
else if (err !== 0)
|
else if (err !== 0)
|
||||||
return this.destroy(errnoException(err, 'shutdown'));
|
return cb(errnoException(err, 'shutdown'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function afterShutdown() {
|
||||||
function afterShutdown(status) {
|
|
||||||
const self = this.handle[owner_symbol];
|
const self = this.handle[owner_symbol];
|
||||||
|
|
||||||
debug('afterShutdown destroyed=%j', self.destroyed,
|
debug('afterShutdown destroyed=%j', self.destroyed,
|
||||||
self._readableState);
|
self._readableState);
|
||||||
|
|
||||||
this.callback();
|
this.callback();
|
||||||
|
|
||||||
// Callback may come after call to destroy.
|
|
||||||
if (self.destroyed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!self.readable || self.readableEnded) {
|
|
||||||
debug('readableState ended, destroying');
|
|
||||||
self.destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide a better error message when we call end() as a result
|
// Provide a better error message when we call end() as a result
|
||||||
@ -452,10 +437,10 @@ function writeAfterFIN(chunk, encoding, cb) {
|
|||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
const er = new Error('This socket has been ended by the other party');
|
const er = new Error('This socket has been ended by the other party');
|
||||||
er.code = 'EPIPE';
|
er.code = 'EPIPE';
|
||||||
process.nextTick(emitErrorNT, this, er);
|
|
||||||
if (typeof cb === 'function') {
|
if (typeof cb === 'function') {
|
||||||
defaultTriggerAsyncIdScope(this[async_id_symbol], process.nextTick, cb, er);
|
defaultTriggerAsyncIdScope(this[async_id_symbol], process.nextTick, cb, er);
|
||||||
}
|
}
|
||||||
|
this.destroy(er);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -628,12 +613,7 @@ Socket.prototype.read = function(n) {
|
|||||||
function onReadableStreamEnd() {
|
function onReadableStreamEnd() {
|
||||||
if (!this.allowHalfOpen) {
|
if (!this.allowHalfOpen) {
|
||||||
this.write = writeAfterFIN;
|
this.write = writeAfterFIN;
|
||||||
if (this.writable)
|
}
|
||||||
this.end();
|
|
||||||
else if (!this.writableLength)
|
|
||||||
this.destroy();
|
|
||||||
} else if (!this.destroyed && !this.writable && !this.writableLength)
|
|
||||||
this.destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +23,10 @@ server.on('stream', (stream) => {
|
|||||||
|
|
||||||
server.listen(0, () => {
|
server.listen(0, () => {
|
||||||
const h2header = Buffer.alloc(9);
|
const h2header = Buffer.alloc(9);
|
||||||
const conn = net.connect(server.address().port);
|
const conn = net.connect({
|
||||||
|
port: server.address().port,
|
||||||
|
allowHalfOpen: true
|
||||||
|
});
|
||||||
|
|
||||||
conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n');
|
conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n');
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
|
|
||||||
@ -31,10 +32,7 @@ const server = net.createServer(common.mustCall(function(socket) {
|
|||||||
|
|
||||||
socket.resume();
|
socket.resume();
|
||||||
|
|
||||||
socket.on('error', common.mustCall(function(error) {
|
socket.on('error', common.mustNotCall());
|
||||||
console.error('received error as expected, closing server', error);
|
|
||||||
server.close();
|
|
||||||
}));
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
server.listen(0, function() {
|
server.listen(0, function() {
|
||||||
@ -44,7 +42,10 @@ server.listen(0, function() {
|
|||||||
// Then 'end' will be emitted when it receives a FIN packet from
|
// Then 'end' will be emitted when it receives a FIN packet from
|
||||||
// the other side.
|
// the other side.
|
||||||
client.on('end', common.mustCall(() => {
|
client.on('end', common.mustCall(() => {
|
||||||
serverSocket.write('test', common.mustCall());
|
serverSocket.write('test', common.mustCall((err) => {
|
||||||
|
assert(err);
|
||||||
|
server.close();
|
||||||
|
}));
|
||||||
}));
|
}));
|
||||||
client.end();
|
client.end();
|
||||||
});
|
});
|
||||||
|
@ -34,7 +34,8 @@ const server = tls.createServer(serverConfig, common.mustCall(function() {
|
|||||||
secureProtocol: v.secureProtocol
|
secureProtocol: v.secureProtocol
|
||||||
}, common.mustCall(function() {
|
}, common.mustCall(function() {
|
||||||
assert.strictEqual(this.getProtocol(), v.version);
|
assert.strictEqual(this.getProtocol(), v.version);
|
||||||
this.on('end', common.mustCall(function() {
|
this.on('end', common.mustCall());
|
||||||
|
this.on('close', common.mustCall(function() {
|
||||||
assert.strictEqual(this.getProtocol(), null);
|
assert.strictEqual(this.getProtocol(), null);
|
||||||
})).end();
|
})).end();
|
||||||
if (++connected === clientConfigs.length)
|
if (++connected === clientConfigs.length)
|
||||||
|
@ -59,9 +59,8 @@ const net = require('net');
|
|||||||
assert.strictEqual(client.bufferSize, i + 1);
|
assert.strictEqual(client.bufferSize, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It seems that tlsSockets created from sockets of `Duplex` emit no
|
client.on('end', common.mustCall());
|
||||||
// "finish" events. We use "end" event instead.
|
client.on('close', common.mustCall(() => {
|
||||||
client.on('end', common.mustCall(() => {
|
|
||||||
assert.strictEqual(client.bufferSize, undefined);
|
assert.strictEqual(client.bufferSize, undefined);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user