forked from svrjs/svrjs
Update to SVR.JS 3.14.1
This commit is contained in:
parent
91f2d3b50f
commit
06712f35b5
5 changed files with 175 additions and 81 deletions
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SVR.JS 3.14.0</title>
|
<title>SVR.JS 3.14.1</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<style>
|
<style>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Welcome to SVR.JS 3.14.0</h1>
|
<h1>Welcome to SVR.JS 3.14.1</h1>
|
||||||
<br/>
|
<br/>
|
||||||
<img src="/logo.png" style="width: 256px;" />
|
<img src="/logo.png" style="width: 256px;" />
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -134,9 +134,8 @@
|
||||||
</div>
|
</div>
|
||||||
<p>Changes:</p>
|
<p>Changes:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Added new <i>config.json</i> properties: <i>useClientCertificate</i>, <i>rejectUnauthorizedClientCertificates</i>, <i>cipherSuite</i>, <i>ecdhCurve</i>, <i>tlsMinVersion</i>, <i>tlsMaxVersion</i>, <i>signatureAlgorithms</i> and <i>http2Settings</i>.</li>
|
<li>Added support for IP-based virtual hosts.</li>
|
||||||
<li>Added support for web root postfixes (along with postfix prefixes).</li>
|
<li>Fixed SVR.JS crashes with <i>X-SVR-JS-From-Main-Thread</i> header and unknown client IPs.</li>
|
||||||
<li>Custom head and foot inclusion is now returning 500 error in case of server error instead of crashing the server.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="/tests.html">Tests</a><br/>
|
<a href="/tests.html">Tests</a><br/>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SVR.JS 3.14.0 Licenses</title>
|
<title>SVR.JS 3.14.1 Licenses</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<style>
|
<style>
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>SVR.JS 3.14.0 Licenses</h1>
|
<h1>SVR.JS 3.14.1 Licenses</h1>
|
||||||
<h2>SVR.JS 3.14.0</h2>
|
<h2>SVR.JS 3.14.1</h2>
|
||||||
<div style="display: inline-block; text-align: left; border-width: 2px; border-style: solid; border-color: gray; padding: 8px;">
|
<div style="display: inline-block; text-align: left; border-width: 2px; border-style: solid; border-color: gray; padding: 8px;">
|
||||||
MIT License<br/>
|
MIT License<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE<br/>
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE<br/>
|
||||||
SOFTWARE.<br/>
|
SOFTWARE.<br/>
|
||||||
</div>
|
</div>
|
||||||
<h2>Packages used by SVR.JS 3.14.0</h2>
|
<h2>Packages used by SVR.JS 3.14.1</h2>
|
||||||
<div style="width: 100%; background-color: #ccc; border: 1px solid green; text-align: left; margin: 10px 0;">
|
<div style="width: 100%; background-color: #ccc; border: 1px solid green; text-align: left; margin: 10px 0;">
|
||||||
<div style="float: right;">License: MIT</div>
|
<div style="float: right;">License: MIT</div>
|
||||||
<div style="font-size: 20px;">
|
<div style="font-size: 20px;">
|
||||||
|
|
Binary file not shown.
233
svr.js
233
svr.js
|
@ -69,7 +69,7 @@ function deleteFolderRecursive(path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var os = require("os");
|
var os = require("os");
|
||||||
var version = "3.14.0";
|
var version = "3.14.1";
|
||||||
var singlethreaded = false;
|
var singlethreaded = false;
|
||||||
|
|
||||||
if (process.versions) process.versions.svrjs = version; // Inject SVR.JS into process.versions
|
if (process.versions) process.versions.svrjs = version; // Inject SVR.JS into process.versions
|
||||||
|
@ -306,7 +306,7 @@ function generateETag(filePath, stat) {
|
||||||
return ETagDB[filePath + "-" + stat.size + "-" + stat.mtime];
|
return ETagDB[filePath + "-" + stat.size + "-" + stat.mtime];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Brute force-related
|
// Brute force protection-related
|
||||||
var bruteForceDb = {};
|
var bruteForceDb = {};
|
||||||
|
|
||||||
// PBKDF2/scrypt cache
|
// PBKDF2/scrypt cache
|
||||||
|
@ -321,6 +321,7 @@ var reallyExiting = false;
|
||||||
var crashed = false;
|
var crashed = false;
|
||||||
var threadLimitWarned = false;
|
var threadLimitWarned = false;
|
||||||
|
|
||||||
|
// SVR.JS worker forking function
|
||||||
function SVRJSFork() {
|
function SVRJSFork() {
|
||||||
// Log
|
// Log
|
||||||
if (SVRJSInitialized) serverconsole.locmessage("Starting next thread, because previous one hung up/crashed...");
|
if (SVRJSInitialized) serverconsole.locmessage("Starting next thread, because previous one hung up/crashed...");
|
||||||
|
@ -531,7 +532,85 @@ function createRegex(regex, isPath) {
|
||||||
return new RegExp(searchString, modifiers);
|
return new RegExp(searchString, modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkForEnabledDirectoryListing(hostname) {
|
// Function to check if IPs are equal
|
||||||
|
function ipMatch(IP1, IP2) {
|
||||||
|
|
||||||
|
if (!IP1) return true;
|
||||||
|
if (!IP2) return false;
|
||||||
|
|
||||||
|
// Function to normalize IPv4 address (remove leading zeros)
|
||||||
|
function normalizeIPv4Address(address) {
|
||||||
|
return address.replace(/(^|\.)(?:0(?!\.|$))+/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to expand IPv6 address to full format
|
||||||
|
function expandIPv6Address(address) {
|
||||||
|
var fullAddress = "";
|
||||||
|
var expandedAddress = "";
|
||||||
|
var validGroupCount = 8;
|
||||||
|
var validGroupSize = 4;
|
||||||
|
|
||||||
|
var ipv4 = "";
|
||||||
|
var extractIpv4 = /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/;
|
||||||
|
var validateIpv4 = /((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})/;
|
||||||
|
|
||||||
|
if (validateIpv4.test(address)) {
|
||||||
|
var oldGroups = address.match(extractIpv4);
|
||||||
|
for (var i = 1; i < oldGroups.length; i++) {
|
||||||
|
ipv4 += ("00" + (parseInt(oldGroups[i], 10).toString(16))).slice(-2) + (i == 2 ? ":" : "");
|
||||||
|
}
|
||||||
|
address = address.replace(extractIpv4, ipv4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.indexOf("::") == -1) {
|
||||||
|
fullAddress = address;
|
||||||
|
} else {
|
||||||
|
var sides = address.split("::");
|
||||||
|
var groupsPresent = 0;
|
||||||
|
sides.forEach(function (side) {
|
||||||
|
groupsPresent += side.split(":").length;
|
||||||
|
});
|
||||||
|
fullAddress += sides[0] + ":";
|
||||||
|
if (validGroupCount - groupsPresent > 1) {
|
||||||
|
fullAddress += "0000:".repeat(validGroupCount - groupsPresent);
|
||||||
|
}
|
||||||
|
fullAddress += sides[1];
|
||||||
|
}
|
||||||
|
var groups = fullAddress.split(":");
|
||||||
|
for (var i = 0; i < validGroupCount; i++) {
|
||||||
|
if (groups[i].length < validGroupSize) {
|
||||||
|
groups[i] = "0".repeat(validGroupSize - groups[i].length) + groups[i];
|
||||||
|
}
|
||||||
|
expandedAddress += (i != validGroupCount - 1) ? groups[i] + ":" : groups[i];
|
||||||
|
}
|
||||||
|
return expandedAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize or expand IP addresses
|
||||||
|
IP1 = IP1.toLowerCase();
|
||||||
|
if (IP1 == "localhost") IP1 = "::1";
|
||||||
|
if (IP1.indexOf("::ffff:") == 0) IP1 = IP1.substr(7);
|
||||||
|
if (IP1.indexOf(":") > -1) {
|
||||||
|
IP1 = expandIPv6Address(IP1);
|
||||||
|
} else {
|
||||||
|
IP1 = normalizeIPv4Address(IP1);
|
||||||
|
}
|
||||||
|
|
||||||
|
IP2 = IP2.toLowerCase();
|
||||||
|
if (IP2 == "localhost") IP2 = "::1";
|
||||||
|
if (IP2.indexOf("::ffff:") == 0) IP2 = IP2.substr(7);
|
||||||
|
if (IP2.indexOf(":") > -1) {
|
||||||
|
IP2 = expandIPv6Address(IP2);
|
||||||
|
} else {
|
||||||
|
IP2 = normalizeIPv4Address(IP2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if processed IPs are equal
|
||||||
|
if (IP1 == IP2) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkForEnabledDirectoryListing(hostname, localAddress) {
|
||||||
function matchHostname(hostnameM) {
|
function matchHostname(hostnameM) {
|
||||||
if (typeof hostnameM == "undefined" || hostnameM == "*") {
|
if (typeof hostnameM == "undefined" || hostnameM == "*") {
|
||||||
return true;
|
return true;
|
||||||
|
@ -550,7 +629,7 @@ function checkForEnabledDirectoryListing(hostname) {
|
||||||
if (!configJSON.enableDirectoryListingVHost) return main;
|
if (!configJSON.enableDirectoryListingVHost) return main;
|
||||||
var vhostP = null;
|
var vhostP = null;
|
||||||
configJSON.enableDirectoryListingVHost.every(function (vhost) {
|
configJSON.enableDirectoryListingVHost.every(function (vhost) {
|
||||||
if (matchHostname(vhost.host)) {
|
if (matchHostname(vhost.host) && ipMatch(vhost.ip, localAddress)) {
|
||||||
vhostP = vhost;
|
vhostP = vhost;
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -757,7 +836,7 @@ function ipBlockList(rawBlockList) {
|
||||||
|
|
||||||
// Normalize or expand the IP address
|
// Normalize or expand the IP address
|
||||||
rawValue = rawValue.toLowerCase();
|
rawValue = rawValue.toLowerCase();
|
||||||
if (rawValue == "localhost") rawValue = "127.0.0.1";
|
if (rawValue == "localhost") rawValue = "::1";
|
||||||
if (rawValue.indexOf("::ffff:") == 0) rawValue = rawValue.substr(7);
|
if (rawValue.indexOf("::ffff:") == 0) rawValue = rawValue.substr(7);
|
||||||
if (rawValue.indexOf(":") > -1) {
|
if (rawValue.indexOf(":") > -1) {
|
||||||
isIPv6 = true;
|
isIPv6 = true;
|
||||||
|
@ -794,8 +873,8 @@ function generateErrorStack(errorObject) {
|
||||||
|
|
||||||
// If the error stack starts with the error name, return the original stack (it is V8-style then).
|
// If the error stack starts with the error name, return the original stack (it is V8-style then).
|
||||||
if (errorStack.some(function (errorStackLine) {
|
if (errorStack.some(function (errorStackLine) {
|
||||||
return (errorStackLine.indexOf(errorObject.name) == 0);
|
return (errorStackLine.indexOf(errorObject.name) == 0);
|
||||||
})) {
|
})) {
|
||||||
return errorObject.stack;
|
return errorObject.stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,6 +933,7 @@ function calculateNetworkIPv4FromCidr(ipWithCidr) {
|
||||||
}).join(".");
|
}).join(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IP and network inteface-related
|
||||||
var ifaces = {};
|
var ifaces = {};
|
||||||
var ifaceEx = null;
|
var ifaceEx = null;
|
||||||
try {
|
try {
|
||||||
|
@ -864,11 +944,7 @@ try {
|
||||||
var ips = [];
|
var ips = [];
|
||||||
var brdIPs = ["255.255.255.255", "127.255.255.255", "0.255.255.255"];
|
var brdIPs = ["255.255.255.255", "127.255.255.255", "0.255.255.255"];
|
||||||
var netIPs = ["127.0.0.0"];
|
var netIPs = ["127.0.0.0"];
|
||||||
var attmts = 5;
|
|
||||||
var attmtsRedir = 5;
|
|
||||||
var errors = os.constants.errno;
|
|
||||||
var timestamp = new Date().getTime();
|
|
||||||
var wwwredirect = false;
|
|
||||||
Object.keys(ifaces).forEach(function (ifname) {
|
Object.keys(ifaces).forEach(function (ifname) {
|
||||||
var alias = 0;
|
var alias = 0;
|
||||||
ifaces[ifname].forEach(function (iface) {
|
ifaces[ifname].forEach(function (iface) {
|
||||||
|
@ -885,6 +961,7 @@ Object.keys(ifaces).forEach(function (ifname) {
|
||||||
alias++;
|
alias++;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ips.length == 0) {
|
if (ips.length == 0) {
|
||||||
Object.keys(ifaces).forEach(function (ifname) {
|
Object.keys(ifaces).forEach(function (ifname) {
|
||||||
var alias = 0;
|
var alias = 0;
|
||||||
|
@ -901,9 +978,20 @@ if (ips.length == 0) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Server startup attempt counter
|
||||||
|
var attmts = 5;
|
||||||
|
var attmtsRedir = 5;
|
||||||
|
|
||||||
|
// Some variables...
|
||||||
|
var errors = os.constants.errno;
|
||||||
|
var timestamp = new Date().getTime();
|
||||||
|
|
||||||
|
// Server IP address
|
||||||
var host = ips[(ips.length) - 1];
|
var host = ips[(ips.length) - 1];
|
||||||
if (!host) host = "[offline]";
|
if (!host) host = "[offline]";
|
||||||
|
|
||||||
|
// Public IP address-related
|
||||||
var ipRequestCompleted = false;
|
var ipRequestCompleted = false;
|
||||||
var ipRequestGotError = false;
|
var ipRequestGotError = false;
|
||||||
if (host != "[offline]" || ifaceEx) {
|
if (host != "[offline]" || ifaceEx) {
|
||||||
|
@ -1060,11 +1148,11 @@ if (fs.existsSync(__dirname + "/config.json")) {
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
configJSONRErr = err2;
|
configJSONRErr = err2;
|
||||||
// throw new Error("Cannot read JSON file.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default server configuration properties
|
// Default server configuration properties
|
||||||
|
var wwwredirect = false;
|
||||||
var rawBlackList = [];
|
var rawBlackList = [];
|
||||||
var users = [];
|
var users = [];
|
||||||
var page404 = "404.html";
|
var page404 = "404.html";
|
||||||
|
@ -1199,6 +1287,7 @@ try {
|
||||||
if (vnum === undefined) vnum = 0;
|
if (vnum === undefined) vnum = 0;
|
||||||
if (process.isBun) vnum = 64;
|
if (process.isBun) vnum = 64;
|
||||||
|
|
||||||
|
// SVR.JS path sanitizer function
|
||||||
function sanitizeURL(resource) {
|
function sanitizeURL(resource) {
|
||||||
if (resource == "*") return "*";
|
if (resource == "*") return "*";
|
||||||
if (resource == "") return "";
|
if (resource == "") return "";
|
||||||
|
@ -1231,6 +1320,7 @@ function sanitizeURL(resource) {
|
||||||
else return sanitizedResource;
|
else return sanitizedResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Node.JS mojibake URL fixing function
|
||||||
function fixNodeMojibakeURL(string) {
|
function fixNodeMojibakeURL(string) {
|
||||||
var encoded = "";
|
var encoded = "";
|
||||||
|
|
||||||
|
@ -1249,6 +1339,7 @@ function fixNodeMojibakeURL(string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SSL-related
|
||||||
var key = "";
|
var key = "";
|
||||||
var cert = "";
|
var cert = "";
|
||||||
|
|
||||||
|
@ -1277,7 +1368,7 @@ if (secure) {
|
||||||
var sniNames = Object.keys(sni);
|
var sniNames = Object.keys(sni);
|
||||||
var sniCredentials = [];
|
var sniCredentials = [];
|
||||||
sniNames.forEach(function (sniName) {
|
sniNames.forEach(function (sniName) {
|
||||||
if(typeof sniName === "string" && sniName.match(/\*[^*.:]*\*[^*.:]*(?:\.|:|$)/)) {
|
if (typeof sniName === "string" && sniName.match(/\*[^*.:]*\*[^*.:]*(?:\.|:|$)/)) {
|
||||||
sniReDos = true;
|
sniReDos = true;
|
||||||
}
|
}
|
||||||
sniCredentials.push({
|
sniCredentials.push({
|
||||||
|
@ -1306,7 +1397,7 @@ function LOG(s) {
|
||||||
flags: "a",
|
flags: "a",
|
||||||
autoClose: false
|
autoClose: false
|
||||||
});
|
});
|
||||||
logFile.on("error", function(err) {
|
logFile.on("error", function (err) {
|
||||||
if (!s.match(/^SERVER WARNING MESSAGE(?: \[Request Id: [0-9a-f]{6}\])?: There was a problem while saving logs! Logs will not be kept in log file\. Reason: /) && !reallyExiting) serverconsole.locwarnmessage("There was a problem while saving logs! Logs will not be kept in log file. Reason: " + err.message);
|
if (!s.match(/^SERVER WARNING MESSAGE(?: \[Request Id: [0-9a-f]{6}\])?: There was a problem while saving logs! Logs will not be kept in log file\. Reason: /) && !reallyExiting) serverconsole.locwarnmessage("There was a problem while saving logs! Logs will not be kept in log file. Reason: " + err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1403,7 +1494,7 @@ var serverconsole = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrap around process.exit, so log contents can flush.
|
// Wrap around process.exit, so that log contents can be flushed.
|
||||||
process.unsafeExit = process.exit;
|
process.unsafeExit = process.exit;
|
||||||
process.exit = function (code) {
|
process.exit = function (code) {
|
||||||
if (logFile && logFile.writable && !logFile.pending) {
|
if (logFile && logFile.writable && !logFile.pending) {
|
||||||
|
@ -1438,6 +1529,7 @@ process.exit = function (code) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SVR.JS mod loader
|
||||||
var modLoadingErrors = [];
|
var modLoadingErrors = [];
|
||||||
var SSJSError = undefined;
|
var SSJSError = undefined;
|
||||||
|
|
||||||
|
@ -1742,6 +1834,7 @@ function sha256(s) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to get URL path for use in forbidden path adding.
|
||||||
function getInitializePath(to) {
|
function getInitializePath(to) {
|
||||||
var cwd = process.cwd();
|
var cwd = process.cwd();
|
||||||
if (os.platform() == "win32") {
|
if (os.platform() == "win32") {
|
||||||
|
@ -1758,6 +1851,7 @@ function getInitializePath(to) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to check if URL path name is a forbidden path.
|
||||||
function isForbiddenPath(decodedHref, match) {
|
function isForbiddenPath(decodedHref, match) {
|
||||||
var forbiddenPath = forbiddenPaths[match];
|
var forbiddenPath = forbiddenPaths[match];
|
||||||
if (!forbiddenPath) return false;
|
if (!forbiddenPath) return false;
|
||||||
|
@ -1772,6 +1866,7 @@ function isForbiddenPath(decodedHref, match) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to check if URL path name is index of one of defined forbidden paths.
|
||||||
function isIndexOfForbiddenPath(decodedHref, match) {
|
function isIndexOfForbiddenPath(decodedHref, match) {
|
||||||
var forbiddenPath = forbiddenPaths[match];
|
var forbiddenPath = forbiddenPaths[match];
|
||||||
if (!forbiddenPath) return false;
|
if (!forbiddenPath) return false;
|
||||||
|
@ -1786,7 +1881,6 @@ function isIndexOfForbiddenPath(decodedHref, match) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Set up forbidden paths
|
// Set up forbidden paths
|
||||||
var forbiddenPaths = {};
|
var forbiddenPaths = {};
|
||||||
|
|
||||||
|
@ -1864,7 +1958,7 @@ var serverErrorDescs = {
|
||||||
599: "The server couldn't connect in time while it was acting as a proxy."
|
599: "The server couldn't connect in time while it was acting as a proxy."
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create server
|
// Create server instances
|
||||||
if (!cluster.isPrimary) {
|
if (!cluster.isPrimary) {
|
||||||
var reqcounter = 0;
|
var reqcounter = 0;
|
||||||
var malformedcounter = 0;
|
var malformedcounter = 0;
|
||||||
|
@ -2118,9 +2212,9 @@ if (!cluster.isPrimary) {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
var snMatches = sniCredentialsSingle.name.match(/^([^:[]*|\[[^]]*\]?)((?::.*)?)$/);
|
var snMatches = sniCredentialsSingle.name.match(/^([^:[]*|\[[^]]*\]?)((?::.*)?)$/);
|
||||||
if(!snMatches[1][0].match(/^\.+$/)) snMatches[1][0] = snMatches[1][0].replace(/\.+$/,"");
|
if (!snMatches[1][0].match(/^\.+$/)) snMatches[1][0] = snMatches[1][0].replace(/\.+$/, "");
|
||||||
server._contexts[server._contexts.length-1][0] = new RegExp("^" + snMatches[1].replace(/([.^$+?\-\\[\]{}])/g, "\\$1").replace(/\*/g, "[^.:]*") + ((snMatches[1][0] == "[" || snMatches[1].match(/^(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/)) ? "" : "\.?") + snMatches[2].replace(/([.^$+?\-\\[\]{}])/g, "\\$1").replace(/\*/g, "[^.]*") + "$", "i");
|
server._contexts[server._contexts.length - 1][0] = new RegExp("^" + snMatches[1].replace(/([.^$+?\-\\[\]{}])/g, "\\$1").replace(/\*/g, "[^.:]*") + ((snMatches[1][0] == "[" || snMatches[1].match(/^(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/)) ? "" : "\.?") + snMatches[2].replace(/([.^$+?\-\\[\]{}])/g, "\\$1").replace(/\*/g, "[^.]*") + "$", "i");
|
||||||
} catch(ex) {
|
} catch (ex) {
|
||||||
// Can't replace regex, ignoring...
|
// Can't replace regex, ignoring...
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2226,8 +2320,8 @@ if (!cluster.isPrimary) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
res.writeHead = function (code, name, headers) {
|
res.writeHead = function (code, name, headers) {
|
||||||
if(code >= 400 && code <= 499) err4xxcounter++;
|
if (code >= 400 && code <= 499) err4xxcounter++;
|
||||||
if(code >= 500 && code <= 599) err5xxcounter++;
|
if (code >= 500 && code <= 599) err5xxcounter++;
|
||||||
var head = ("HTTP/1.1 " + code.toString() + " " + name + "\r\n");
|
var head = ("HTTP/1.1 " + code.toString() + " " + name + "\r\n");
|
||||||
var headers = JSON.parse(JSON.stringify(headers));
|
var headers = JSON.parse(JSON.stringify(headers));
|
||||||
headers["Date"] = (new Date()).toGMTString();
|
headers["Date"] = (new Date()).toGMTString();
|
||||||
|
@ -2799,7 +2893,7 @@ if (!cluster.isPrimary) {
|
||||||
if (configJSON.customHeadersVHost) {
|
if (configJSON.customHeadersVHost) {
|
||||||
var vhostP = null;
|
var vhostP = null;
|
||||||
configJSON.customHeadersVHost.every(function (vhost) {
|
configJSON.customHeadersVHost.every(function (vhost) {
|
||||||
if (matchHostname(vhost.host)) {
|
if (matchHostname(vhost.host) && ipMatch(vhost.ip, req.socket ? req.socket.localAddress : undefined)) {
|
||||||
vhostP = vhost;
|
vhostP = vhost;
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2875,7 +2969,7 @@ if (!cluster.isPrimary) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.headers["x-svr-js-from-main-thread"] == "true" && (!req.socket.remoteAddress || req.socket.remoteAddress == "::1" || req.socket.remoteAddress == "::ffff:127.0.0.1" || req.socket.remoteAddress == "127.0.0.1" || req.socket.remoteAddress == "localhost" || req.socket.remoteAddress == host || req.socket.remoteAddress == "::ffff:" + host)) {
|
if (req.headers["x-svr-js-from-main-thread"] == "true" && req.socket && (!req.socket.remoteAddress || req.socket.remoteAddress == "::1" || req.socket.remoteAddress == "::ffff:127.0.0.1" || req.socket.remoteAddress == "127.0.0.1" || req.socket.remoteAddress == "localhost" || req.socket.remoteAddress == host || req.socket.remoteAddress == "::ffff:" + host)) {
|
||||||
var headers = getCustomHeaders();
|
var headers = getCustomHeaders();
|
||||||
res.writeHead(204, "No Content", headers);
|
res.writeHead(204, "No Content", headers);
|
||||||
res.end();
|
res.end();
|
||||||
|
@ -2975,7 +3069,7 @@ if (!cluster.isPrimary) {
|
||||||
var oldHostHeader = req.headers.host;
|
var oldHostHeader = req.headers.host;
|
||||||
if (typeof req.headers.host == "string") {
|
if (typeof req.headers.host == "string") {
|
||||||
req.headers.host = req.headers.host.toLowerCase();
|
req.headers.host = req.headers.host.toLowerCase();
|
||||||
if(!req.headers.host.match(/^\.+$/)) req.headers.host = req.headers.host.replace(/\.$/g,"");
|
if (!req.headers.host.match(/^\.+$/)) req.headers.host = req.headers.host.replace(/\.$/g, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isProxy) serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " wants " + (req.method == "GET" ? "content in " : (req.method == "POST" ? "to post content in " : (req.method == "PUT" ? "to add content in " : (req.method == "DELETE" ? "to delete content in " : (req.method == "PATCH" ? "to patch content in " : "to access content using " + req.method + " method in "))))) + (req.headers.host == undefined ? "" : req.headers.host) + req.url);
|
if (!isProxy) serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " wants " + (req.method == "GET" ? "content in " : (req.method == "POST" ? "to post content in " : (req.method == "PUT" ? "to add content in " : (req.method == "DELETE" ? "to delete content in " : (req.method == "PATCH" ? "to patch content in " : "to access content using " + req.method + " method in "))))) + (req.headers.host == undefined ? "" : req.headers.host) + req.url);
|
||||||
|
@ -3067,7 +3161,7 @@ if (!cluster.isPrimary) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list[_i].scode != errorCode || !matchHostname(list[_i].host)) {
|
if (list[_i].scode != errorCode || !(matchHostname(list[_i].host) && ipMatch(list[_i].ip, req.socket ? req.socket.localAddress : undefined))) {
|
||||||
getErrorFileName(list, callback, _i + 1);
|
getErrorFileName(list, callback, _i + 1);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -3286,7 +3380,7 @@ if (!cluster.isPrimary) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URL-related objects.
|
||||||
var uobject = parseURL(req.url);
|
var uobject = parseURL(req.url);
|
||||||
var search = uobject.search;
|
var search = uobject.search;
|
||||||
var href = uobject.pathname;
|
var href = uobject.pathname;
|
||||||
|
@ -3303,6 +3397,7 @@ if (!cluster.isPrimary) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.headers["expect"] && req.headers["expect"] != "100-continue") {
|
if (req.headers["expect"] && req.headers["expect"] != "100-continue") {
|
||||||
|
// Expectations not met.
|
||||||
callServerError(417);
|
callServerError(417);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3416,8 +3511,8 @@ if (!cluster.isPrimary) {
|
||||||
statusBody += "Server errors (5xx): " + err5xxcounter + "<br/>";
|
statusBody += "Server errors (5xx): " + err5xxcounter + "<br/>";
|
||||||
statusBody += "Average error rate: " + (Math.round(((err4xxcounter + err5xxcounter) / reqcounter) * 10000) / 100) + "%<br/>";
|
statusBody += "Average error rate: " + (Math.round(((err4xxcounter + err5xxcounter) / reqcounter) * 10000) / 100) + "%<br/>";
|
||||||
statusBody += "Malformed HTTP requests: " + malformedcounter;
|
statusBody += "Malformed HTTP requests: " + malformedcounter;
|
||||||
if(process.memoryUsage) statusBody += "<br/>Memory usage of thread: " + sizify(process.memoryUsage().rss, true) + "B";
|
if (process.memoryUsage) statusBody += "<br/>Memory usage of thread: " + sizify(process.memoryUsage().rss, true) + "B";
|
||||||
if(process.cpuUsage) statusBody += "<br/>Total CPU usage by thread: u" + (process.cpuUsage().user / 1000) + "ms s" + (process.cpuUsage().system / 1000) + "ms - " + (Math.round((((process.cpuUsage().user + process.cpuUsage().system) / 1000000) / process.uptime()) * 1000) / 1000) + "%";
|
if (process.cpuUsage) statusBody += "<br/>Total CPU usage by thread: u" + (process.cpuUsage().user / 1000) + "ms s" + (process.cpuUsage().system / 1000) + "ms - " + (Math.round((((process.cpuUsage().user + process.cpuUsage().system) / 1000000) / process.uptime()) * 1000) / 1000) + "%";
|
||||||
statusBody += "<br/>Thread PID: " + process.pid + "<br/>";
|
statusBody += "<br/>Thread PID: " + process.pid + "<br/>";
|
||||||
|
|
||||||
var hdhds = getCustomHeaders();
|
var hdhds = getCustomHeaders();
|
||||||
|
@ -3427,11 +3522,6 @@ if (!cluster.isPrimary) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////
|
|
||||||
////THERE IS NO MORE "THE BOOK OF ZSOIE"!////
|
|
||||||
//// But it's in easteregg.tar.gz mod... ////
|
|
||||||
/////////////////////////////////////////////
|
|
||||||
|
|
||||||
var pth = decodeURIComponent(href).replace(/\/+/g, "/").substr(1);
|
var pth = decodeURIComponent(href).replace(/\/+/g, "/").substr(1);
|
||||||
var readFrom = "./" + pth;
|
var readFrom = "./" + pth;
|
||||||
fs.stat(readFrom, function (err, stats) {
|
fs.stat(readFrom, function (err, stats) {
|
||||||
|
@ -3516,7 +3606,7 @@ if (!cluster.isPrimary) {
|
||||||
function properDirectoryListingAndStaticFileServe() {
|
function properDirectoryListingAndStaticFileServe() {
|
||||||
if (stats.isDirectory()) {
|
if (stats.isDirectory()) {
|
||||||
// Check if directory listing is enabled in the configuration
|
// Check if directory listing is enabled in the configuration
|
||||||
if (checkForEnabledDirectoryListing(req.headers.host)) {
|
if (checkForEnabledDirectoryListing(req.headers.host, req.socket ? req.socket.localAddress : undefined)) {
|
||||||
var customHeaders = getCustomHeaders();
|
var customHeaders = getCustomHeaders();
|
||||||
customHeaders["Content-Type"] = "text/html; charset=utf-8";
|
customHeaders["Content-Type"] = "text/html; charset=utf-8";
|
||||||
res.writeHead(200, http.STATUS_CODES[200], customHeaders);
|
res.writeHead(200, http.STATUS_CODES[200], customHeaders);
|
||||||
|
@ -3525,23 +3615,23 @@ if (!cluster.isPrimary) {
|
||||||
var customDirListingHeader = fs.existsSync(("." + decodeURIComponent(href) + "/.dirhead").replace(/\/+/g, "/")) ?
|
var customDirListingHeader = fs.existsSync(("." + decodeURIComponent(href) + "/.dirhead").replace(/\/+/g, "/")) ?
|
||||||
fs.readFileSync(("." + decodeURIComponent(href) + "/.dirhead").replace(/\/+/g, "/")).toString() :
|
fs.readFileSync(("." + decodeURIComponent(href) + "/.dirhead").replace(/\/+/g, "/")).toString() :
|
||||||
(fs.existsSync(("." + decodeURIComponent(href) + "/HEAD.html").replace(/\/+/g, "/")) && (os.platform != "win32" || href != "/")) ?
|
(fs.existsSync(("." + decodeURIComponent(href) + "/HEAD.html").replace(/\/+/g, "/")) && (os.platform != "win32" || href != "/")) ?
|
||||||
fs.readFileSync(("." + decodeURIComponent(href) + "/HEAD.html").replace(/\/+/g, "/")).toString() :
|
fs.readFileSync(("." + decodeURIComponent(href) + "/HEAD.html").replace(/\/+/g, "/")).toString() :
|
||||||
"";
|
"";
|
||||||
var customDirListingFooter = fs.existsSync(("." + decodeURIComponent(href) + "/.dirfoot").replace(/\/+/g, "/")) ?
|
var customDirListingFooter = fs.existsSync(("." + decodeURIComponent(href) + "/.dirfoot").replace(/\/+/g, "/")) ?
|
||||||
fs.readFileSync(("." + decodeURIComponent(href) + "/.dirfoot").replace(/\/+/g, "/")).toString() :
|
fs.readFileSync(("." + decodeURIComponent(href) + "/.dirfoot").replace(/\/+/g, "/")).toString() :
|
||||||
(fs.existsSync(("." + decodeURIComponent(href) + "/FOOT.html").replace(/\/+/g, "/")) && (os.platform != "win32" || href != "/")) ?
|
(fs.existsSync(("." + decodeURIComponent(href) + "/FOOT.html").replace(/\/+/g, "/")) && (os.platform != "win32" || href != "/")) ?
|
||||||
fs.readFileSync(("." + decodeURIComponent(href) + "/FOOT.html").replace(/\/+/g, "/")).toString() :
|
fs.readFileSync(("." + decodeURIComponent(href) + "/FOOT.html").replace(/\/+/g, "/")).toString() :
|
||||||
"";
|
"";
|
||||||
|
|
||||||
// Check if custom header has HTML tag
|
// Check if custom header has HTML tag
|
||||||
var headerHasHTMLTag = customDirListingHeader.replace(/<!--(?:(?:(?!--\>)[\s\S])*|)(?:-->|$)/g, "").match(/<html(?![a-zA-Z0-9])(?:"(?:\\(?:[\s\S]|$)|[^\\"])*(?:"|$)|'(?:\\(?:[\s\S]|$)|[^\\'])*(?:'|$)|[^'">])*(?:>|$)/i);
|
var headerHasHTMLTag = customDirListingHeader.replace(/<!--(?:(?:(?!--\>)[\s\S])*|)(?:-->|$)/g, "").match(/<html(?![a-zA-Z0-9])(?:"(?:\\(?:[\s\S]|$)|[^\\"])*(?:"|$)|'(?:\\(?:[\s\S]|$)|[^\\'])*(?:'|$)|[^'">])*(?:>|$)/i);
|
||||||
|
|
||||||
// Generate HTML head and footer based on configuration and custom content
|
// Generate HTML head and footer based on configuration and custom content
|
||||||
var htmlHead = (!configJSON.enableDirectoryListingWithDefaultHead || head == "" ?
|
var htmlHead = (!configJSON.enableDirectoryListingWithDefaultHead || head == "" ?
|
||||||
(!headerHasHTMLTag ?
|
(!headerHasHTMLTag ?
|
||||||
"<!DOCTYPE html><html><head><title>Directory: " + decodeURIComponent(origHref).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</title><meta charset=\"UTF-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /></head><body>" :
|
"<!DOCTYPE html><html><head><title>Directory: " + decodeURIComponent(origHref).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</title><meta charset=\"UTF-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /></head><body>" :
|
||||||
customDirListingHeader.replace(/<head>/i, "<head><title>Directory: " + decodeURIComponent(origHref).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</title>")) :
|
customDirListingHeader.replace(/<head>/i, "<head><title>Directory: " + decodeURIComponent(origHref).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</title>")) :
|
||||||
head.replace(/<head>/i, "<head><title>Directory: " + decodeURIComponent(origHref).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</title>")) +
|
head.replace(/<head>/i, "<head><title>Directory: " + decodeURIComponent(origHref).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</title>")) +
|
||||||
(!headerHasHTMLTag ? customDirListingHeader : "") +
|
(!headerHasHTMLTag ? customDirListingHeader : "") +
|
||||||
"<h1>Directory: " + decodeURIComponent(origHref).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</h1><table id=\"directoryListing\"> <tr> <th></th> <th>Filename</th> <th>Size</th> <th>Date</th> </tr>" + (checkPathLevel(decodeURIComponent(origHref)) < 1 ? "" : "<tr><td style=\"width: 24px;\"><img src=\"/.dirimages/return.png\" width=\"24px\" height=\"24px\" alt=\"[RET]\" /></td><td style=\"word-wrap: break-word; word-break: break-word; overflow-wrap: break-word;\"><a href=\"" + (origHref).replace(/\/+/g, "/").replace(/\/[^\/]*\/?$/, "/") + "\">Return</a></td><td></td><td></td></tr>");
|
"<h1>Directory: " + decodeURIComponent(origHref).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</h1><table id=\"directoryListing\"> <tr> <th></th> <th>Filename</th> <th>Size</th> <th>Date</th> </tr>" + (checkPathLevel(decodeURIComponent(origHref)) < 1 ? "" : "<tr><td style=\"width: 24px;\"><img src=\"/.dirimages/return.png\" width=\"24px\" height=\"24px\" alt=\"[RET]\" /></td><td style=\"word-wrap: break-word; word-break: break-word; overflow-wrap: break-word;\"><a href=\"" + (origHref).replace(/\/+/g, "/").replace(/\/[^\/]*\/?$/, "/") + "\">Return</a></td><td></td><td></td></tr>");
|
||||||
|
|
||||||
|
@ -4185,7 +4275,7 @@ if (!cluster.isPrimary) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle redirects to addresses with www.
|
// Handle redirects to addresses with "www." prefix
|
||||||
if (wwwredirect) {
|
if (wwwredirect) {
|
||||||
var hostname = req.headers.host.split[":"];
|
var hostname = req.headers.host.split[":"];
|
||||||
var hostport = null;
|
var hostport = null;
|
||||||
|
@ -4203,14 +4293,14 @@ if (!cluster.isPrimary) {
|
||||||
if (!isProxy) {
|
if (!isProxy) {
|
||||||
for (var i = (_mapBegIndex ? _mapBegIndex : 0); i < map.length; i++) {
|
for (var i = (_mapBegIndex ? _mapBegIndex : 0); i < map.length; i++) {
|
||||||
var mapEntry = map[i];
|
var mapEntry = map[i];
|
||||||
if(href != "/" && (mapEntry.isNotDirectory || mapEntry.isNotFile) && !_fileState) {
|
if (href != "/" && (mapEntry.isNotDirectory || mapEntry.isNotFile) && !_fileState) {
|
||||||
fs.stat("." + decodeURIComponent(href), function(err, stats) {
|
fs.stat("." + decodeURIComponent(href), function (err, stats) {
|
||||||
var _fileState = 3;
|
var _fileState = 3;
|
||||||
if(err) {
|
if (err) {
|
||||||
_fileState = 3;
|
_fileState = 3;
|
||||||
} else if(stats.isDirectory()) {
|
} else if (stats.isDirectory()) {
|
||||||
_fileState = 2;
|
_fileState = 2;
|
||||||
} else if(stats.isFile()) {
|
} else if (stats.isFile()) {
|
||||||
_fileState = 1;
|
_fileState = 1;
|
||||||
} else {
|
} else {
|
||||||
_fileState = 3;
|
_fileState = 3;
|
||||||
|
@ -4220,7 +4310,7 @@ if (!cluster.isPrimary) {
|
||||||
doCallback = false;
|
doCallback = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (matchHostname(mapEntry.host) && address.match(createRegex(mapEntry.definingRegex)) && !(mapEntry.isNotDirectory && _fileState == 2) && !(mapEntry.isNotFile && _fileState == 1)) {
|
if (matchHostname(mapEntry.host) && ipMatch(mapEntry.ip, req.socket ? req.socket.localAddress : undefined) && address.match(createRegex(mapEntry.definingRegex)) && !(mapEntry.isNotDirectory && _fileState == 2) && !(mapEntry.isNotFile && _fileState == 1)) {
|
||||||
try {
|
try {
|
||||||
mapEntry.replacements.forEach(function (replacement) {
|
mapEntry.replacements.forEach(function (replacement) {
|
||||||
rewrittenURL = rewrittenURL.replace(createRegex(replacement.regex), replacement.replacement);
|
rewrittenURL = rewrittenURL.replace(createRegex(replacement.regex), replacement.replacement);
|
||||||
|
@ -4234,7 +4324,7 @@ if (!cluster.isPrimary) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(doCallback) callback(null, rewrittenURL);
|
if (doCallback) callback(null, rewrittenURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trailing slash redirection
|
// Trailing slash redirection
|
||||||
|
@ -4269,12 +4359,12 @@ if (!cluster.isPrimary) {
|
||||||
var origHref = href;
|
var origHref = href;
|
||||||
|
|
||||||
// Add web root postfixes
|
// Add web root postfixes
|
||||||
if(!isProxy) {
|
if (!isProxy) {
|
||||||
var urlWithPostfix = req.url;
|
var urlWithPostfix = req.url;
|
||||||
var postfixPrefix = "";
|
var postfixPrefix = "";
|
||||||
wwwrootPostfixPrefixesVHost.every(function (currentPostfixPrefix) {
|
wwwrootPostfixPrefixesVHost.every(function (currentPostfixPrefix) {
|
||||||
if (req.url.indexOf(currentPostfixPrefix) == 0) {
|
if (req.url.indexOf(currentPostfixPrefix) == 0) {
|
||||||
if (currentPostfixPrefix.match(/\/+$/)) postfixPrefix = currentPostfixPrefix.replace(/\/+$/,"");
|
if (currentPostfixPrefix.match(/\/+$/)) postfixPrefix = currentPostfixPrefix.replace(/\/+$/, "");
|
||||||
else if (urlWithPostfix.length == currentPostfixPrefix.length || urlWithPostfix[currentPostfixPrefix.length] == "?" || urlWithPostfix[currentPostfixPrefix.length] == "/" || urlWithPostfix[currentPostfixPrefix.length] == "#") postfixPrefix = currentPostfixPrefix;
|
else if (urlWithPostfix.length == currentPostfixPrefix.length || urlWithPostfix[currentPostfixPrefix.length] == "?" || urlWithPostfix[currentPostfixPrefix.length] == "/" || urlWithPostfix[currentPostfixPrefix.length] == "#") postfixPrefix = currentPostfixPrefix;
|
||||||
else return true;
|
else return true;
|
||||||
urlWithPostfix = urlWithPostfix.substr(postfixPrefix.length);
|
urlWithPostfix = urlWithPostfix.substr(postfixPrefix.length);
|
||||||
|
@ -4284,7 +4374,7 @@ if (!cluster.isPrimary) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
wwwrootPostfixesVHost.every(function (postfixEntry) {
|
wwwrootPostfixesVHost.every(function (postfixEntry) {
|
||||||
if (matchHostname(postfixEntry.host) && !(postfixEntry.skipRegex && req.url.match(createRegex(postfixEntry.skipRegex)))) {
|
if (matchHostname(postfixEntry.host) && ipMatch(postfixEntry.ip, req.socket ? req.socket.localAddress : undefined) && !(postfixEntry.skipRegex && req.url.match(createRegex(postfixEntry.skipRegex)))) {
|
||||||
urlWithPostfix = postfixPrefix + "/" + postfixEntry.postfix + urlWithPostfix;
|
urlWithPostfix = postfixPrefix + "/" + postfixEntry.postfix + urlWithPostfix;
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -4347,7 +4437,7 @@ if (!cluster.isPrimary) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite URLs
|
// Rewrite URLs
|
||||||
rewriteURL(req.url, rewriteMap, function(err, rewrittenURL) {
|
rewriteURL(req.url, rewriteMap, function (err, rewrittenURL) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callServerError(500, undefined, err);
|
callServerError(500, undefined, err);
|
||||||
return;
|
return;
|
||||||
|
@ -4412,7 +4502,7 @@ if (!cluster.isPrimary) {
|
||||||
try {
|
try {
|
||||||
res.setHeader(hkS, hkh[hkS]);
|
res.setHeader(hkS, hkh[hkS]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Headers will not be set.
|
// Headers will not be set.
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4446,20 +4536,20 @@ if (!cluster.isPrimary) {
|
||||||
// Scan for non-standard codes
|
// Scan for non-standard codes
|
||||||
if (!isProxy && nonStandardCodes != undefined) {
|
if (!isProxy && nonStandardCodes != undefined) {
|
||||||
for (var i = 0; i < nonStandardCodes.length; i++) {
|
for (var i = 0; i < nonStandardCodes.length; i++) {
|
||||||
if (matchHostname(nonStandardCodes[i].host)) {
|
if (matchHostname(nonStandardCodes[i].host) && ipMatch(nonStandardCodes[i].ip, req.socket ? req.socket.localAddress : undefined)) {
|
||||||
var isMatch = false;
|
var isMatch = false;
|
||||||
if (nonStandardCodes[i].regex) {
|
if (nonStandardCodes[i].regex) {
|
||||||
// Regex match
|
// Regex match
|
||||||
var createdRegex = createRegex(nonStandardCodes[i].regex, true);
|
var createdRegex = createRegex(nonStandardCodes[i].regex, true);
|
||||||
isMatch = req.url.match(createdRegex) || href.match(createdRegex);
|
isMatch = req.url.match(createdRegex) || href.match(createdRegex);
|
||||||
regexI[i] = createdRegex;
|
regexI[i] = createdRegex;
|
||||||
} else {
|
} else {
|
||||||
// Non-regex match
|
// Non-regex match
|
||||||
isMatch = nonStandardCodes[i].url == href || (os.platform() == "win32" && nonStandardCodes[i].url.toLowerCase() == href.toLowerCase());
|
isMatch = nonStandardCodes[i].url == href || (os.platform() == "win32" && nonStandardCodes[i].url.toLowerCase() == href.toLowerCase());
|
||||||
}
|
}
|
||||||
if (isMatch) {
|
if (isMatch) {
|
||||||
if (nonStandardCodes[i].scode == 401) {
|
if (nonStandardCodes[i].scode == 401) {
|
||||||
// HTTP authentication
|
// HTTP authentication
|
||||||
if (authIndex == -1) {
|
if (authIndex == -1) {
|
||||||
authIndex = i;
|
authIndex = i;
|
||||||
}
|
}
|
||||||
|
@ -4670,10 +4760,10 @@ if (!cluster.isPrimary) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (authcode.disableBruteProtection) {
|
if (authcode.disableBruteProtection) {
|
||||||
// Don't brute-force protect it, just do HTTP authentication
|
// Don't brute-force protect it, just do HTTP authentication
|
||||||
authorizedCallback(false);
|
authorizedCallback(false);
|
||||||
} else if (!process.send) {
|
} else if (!process.send) {
|
||||||
// Query data from JS object database
|
// Query data from JS object database
|
||||||
if (!bruteForceDb[reqip] || !bruteForceDb[reqip].lastAttemptDate || (new Date() - 300000 >= bruteForceDb[reqip].lastAttemptDate)) {
|
if (!bruteForceDb[reqip] || !bruteForceDb[reqip].lastAttemptDate || (new Date() - 300000 >= bruteForceDb[reqip].lastAttemptDate)) {
|
||||||
if (bruteForceDb[reqip] && bruteForceDb[reqip].invalidAttempts >= 10) bruteForceDb[reqip] = {
|
if (bruteForceDb[reqip] && bruteForceDb[reqip].invalidAttempts >= 10) bruteForceDb[reqip] = {
|
||||||
invalidAttempts: 5
|
invalidAttempts: 5
|
||||||
|
@ -4794,12 +4884,14 @@ if (!cluster.isPrimary) {
|
||||||
|
|
||||||
var closedMaster = true;
|
var closedMaster = true;
|
||||||
|
|
||||||
|
// IPC listener for server listening signalization
|
||||||
function listenConnListener(msg) {
|
function listenConnListener(msg) {
|
||||||
if (msg == "\x12LISTEN") {
|
if (msg == "\x12LISTEN") {
|
||||||
listeningMessage();
|
listeningMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IPC listener for brue force protection
|
||||||
function bruteForceListenerWrapper(worker) {
|
function bruteForceListenerWrapper(worker) {
|
||||||
return function bruteForceListener(message) {
|
return function bruteForceListener(message) {
|
||||||
var ip = "";
|
var ip = "";
|
||||||
|
@ -4834,6 +4926,7 @@ function bruteForceListenerWrapper(worker) {
|
||||||
var isWorkerHungUpBuff = true;
|
var isWorkerHungUpBuff = true;
|
||||||
var isWorkerHungUpBuff2 = true;
|
var isWorkerHungUpBuff2 = true;
|
||||||
|
|
||||||
|
// General IPC message listener
|
||||||
function msgListener(msg) {
|
function msgListener(msg) {
|
||||||
for (var i = 0; i < Object.keys(cluster.workers).length; i++) {
|
for (var i = 0; i < Object.keys(cluster.workers).length; i++) {
|
||||||
if (msg == "\x12END") {
|
if (msg == "\x12END") {
|
||||||
|
@ -4978,11 +5071,11 @@ function start(init) {
|
||||||
if (process.isBun) {
|
if (process.isBun) {
|
||||||
serverconsole.locwarnmessage("Bun support is experimental. Some features of SVR.JS, SVR.JS mods and SVR.JS server-side JavaScript may not work as expected.");
|
serverconsole.locwarnmessage("Bun support is experimental. Some features of SVR.JS, SVR.JS mods and SVR.JS server-side JavaScript may not work as expected.");
|
||||||
if (users.some(function (entry) {
|
if (users.some(function (entry) {
|
||||||
return entry.pbkdf2;
|
return entry.pbkdf2;
|
||||||
})) serverconsole.locwarnmessage("PBKDF2 password hashing function in Bun blocks the event loop, which may result in denial of service.");
|
})) serverconsole.locwarnmessage("PBKDF2 password hashing function in Bun blocks the event loop, which may result in denial of service.");
|
||||||
if (users.some(function (entry) {
|
if (users.some(function (entry) {
|
||||||
return entry.scrypt;
|
return entry.scrypt;
|
||||||
})) serverconsole.locwarnmessage("scrypt password hashing function in Bun blocks the event loop, which may result in denial of service.");
|
})) serverconsole.locwarnmessage("scrypt password hashing function in Bun blocks the event loop, which may result in denial of service.");
|
||||||
}
|
}
|
||||||
if (cluster.isPrimary === undefined) serverconsole.locwarnmessage("You're running SVR.JS on single thread. Reliability may suffer, as the server is stopped after crash.");
|
if (cluster.isPrimary === undefined) serverconsole.locwarnmessage("You're running SVR.JS on single thread. Reliability may suffer, as the server is stopped after crash.");
|
||||||
if (crypto.__disabled__ !== undefined) serverconsole.locwarnmessage("Your Node.JS version doesn't have crypto support! The 'crypto' module is essential for providing cryptographic functionality in Node.JS. Without crypto support, certain security features may be unavailable, and some functionality may not work as expected. It's recommended to use a Node.JS version that includes crypto support to ensure the security and proper functioning of your server.");
|
if (crypto.__disabled__ !== undefined) serverconsole.locwarnmessage("Your Node.JS version doesn't have crypto support! The 'crypto' module is essential for providing cryptographic functionality in Node.JS. Without crypto support, certain security features may be unavailable, and some functionality may not work as expected. It's recommended to use a Node.JS version that includes crypto support to ensure the security and proper functioning of your server.");
|
||||||
|
@ -5813,20 +5906,22 @@ if (cluster.isPrimary || cluster.isPrimary === undefined) {
|
||||||
process.exit();
|
process.exit();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// Crash handler
|
||||||
process.on("uncaughtException", function (err) {
|
process.on("uncaughtException", function (err) {
|
||||||
// CRASH HANDLER
|
|
||||||
serverconsole.locerrmessage("SVR.JS worker just crashed!!!");
|
serverconsole.locerrmessage("SVR.JS worker just crashed!!!");
|
||||||
serverconsole.locerrmessage("Stack:");
|
serverconsole.locerrmessage("Stack:");
|
||||||
serverconsole.locerrmessage(generateErrorStack(err));
|
serverconsole.locerrmessage(generateErrorStack(err));
|
||||||
process.exit(err.errno);
|
process.exit(err.errno);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("unhandledRejection", function (err) {
|
process.on("unhandledRejection", function (err) {
|
||||||
// CRASH HANDLER
|
|
||||||
serverconsole.locerrmessage("SVR.JS worker just crashed!!!");
|
serverconsole.locerrmessage("SVR.JS worker just crashed!!!");
|
||||||
serverconsole.locerrmessage("Stack:");
|
serverconsole.locerrmessage("Stack:");
|
||||||
serverconsole.locerrmessage(err.stack ? generateErrorStack(err) : String(err));
|
serverconsole.locerrmessage(err.stack ? generateErrorStack(err) : String(err));
|
||||||
process.exit(err.errno);
|
process.exit(err.errno);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Warning handler
|
||||||
process.on("warning", function (warning) {
|
process.on("warning", function (warning) {
|
||||||
serverconsole.locwarnmessage(warning.message);
|
serverconsole.locwarnmessage(warning.message);
|
||||||
if (warning.stack) {
|
if (warning.stack) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SVR.JS 3.14.0 Tests</title>
|
<title>SVR.JS 3.14.1 Tests</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<style>
|
<style>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>SVR.JS 3.14.0 Tests</h1>
|
<h1>SVR.JS 3.14.1 Tests</h1>
|
||||||
<h2>Directory (without trailing slash)</h2>
|
<h2>Directory (without trailing slash)</h2>
|
||||||
<iframe src="/testdir" width="50%" height="300px"></iframe>
|
<iframe src="/testdir" width="50%" height="300px"></iframe>
|
||||||
<h2>Directory (with query)</h2>
|
<h2>Directory (with query)</h2>
|
||||||
|
|
Reference in a new issue