1
0
Fork 0
forked from svrjs/svrjs

Update to SVR.JS 3.14.0

This commit is contained in:
Dorian Niemiec 2024-01-24 21:06:17 +01:00
parent 688c850c50
commit 91f2d3b50f
4 changed files with 131 additions and 21 deletions

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>SVR.JS 3.13.1</title> <title>SVR.JS 3.14.0</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.13.1</h1> <h1>Welcome to SVR.JS 3.14.0</h1>
<br/> <br/>
<img src="/logo.png" style="width: 256px;" /> <img src="/logo.png" style="width: 256px;" />
<br/> <br/>
@ -134,8 +134,9 @@
</div> </div>
<p>Changes:</p> <p>Changes:</p>
<ul> <ul>
<li>Fixed error handling for invalid URL rewrite regexes.</li> <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>Fixed bug with non-working HTTP proxy handler (excluding CONNECT method).</li> <li>Added support for web root postfixes (along with postfix prefixes).</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/>

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>SVR.JS 3.13.1 Licenses</title> <title>SVR.JS 3.14.0 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.13.1 Licenses</h1> <h1>SVR.JS 3.14.0 Licenses</h1>
<h2>SVR.JS 3.13.1</h2> <h2>SVR.JS 3.14.0</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.13.1</h2> <h2>Packages used by SVR.JS 3.14.0</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;">

127
svr.js
View file

