Skip to content

Commit 4e2e7d1

Browse files
lainojoyeecheung
laino
authored andcommitted
cluster: resolve relative unix socket paths
Relative unix sockets paths were previously interpreted relative to the master's CWD, which was inconsistent with non-cluster behavior. A test case has been added as well. PR-URL: #16749 Fixes: #16387 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent f878f94 commit 4e2e7d1

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

lib/internal/cluster/child.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22
const assert = require('assert');
33
const util = require('util');
4+
const path = require('path');
45
const EventEmitter = require('events');
56
const Worker = require('internal/cluster/worker');
67
const { internal, sendHelper } = require('internal/cluster/utils');
@@ -48,7 +49,14 @@ cluster._setupWorker = function() {
4849

4950
// obj is a net#Server or a dgram#Socket object.
5051
cluster._getServer = function(obj, options, cb) {
51-
const indexesKey = [options.address,
52+
let address = options.address;
53+
54+
// Resolve unix socket paths to absolute paths
55+
if (options.port < 0 && typeof address === 'string' &&
56+
process.platform !== 'win32')
57+
address = path.resolve(address);
58+
59+
const indexesKey = [address,
5260
options.port,
5361
options.addressType,
5462
options.fd ].join(':');
@@ -64,6 +72,8 @@ cluster._getServer = function(obj, options, cb) {
6472
data: null
6573
}, options);
6674

75+
message.address = address;
76+
6777
// Set custom data on handle (i.e. tls tickets key)
6878
if (obj._getServerData)
6979
message.data = obj._getServerData();

lib/internal/cluster/master.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
const assert = require('assert');
33
const { fork } = require('child_process');
44
const util = require('util');
5+
const path = require('path');
56
const EventEmitter = require('events');
67
const RoundRobinHandle = require('internal/cluster/round_robin_handle');
78
const SharedHandle = require('internal/cluster/shared_handle');
@@ -276,6 +277,18 @@ function queryServer(worker, message) {
276277
var handle = handles[key];
277278

278279
if (handle === undefined) {
280+
let address = message.address;
281+
282+
// Find shortest path for unix sockets because of the ~100 byte limit
283+
if (message.port < 0 && typeof address === 'string' &&
284+
process.platform !== 'win32') {
285+
286+
address = path.relative(process.cwd(), address);
287+
288+
if (message.address.length < address.length)
289+
address = message.address;
290+
}
291+
279292
var constructor = RoundRobinHandle;
280293
// UDP is exempt from round-robin connection balancing for what should
281294
// be obvious reasons: it's connectionless. There is nothing to send to
@@ -287,7 +300,7 @@ function queryServer(worker, message) {
287300
}
288301

289302
handles[key] = handle = new constructor(key,
290-
message.address,
303+
address,
291304
message.port,
292305
message.addressType,
293306
message.fd,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cluster = require('cluster');
5+
const net = require('net');
6+
const path = require('path');
7+
const fs = require('fs');
8+
9+
if (common.isWindows)
10+
common.skip('On Windows named pipes live in their own ' +
11+
'filesystem and don\'t have a ~100 byte limit');
12+
13+
// Choose a socket name such that the absolute path would exceed 100 bytes.
14+
const socketDir = './unix-socket-dir';
15+
const socketName = 'A'.repeat(100 - socketDir.length - 1);
16+
17+
// Make sure we're not in a weird environment
18+
assert.strictEqual(path.resolve(socketDir, socketName).length > 100, true,
19+
'absolute socket path should be longer than 100 bytes');
20+
21+
if (cluster.isMaster) {
22+
// ensure that the worker exits peacefully
23+
process.chdir(common.tmpDir);
24+
fs.mkdirSync(socketDir);
25+
cluster.fork().on('exit', common.mustCall(function(statusCode) {
26+
assert.strictEqual(statusCode, 0);
27+
28+
assert.strictEqual(
29+
fs.existsSync(path.join(socketDir, socketName)), false,
30+
'Socket should be removed when the worker exits');
31+
}));
32+
} else {
33+
process.chdir(socketDir);
34+
35+
const server = net.createServer(common.mustNotCall());
36+
37+
server.listen(socketName, common.mustCall(function() {
38+
assert.strictEqual(
39+
fs.existsSync(socketName), true,
40+
'Socket created in CWD');
41+
42+
process.disconnect();
43+
}));
44+
}

0 commit comments

Comments
 (0)