Skip to content

Commit fd6af98

Browse files
jscissrmcollina
authored andcommitted
net: refactor Server.prototype.listen
This PR simplifies Server.prototype.listen, removing some redundancy and inconsistency. Because listen and connect have a similar function signature, normalizeConnectArgs can be reused for listen. listenAfterLookup renamed to lookupAndListen for consistency with lookupAndConnect, and moved out of Server.prototype.listen. PR-URL: #4039 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Glen Keane <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent 1ffdbb6 commit fd6af98

File tree

3 files changed

+98
-92
lines changed

3 files changed

+98
-92
lines changed

lib/_tls_wrap.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ function SNICallback(servername, callback) {
952952
//
953953
//
954954
function normalizeConnectArgs(listArgs) {
955-
var args = net._normalizeConnectArgs(listArgs);
955+
var args = net._normalizeArgs(listArgs);
956956
var options = args[0];
957957
var cb = args[1];
958958

lib/net.js

Lines changed: 58 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,16 @@ exports.connect = exports.createConnection = function() {
6363
var args = new Array(arguments.length);
6464
for (var i = 0; i < arguments.length; i++)
6565
args[i] = arguments[i];
66-
args = normalizeConnectArgs(args);
66+
args = normalizeArgs(args);
6767
debug('createConnection', args);
6868
var s = new Socket(args[0]);
6969
return Socket.prototype.connect.apply(s, args);
7070
};
7171

72-
// Returns an array [options] or [options, cb]
72+
// Returns an array [options, cb], where cb can be null.
7373
// It is the same as the argument of Socket.prototype.connect().
74-
function normalizeConnectArgs(args) {
74+
// This is used by Server.prototype.listen() and Socket.prototype.connect().
75+
function normalizeArgs(args) {
7576
var options = {};
7677

7778
if (args.length === 0) {
@@ -91,9 +92,11 @@ function normalizeConnectArgs(args) {
9192
}
9293

9394
var cb = args[args.length - 1];
94-
return typeof cb === 'function' ? [options, cb] : [options];
95+
if (typeof cb !== 'function')
96+
cb = null;
97+
return [options, cb];
9598
}
96-
exports._normalizeConnectArgs = normalizeConnectArgs;
99+
exports._normalizeArgs = normalizeArgs;
97100

98101

99102
// called when creating new Socket, or when re-using a closed Socket
@@ -888,7 +891,7 @@ Socket.prototype.connect = function(options, cb) {
888891
var args = new Array(arguments.length);
889892
for (var i = 0; i < arguments.length; i++)
890893
args[i] = arguments[i];
891-
args = normalizeConnectArgs(args);
894+
args = normalizeArgs(args);
892895
return Socket.prototype.connect.apply(this, args);
893896
}
894897

@@ -1325,84 +1328,70 @@ function listen(self, address, port, addressType, backlog, fd, exclusive) {
13251328

13261329

13271330
Server.prototype.listen = function() {
1328-
var self = this;
1331+
var args = new Array(arguments.length);
1332+
for (var i = 0; i < arguments.length; i++)
1333+
args[i] = arguments[i];
1334+
var [options, cb] = normalizeArgs(args);
13291335

1330-
var lastArg = arguments[arguments.length - 1];
1331-
if (typeof lastArg === 'function') {
1332-
self.once('listening', lastArg);
1336+
if (typeof cb === 'function') {
1337+
this.once('listening', cb);
13331338
}
13341339

1335-
var port = toNumber(arguments[0]);
1340+
if (args.length === 0 || typeof args[0] === 'function') {
1341+
// Bind to a random port.
1342+
options.port = 0;
1343+
}
13361344

13371345
// The third optional argument is the backlog size.
13381346
// When the ip is omitted it can be the second argument.
1339-
var backlog = toNumber(arguments[1]) || toNumber(arguments[2]);
1347+
var backlog = toNumber(args.length > 1 && args[1]) ||
1348+
toNumber(args.length > 2 && args[2]);
13401349

1341-
if (arguments.length === 0 || typeof arguments[0] === 'function') {
1342-
// Bind to a random port.
1343-
listen(self, null, 0, null, backlog);
1344-
} else if (arguments[0] !== null && typeof arguments[0] === 'object') {
1345-
var h = arguments[0];
1346-
h = h._handle || h.handle || h;
1347-
1348-
if (h instanceof TCP) {
1349-
self._handle = h;
1350-
listen(self, null, -1, -1, backlog);
1351-
} else if (typeof h.fd === 'number' && h.fd >= 0) {
1352-
listen(self, null, null, null, backlog, h.fd);
1353-
} else {
1354-
// The first argument is a configuration object
1355-
if (h.backlog)
1356-
backlog = h.backlog;
1357-
1358-
if (typeof h.port === 'number' || typeof h.port === 'string' ||
1359-
(typeof h.port === 'undefined' && 'port' in h)) {
1360-
// Undefined is interpreted as zero (random port) for consistency
1361-
// with net.connect().
1362-
assertPort(h.port);
1363-
if (h.host)
1364-
listenAfterLookup(h.port | 0, h.host, backlog, h.exclusive);
1365-
else
1366-
listen(self, null, h.port | 0, 4, backlog, undefined, h.exclusive);
1367-
} else if (h.path && isPipeName(h.path)) {
1368-
const pipeName = self._pipeName = h.path;
1369-
listen(self, pipeName, -1, -1, backlog, undefined, h.exclusive);
1370-
} else {
1371-
throw new Error('Invalid listen argument: ' + h);
1372-
}
1373-
}
1374-
} else if (isPipeName(arguments[0])) {
1375-
// UNIX socket or Windows pipe.
1376-
const pipeName = self._pipeName = arguments[0];
1377-
listen(self, pipeName, -1, -1, backlog);
1378-
1379-
} else if (arguments[1] === undefined ||
1380-
typeof arguments[1] === 'function' ||
1381-
typeof arguments[1] === 'number') {
1382-
// The first argument is the port, no IP given.
1383-
assertPort(port);
1384-
listen(self, null, port, 4, backlog);
1350+
options = options._handle || options.handle || options;
13851351

1352+
if (options instanceof TCP) {
1353+
this._handle = options;
1354+
listen(this, null, -1, -1, backlog);
1355+
} else if (typeof options.fd === 'number' && options.fd >= 0) {
1356+
listen(this, null, null, null, backlog, options.fd);
13861357
} else {
1387-
// The first argument is the port, the second an IP.
1388-
assertPort(port);
1389-
listenAfterLookup(port, arguments[1], backlog);
1390-
}
1391-
1392-
function listenAfterLookup(port, address, backlog, exclusive) {
1393-
require('dns').lookup(address, function(err, ip, addressType) {
1394-
if (err) {
1395-
self.emit('error', err);
1358+
backlog = options.backlog || backlog;
1359+
1360+
if (typeof options.port === 'number' || typeof options.port === 'string' ||
1361+
(typeof options.port === 'undefined' && 'port' in options)) {
1362+
// Undefined is interpreted as zero (random port) for consistency
1363+
// with net.connect().
1364+
assertPort(options.port);
1365+
if (options.host) {
1366+
lookupAndListen(this, options.port | 0, options.host, backlog,
1367+
options.exclusive);
13961368
} else {
1397-
addressType = ip ? addressType : 4;
1398-
listen(self, ip, port, addressType, backlog, undefined, exclusive);
1369+
listen(this, null, options.port | 0, 4, backlog, undefined,
1370+
options.exclusive);
13991371
}
1400-
});
1372+
} else if (options.path && isPipeName(options.path)) {
1373+
// UNIX socket or Windows pipe.
1374+
const pipeName = this._pipeName = options.path;
1375+
listen(this, pipeName, -1, -1, backlog, undefined, options.exclusive);
1376+
} else {
1377+
throw new Error('Invalid listen argument: ' + options);
1378+
}
14011379
}
14021380

1403-
return self;
1381+
return this;
14041382
};
14051383

1384+
function lookupAndListen(self, port, address, backlog, exclusive) {
1385+
require('dns').lookup(address, function(err, ip, addressType) {
1386+
if (err) {
1387+
self.emit('error', err);
1388+
} else {
1389+
addressType = ip ? addressType : 4;
1390+
listen(self, ip, port, addressType, backlog, undefined, exclusive);
1391+
}
1392+
});
1393+
}
1394+
14061395
Object.defineProperty(Server.prototype, 'listening', {
14071396
get: function() {
14081397
return !!this._handle;
Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,45 @@
11
'use strict';
2-
var common = require('../common');
3-
var assert = require('assert');
4-
var net = require('net');
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const net = require('net');
55

66
function close() { this.close(); }
7-
net.Server().listen({ port: undefined }, close);
8-
net.Server().listen({ port: '' + common.PORT }, close);
97

10-
[ 'nan',
11-
-1,
12-
123.456,
13-
0x10000,
14-
1 / 0,
15-
-1 / 0,
16-
'+Infinity',
17-
'-Infinity'
18-
].forEach(function(port) {
19-
assert.throws(function() {
20-
net.Server().listen({ port: port }, common.fail);
21-
}, /"port" argument must be >= 0 and < 65536/i);
22-
});
8+
// From lib/net.js
9+
function toNumber(x) { return (x = Number(x)) >= 0 ? x : false; }
10+
11+
function isPipeName(s) {
12+
return typeof s === 'string' && toNumber(s) === false;
13+
}
14+
15+
const listenVariants = [
16+
(port, cb) => net.Server().listen({port}, cb),
17+
(port, cb) => net.Server().listen(port, cb)
18+
];
19+
20+
listenVariants.forEach((listenVariant, i) => {
21+
listenVariant(undefined, common.mustCall(close));
22+
listenVariant('0', common.mustCall(close));
23+
24+
[
25+
'nan',
26+
-1,
27+
123.456,
28+
0x10000,
29+
1 / 0,
30+
-1 / 0,
31+
'+Infinity',
32+
'-Infinity'
33+
].forEach((port) => {
34+
if (i === 1 && isPipeName(port)) {
35+
// skip this, because listen(port) can also be listen(path)
36+
return;
37+
}
38+
assert.throws(() => listenVariant(port, common.fail),
39+
/"port" argument must be >= 0 and < 65536/i);
40+
});
2341

24-
[null, true, false].forEach(function(port) {
25-
assert.throws(function() {
26-
net.Server().listen({ port: port }, common.fail);
27-
}, /invalid listen argument/i);
42+
[null, true, false].forEach((port) =>
43+
assert.throws(() => listenVariant(port, common.fail),
44+
/invalid listen argument/i));
2845
});

0 commit comments

Comments
 (0)