@ -69,7 +69,7 @@ function deleteFolderRecursive(path) {
} }
var os = require("os"); var os = require("os");
var version = "3.13.1"; var version = "3.14.0";
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
@ -1086,6 +1086,8 @@ var useWebRootServerSideScript = true;
var exposeModsInErrorPages = true; var exposeModsInErrorPages = true;
var disableTrailingSlashRedirects = false; var disableTrailingSlashRedirects = false;
var environmentVariables = {}; var environmentVariables = {};
var wwwrootPostfixesVHost = [];
var wwwrootPostfixPrefixesVHost = [];
// Get properties from config.json // Get properties from config.json
if (configJSON.blacklist != undefined) rawBlackList = configJSON.blacklist; if (configJSON.blacklist != undefined) rawBlackList = configJSON.blacklist;
@ -1139,6 +1141,8 @@ if (configJSON.useWebRootServerSideScript != undefined) useWebRootServerSideScri
if (configJSON.exposeModsInErrorPages != undefined) exposeModsInErrorPages = configJSON.exposeModsInErrorPages; if (configJSON.exposeModsInErrorPages != undefined) exposeModsInErrorPages = configJSON.exposeModsInErrorPages;
if (configJSON.disableTrailingSlashRedirects != undefined) disableTrailingSlashRedirects = configJSON.disableTrailingSlashRedirects; if (configJSON.disableTrailingSlashRedirects != undefined) disableTrailingSlashRedirects = configJSON.disableTrailingSlashRedirects;
if (configJSON.environmentVariables != undefined) environmentVariables = configJSON.environmentVariables; if (configJSON.environmentVariables != undefined) environmentVariables = configJSON.environmentVariables;
if (configJSON.wwwrootPostfixesVHost != undefined) wwwrootPostfixesVHost = configJSON.wwwrootPostfixesVHost;
if (configJSON.wwwrootPostfixPrefixesVHost != undefined) wwwrootPostfixPrefixesVHost = configJSON.wwwrootPostfixPrefixesVHost;
var wwwrootError = null; var wwwrootError = null;
try { try {
@ -2065,12 +2069,21 @@ if (!cluster.isPrimary) {
allowHTTP1: true, allowHTTP1: true,
requireHostHeader: false, requireHostHeader: false,
key: key, key: key,
cert: cert cert: cert,
requestCert: configJSON.useClientCertificate,
rejectUnauthorized: configJSON.rejectUnauthorizedClientCertificates,
ciphers: configJSON.cipherSuite,
ecdhCurve: configJSON.ecdhCurve,
minVersion: configJSON.tlsMinVersion,
maxVersion: configJSON.tlsMaxVersion,
sigalgs: configJSON.signatureAlgorithms,
settings: configJSON.http2Settings
}); });
} else { } else {
server = http2.createServer({ server = http2.createServer({
allowHTTP1: true, allowHTTP1: true,
requireHostHeader: false requireHostHeader: false,
settings: configJSON.http2Settings
}); });
} }
} else { } else {
@ -2078,7 +2091,14 @@ if (!cluster.isPrimary) {
server = https.createServer({ server = https.createServer({
key: key, key: key,
cert: cert, cert: cert,
requireHostHeader: false requireHostHeader: false,
requestCert: configJSON.useClientCertificate,
rejectUnauthorized: configJSON.rejectUnauthorizedClientCertificates,
ciphers: configJSON.cipherSuite,
ecdhCurve: configJSON.ecdhCurve,
minVersion: configJSON.tlsMinVersion,
maxVersion: configJSON.tlsMaxVersion,
sigalgs: configJSON.signatureAlgorithms
}); });
} else { } else {
try { try {
@ -2315,8 +2335,9 @@ if (!cluster.isPrimary) {
}); });
socket.on("error", function () {}); socket.on("error", function () {});
var head = fs.existsSync("./.head") ? fs.readFileSync("./.head").toString() : (fs.existsSync("./head.html") ? fs.readFileSync("./head.html").toString() : ""); // header // Header and footer placeholders
var foot = fs.existsSync("./.foot") ? fs.readFileSync("./.foot").toString() : (fs.existsSync("./foot.html") ? fs.readFileSync("./foot.html").toString() : ""); // footer var head = "";
var foot = "";
function responseEnd(body) { function responseEnd(body) {
// If body is Buffer, then it is converted to String anyway. // If body is Buffer, then it is converted to String anyway.
@ -2464,6 +2485,9 @@ if (!cluster.isPrimary) {
serverconsole.locmessage("Somebody connected to " + (secure && fromMain ? ((typeof sport == "number" ? "port " : "socket ") + sport) : ((typeof port == "number" ? "port " : "socket ") + port)) + "..."); serverconsole.locmessage("Somebody connected to " + (secure && fromMain ? ((typeof sport == "number" ? "port " : "socket ") + sport) : ((typeof port == "number" ? "port " : "socket ") + port)) + "...");
serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " sent invalid request."); serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " sent invalid request.");
try { try {
head = fs.existsSync("./.head") ? fs.readFileSync("./.head").toString() : (fs.existsSync("./head.html") ? fs.readFileSync("./head.html").toString() : ""); // header
foot = fs.existsSync("./.foot") ? fs.readFileSync("./.foot").toString() : (fs.existsSync("./foot.html") ? fs.readFileSync("./foot.html").toString() : ""); // footer
if ((err.code && (err.code.indexOf("ERR_SSL_") == 0 || err.code.indexOf("ERR_TLS_") == 0)) || (!err.code && err.message.indexOf("SSL routines") != -1)) { if ((err.code && (err.code.indexOf("ERR_SSL_") == 0 || err.code.indexOf("ERR_TLS_") == 0)) || (!err.code && err.message.indexOf("SSL routines") != -1)) {
if (err.code == "ERR_SSL_HTTP_REQUEST" || err.message.indexOf("http request") != -1) { if (err.code == "ERR_SSL_HTTP_REQUEST" || err.message.indexOf("http request") != -1) {
serverconsole.errmessage("Client sent HTTP request to HTTPS port."); serverconsole.errmessage("Client sent HTTP request to HTTPS port.");
@ -2962,8 +2986,9 @@ if (!cluster.isPrimary) {
var acceptEncoding = req.headers["accept-encoding"]; var acceptEncoding = req.headers["accept-encoding"];
if (!acceptEncoding) acceptEncoding = ""; if (!acceptEncoding) acceptEncoding = "";
var head = fs.existsSync("./.head") ? fs.readFileSync("./.head").toString() : (fs.existsSync("./head.html") ? fs.readFileSync("./head.html").toString() : ""); // header // Header and footer placeholders
var foot = fs.existsSync("./.foot") ? fs.readFileSync("./.foot").toString() : (fs.existsSync("./foot.html") ? fs.readFileSync("./foot.html").toString() : ""); // footer var head = "";
var foot = "";
function responseEnd(body) { function responseEnd(body) {
// If body is Buffer, then it is converted to String anyway. // If body is Buffer, then it is converted to String anyway.
@ -3128,6 +3153,12 @@ if (!cluster.isPrimary) {
}); });
} }
try {
head = fs.existsSync("./.head") ? fs.readFileSync("./.head").toString() : (fs.existsSync("./head.html") ? fs.readFileSync("./head.html").toString() : ""); // header
foot = fs.existsSync("./.foot") ? fs.readFileSync("./.foot").toString() : (fs.existsSync("./foot.html") ? fs.readFileSync("./foot.html").toString() : ""); // footer
} catch (err) {
callServerError(500, undefined, generateErrorStack(err));
}
// Function to perform HTTP redirection to a specified destination URL // Function to perform HTTP redirection to a specified destination URL
function redirect(destination, isTemporary, keepMethod, customHeaders) { function redirect(destination, isTemporary, keepMethod, customHeaders) {
@ -4189,7 +4220,7 @@ if (!cluster.isPrimary) {
doCallback = false; doCallback = false;
break; break;
} }
if (matchHostname(mapEntry.host) && createRegex(mapEntry.definingRegex).test(address) && !(mapEntry.isNotDirectory && _fileState == 2) && !(mapEntry.isNotFile && _fileState == 1)) { if (matchHostname(mapEntry.host) && 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);
@ -4237,6 +4268,84 @@ if (!cluster.isPrimary) {
var origHref = href; var origHref = href;
// Add web root postfixes
if(!isProxy) {
var urlWithPostfix = req.url;
var postfixPrefix = "";
wwwrootPostfixPrefixesVHost.every(function (currentPostfixPrefix) {
if (req.url.indexOf(currentPostfixPrefix) == 0) {
if (currentPostfixPrefix.match(/\/+$/)) postfixPrefix = currentPostfixPrefix.replace(/\/+$/,"");
else if (urlWithPostfix.length == currentPostfixPrefix.length || urlWithPostfix[currentPostfixPrefix.length] == "?" || urlWithPostfix[currentPostfixPrefix.length] == "/" || urlWithPostfix[currentPostfixPrefix.length] == "#") postfixPrefix = currentPostfixPrefix;
else return true;
urlWithPostfix = urlWithPostfix.substr(postfixPrefix.length);
return false;
} else {
return true;
}
});
wwwrootPostfixesVHost.every(function (postfixEntry) {
if (matchHostname(postfixEntry.host) && !(postfixEntry.skipRegex && req.url.match(createRegex(postfixEntry.skipRegex)))) {
urlWithPostfix = postfixPrefix + "/" + postfixEntry.postfix + urlWithPostfix;
return false;
} else {
return true;
}
});
if (urlWithPostfix != req.url) {
serverconsole.resmessage("Added web root postfix: " + req.url + " => " + urlWithPostfix);
req.url = urlWithPostfix;
uobject = parseURL(req.url);
search = uobject.search;
href = uobject.pathname;
ext = path.extname(href).toLowerCase();
ext = ext.substr(1, ext.length);
try {
decodedHref = decodeURIComponent(href);
} catch (err) {
// Return 400 error
callServerError(400);
serverconsole.errmessage("Bad request!");
return;
}
var sHref = sanitizeURL(href);
var preparedReqUrl2 = uobject.pathname + (uobject.search ? uobject.search : "") + (uobject.hash ? uobject.hash : "");
if (req.url != preparedReqUrl2 || sHref != href.replace(/\/\.(?=\/|$)/g, "/").replace(/\/+/g, "/")) {
callServerError(403);
serverconsole.errmessage("Content blocked.");
return;
} else if (sHref != href) {
var rewrittenAgainURL = uobject;
rewrittenAgainURL.path = null;
rewrittenAgainURL.href = null;
rewrittenAgainURL.pathname = sHref;
rewrittenAgainURL.hostname = null;
rewrittenAgainURL.host = null;
rewrittenAgainURL.port = null;
rewrittenAgainURL.protocol = null;
rewrittenAgainURL.slashes = null;
rewrittenAgainURL = url.format(rewrittenAgainURL);
serverconsole.resmessage("URL sanitized: " + req.url + " => " + rewrittenAgainURL);
req.url = rewrittenAgainURL;
uobject = parseURL(req.url);
search = uobject.search;
href = uobject.pathname;
ext = path.extname(href).toLowerCase();
ext = ext.substr(1, ext.length);
try {
decodedHref = decodeURIComponent(href);
} catch (err) {
// Return 400 error
callServerError(400);
serverconsole.errmessage("Bad request!");
return;
}
}
}
}
// Rewrite URLs // Rewrite URLs
rewriteURL(req.url, rewriteMap, function(err, rewrittenURL) { rewriteURL(req.url, rewriteMap, function(err, rewrittenURL) {
if (err) { if (err) {

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>SVR.JS 3.13.1 Tests</title> <title>SVR.JS 3.14.0 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.13.1 Tests</h1> <h1>SVR.JS 3.14.0 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>