forked from svrjs/svrjs
Lint out the codebase, add SVRJSFork() function, networking-related code, and ipSubnetUtils.js utility functions file and corresponding unit tests
This commit is contained in:
parent
2c990a6907
commit
0ea53fdf96
3 changed files with 270 additions and 5 deletions
176
src/index.js
176
src/index.js
|
@ -207,6 +207,10 @@ if (!fs.existsSync(process.dirname + "/temp"))
|
|||
const cluster = require("./utils/clusterBunShim.js"); // Cluster module with shim for Bun
|
||||
const legacyModWrapper = require("./utils/legacyModWrapper.js");
|
||||
const generateErrorStack = require("./utils/generateErrorStack.js");
|
||||
const {
|
||||
calculateNetworkIPv4FromCidr,
|
||||
calculateBroadcastIPv4FromCidr,
|
||||
} = require("./utils/ipSubnetUtils.js");
|
||||
//const serverHTTPErrorDescs = require("../res/httpErrorDescriptions.js");
|
||||
//const getOS = require("./utils/getOS.js");
|
||||
//const parseURL = require("./utils/urlParser.js");
|
||||
|
@ -344,7 +348,7 @@ if (typeof process.serverConfig.port === "string") {
|
|||
if (process.serverConfig.port.match(/^[0-9]+$/)) {
|
||||
process.serverConfig.port = parseInt(process.serverConfig.port);
|
||||
} else {
|
||||
const portLMatch = port.match(
|
||||
const portLMatch = process.serverConfig.port.match(
|
||||
/^(\[[^ \]@\/\\]+\]|[^ \]\[:@\/\\]+):([0-9]+)$/,
|
||||
);
|
||||
if (portLMatch) {
|
||||
|
@ -357,7 +361,7 @@ if (typeof process.serverConfig.port === "string") {
|
|||
}
|
||||
if (typeof process.serverConfig.sport === "string") {
|
||||
if (process.serverConfig.sport.match(/^[0-9]+$/)) {
|
||||
process.serverConfig.sport = parseInt(sport);
|
||||
process.serverConfig.sport = parseInt(process.serverConfig.sport);
|
||||
} else {
|
||||
const sportLMatch = process.serverConfig.sport.match(
|
||||
/^(\[[^ \]@\/\\]+\]|[^ \]\[:@\/\\]+):([0-9]+)$/,
|
||||
|
@ -402,6 +406,58 @@ try {
|
|||
wwwrootError = err;
|
||||
}
|
||||
|
||||
// IP and network inteface-related
|
||||
let ifaces = {};
|
||||
let ifaceEx = null;
|
||||
try {
|
||||
ifaces = os.networkInterfaces();
|
||||
} catch (err) {
|
||||
ifaceEx = err;
|
||||
}
|
||||
var ips = [];
|
||||
const brdIPs = ["255.255.255.255", "127.255.255.255", "0.255.255.255"];
|
||||
const netIPs = ["127.0.0.0"];
|
||||
|
||||
Object.keys(ifaces).forEach((ifname) => {
|
||||
let alias = 0;
|
||||
ifaces[ifname].forEach((iface) => {
|
||||
if (iface.family !== "IPv4" || iface.internal !== false) {
|
||||
return;
|
||||
}
|
||||
if (alias >= 1) {
|
||||
ips.push(ifname + ":" + alias, iface.address);
|
||||
} else {
|
||||
ips.push(ifname, iface.address);
|
||||
}
|
||||
brdIPs.push(calculateBroadcastIPv4FromCidr(iface.cidr));
|
||||
netIPs.push(calculateNetworkIPv4FromCidr(iface.cidr));
|
||||
alias++;
|
||||
});
|
||||
});
|
||||
|
||||
if (ips.length == 0) {
|
||||
Object.keys(ifaces).forEach((ifname) => {
|
||||
let alias = 0;
|
||||
ifaces[ifname].forEach((iface) => {
|
||||
if (iface.family !== "IPv6" || iface.internal !== false) {
|
||||
return;
|
||||
}
|
||||
if (alias >= 1) {
|
||||
ips.push(ifname + ":" + alias, iface.address);
|
||||
} else {
|
||||
ips.push(ifname, iface.address);
|
||||
}
|
||||
alias++;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Server IP address
|
||||
var host = ips[(ips.length) - 1];
|
||||
if (!host) host = "[offline]";
|
||||
|
||||
// TODO: Public IP address-related
|
||||
|
||||
// SSL-related
|
||||
let key = "";
|
||||
let cert = "";
|
||||
|
@ -931,6 +987,108 @@ middleware.forEach((middlewareO) => {
|
|||
}
|
||||
});
|
||||
|
||||
// SVR.JS worker spawn-related
|
||||
let SVRJSInitialized = false;
|
||||
let crashed = false;
|
||||
let threadLimitWarned = false;
|
||||
|
||||
// SVR.JS worker forking function
|
||||
function SVRJSFork() {
|
||||
// Log
|
||||
if (SVRJSInitialized)
|
||||
serverconsole.locmessage(
|
||||
"Starting next thread, because previous one hung up/crashed...",
|
||||
);
|
||||
// Fork new worker
|
||||
var newWorker = {};
|
||||
try {
|
||||
if (
|
||||
!threadLimitWarned &&
|
||||
cluster.__shimmed__ &&
|
||||
process.isBun &&
|
||||
process.versions.bun &&
|
||||
process.versions.bun[0] != "0"
|
||||
) {
|
||||
threadLimitWarned = true;
|
||||
serverconsole.locwarnmessage(
|
||||
"SVR.JS limited the number of workers to one, because of startup problems in Bun 1.0 and newer with shimmed (not native) clustering module. Reliability may suffer.",
|
||||
);
|
||||
}
|
||||
if (
|
||||
!(
|
||||
cluster.__shimmed__ &&
|
||||
process.isBun &&
|
||||
process.versions.bun &&
|
||||
process.versions.bun[0] != "0" &&
|
||||
Object.keys(cluster.workers) > 0
|
||||
)
|
||||
) {
|
||||
newWorker = cluster.fork();
|
||||
} else {
|
||||
if (SVRJSInitialized)
|
||||
serverconsole.locwarnmessage(
|
||||
"SVR.JS limited the number of workers to one, because of startup problems in Bun 1.0 and newer with shimmed (not native) clustering module. Reliability may suffer.",
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.name == "NotImplementedError") {
|
||||
// If cluster.fork throws a NotImplementedError, shim cluster module
|
||||
cluster.bunShim();
|
||||
if (
|
||||
!threadLimitWarned &&
|
||||
cluster.__shimmed__ &&
|
||||
process.isBun &&
|
||||
process.versions.bun &&
|
||||
process.versions.bun[0] != "0"
|
||||
) {
|
||||
threadLimitWarned = true;
|
||||
serverconsole.locwarnmessage(
|
||||
"SVR.JS limited the number of workers to one, because of startup problems in Bun 1.0 and newer with shimmed (not native) clustering module. Reliability may suffer.",
|
||||
);
|
||||
}
|
||||
if (
|
||||
!(
|
||||
cluster.__shimmed__ &&
|
||||
process.isBun &&
|
||||
process.versions.bun &&
|
||||
process.versions.bun[0] != "0" &&
|
||||
Object.keys(cluster.workers) > 0
|
||||
)
|
||||
) {
|
||||
newWorker = cluster.fork();
|
||||
} else {
|
||||
if (SVRJSInitialized)
|
||||
serverconsole.locwarnmessage(
|
||||
"SVR.JS limited the number of workers to one, because of startup problems in Bun 1.0 and newer with shimmed (not native) clustering module. Reliability may suffer.",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// Add event listeners
|
||||
if (newWorker.on) {
|
||||
newWorker.on("error", function (err) {
|
||||
if (!exiting)
|
||||
serverconsole.locwarnmessage(
|
||||
"There was a problem when handling SVR.JS worker! (from master process side) Reason: " +
|
||||
err.message,
|
||||
);
|
||||
});
|
||||
newWorker.on("exit", function () {
|
||||
if (!exiting && Object.keys(cluster.workers).length == 0) {
|
||||
crashed = true;
|
||||
SVRJSFork();
|
||||
}
|
||||
});
|
||||
// TODO: add listeners to workers
|
||||
// newWorker.on("message", bruteForceListenerWrapper(newWorker));
|
||||
// newWorker.on("message", listenConnListener);
|
||||
}
|
||||
}
|
||||
|
||||
// Starting function
|
||||
function start(init) {
|
||||
init = Boolean(init);
|
||||
if (cluster.isPrimary || cluster.isPrimary === undefined) {
|
||||
|
@ -970,7 +1128,7 @@ function start(init) {
|
|||
/^(?:0\.|1\.0\.|1\.1\.[0-9](?![0-9])|1\.1\.1[0-2](?![0-9]))/,
|
||||
)
|
||||
) &&
|
||||
users.some(function (entry) {
|
||||
process.serverConfig.users.some(function (entry) {
|
||||
return entry.pbkdf2;
|
||||
})
|
||||
)
|
||||
|
@ -1161,7 +1319,12 @@ function start(init) {
|
|||
}
|
||||
|
||||
// Print server startup information
|
||||
if (!(process.serverConfig.secure && process.serverConfig.disableNonEncryptedServer))
|
||||
if (
|
||||
!(
|
||||
process.serverConfig.secure &&
|
||||
process.serverConfig.disableNonEncryptedServer
|
||||
)
|
||||
)
|
||||
serverconsole.locmessage(
|
||||
"Starting HTTP server at " +
|
||||
(typeof process.serverConfig.port == "number"
|
||||
|
@ -1213,7 +1376,10 @@ function start(init) {
|
|||
} catch (err) {
|
||||
if (err.code != "ERR_SERVER_ALREADY_LISTEN") throw err;
|
||||
}
|
||||
if (process.serverConfig.secure && !process.serverConfig.disableNonEncryptedServer) {
|
||||
if (
|
||||
process.serverConfig.secure &&
|
||||
!process.serverConfig.disableNonEncryptedServer
|
||||
) {
|
||||
try {
|
||||
if (typeof process.serverConfig.port == "number" && listenAddress) {
|
||||
server2.listen(process.serverConfig.port, listenAddress);
|
||||
|
|
50
src/utils/ipSubnetUtils.js
Normal file
50
src/utils/ipSubnetUtils.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
function calculateBroadcastIPv4FromCidr(ipWithCidr) {
|
||||
// Check if CIDR notation is valid, if it's not, return null
|
||||
if (!ipWithCidr) return null;
|
||||
const ipCA = ipWithCidr.match(/^((?:(?:25[0-5]|(?:2[0-4]|1\d|[1-9]|)\d)\.?\b){4})\/([0-2][0-9]|3[0-2]|[0-9])$/);
|
||||
if (!ipCA) return null;
|
||||
|
||||
// Extract IP and mask (numeric format)
|
||||
const ip = ipCA[1];
|
||||
const mask = parseInt(ipCA[2]);
|
||||
|
||||
return ip
|
||||
.split(".")
|
||||
.map((num, index) => {
|
||||
// Calculate resulting 8-bit
|
||||
var power = Math.max(Math.min(mask - index * 8, 8), 0);
|
||||
return (
|
||||
(parseInt(num) & ((Math.pow(2, power) - 1) << (8 - power))) |
|
||||
(Math.pow(2, 8 - power) - 1)
|
||||
).toString();
|
||||
})
|
||||
.join(".");
|
||||
}
|
||||
|
||||
function calculateNetworkIPv4FromCidr(ipWithCidr) {
|
||||
// Check if CIDR notation is valid, if it's not, return null
|
||||
if (!ipWithCidr) return null;
|
||||
const ipCA = ipWithCidr.match(/^((?:(?:25[0-5]|(?:2[0-4]|1\d|[1-9]|)\d)\.?\b){4})\/([0-2][0-9]|3[0-2]|[0-9])$/);
|
||||
if (!ipCA) return null;
|
||||
|
||||
// Extract IP and mask (numeric format)
|
||||
const ip = ipCA[1];
|
||||
const mask = parseInt(ipCA[2]);
|
||||
|
||||
return ip
|
||||
.split(".")
|
||||
.map((num, index) => {
|
||||
// Calculate resulting 8-bit
|
||||
var power = Math.max(Math.min(mask - index * 8, 8), 0);
|
||||
return (
|
||||
parseInt(num) &
|
||||
((Math.pow(2, power) - 1) << (8 - power))
|
||||
).toString();
|
||||
})
|
||||
.join(".");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
calculateBroadcastIPv4FromCidr: calculateBroadcastIPv4FromCidr,
|
||||
calculateNetworkIPv4FromCidr: calculateNetworkIPv4FromCidr,
|
||||
};
|
49
tests/utils/ipSubnetUtils.test.js
Normal file
49
tests/utils/ipSubnetUtils.test.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
const {
|
||||
calculateBroadcastIPv4FromCidr,
|
||||
calculateNetworkIPv4FromCidr,
|
||||
} = require('../../src/utils/ipSubnetUtils');
|
||||
|
||||
describe('IPv4 subnet utilties', () => {
|
||||
describe('calculateBroadcastIPv4FromCidr', () => {
|
||||
test('should return the broadcast address for a given CIDR', () => {
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/24')).toBe('192.168.1.255');
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/25')).toBe('192.168.1.127');
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/26')).toBe('192.168.1.63');
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/27')).toBe('192.168.1.31');
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/28')).toBe('192.168.1.15');
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/29')).toBe('192.168.1.7');
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/30')).toBe('192.168.1.3');
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/31')).toBe('192.168.1.1');
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/32')).toBe('192.168.1.0');
|
||||
});
|
||||
|
||||
test('should return null for invalid CIDR notation', () => {
|
||||
expect(calculateBroadcastIPv4FromCidr(null)).toBe(null);
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0')).toBe(null);
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/')).toBe(null);
|
||||
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/abc')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateNetworkIPv4FromCidr', () => {
|
||||
test('should return the network address for a given CIDR', () => {
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/24')).toBe('192.168.1.0');
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/25')).toBe('192.168.1.0');
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/26')).toBe('192.168.1.0');
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/27')).toBe('192.168.1.0');
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/28')).toBe('192.168.1.0');
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/29')).toBe('192.168.1.0');
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/30')).toBe('192.168.1.0');
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/31')).toBe('192.168.1.0');
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/32')).toBe('192.168.1.0');
|
||||
});
|
||||
|
||||
test('should return null for invalid CIDR notation', () => {
|
||||
expect(calculateNetworkIPv4FromCidr(null)).toBe(null);
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0')).toBe(null);
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/')).toBe(null);
|
||||
expect(calculateNetworkIPv4FromCidr('192.168.1.0/abc')).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in a new issue