diff --git a/index.html b/index.html index 7a87c60..e572dbe 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ - SVR.JS 3.13.1 + SVR.JS 3.14.0 -

Welcome to SVR.JS 3.13.1

+

Welcome to SVR.JS 3.14.0



@@ -134,8 +134,9 @@

Changes:


Tests
diff --git a/licenses/index.html b/licenses/index.html index 2bc57f2..811d661 100644 --- a/licenses/index.html +++ b/licenses/index.html @@ -1,7 +1,7 @@ - SVR.JS 3.13.1 Licenses + SVR.JS 3.14.0 Licenses -

SVR.JS 3.13.1 Licenses

-

SVR.JS 3.13.1

+

SVR.JS 3.14.0 Licenses

+

SVR.JS 3.14.0

MIT License

@@ -37,7 +37,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-

Packages used by SVR.JS 3.13.1

+

Packages used by SVR.JS 3.14.0

License: MIT
diff --git a/svr.js b/svr.js index 173635b..874c646 100644 --- a/svr.js +++ b/svr.js @@ -69,7 +69,7 @@ function deleteFolderRecursive(path) { } var os = require("os"); -var version = "3.13.1"; +var version = "3.14.0"; var singlethreaded = false; if (process.versions) process.versions.svrjs = version; // Inject SVR.JS into process.versions @@ -1086,6 +1086,8 @@ var useWebRootServerSideScript = true; var exposeModsInErrorPages = true; var disableTrailingSlashRedirects = false; var environmentVariables = {}; +var wwwrootPostfixesVHost = []; +var wwwrootPostfixPrefixesVHost = []; // Get properties from config.json 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.disableTrailingSlashRedirects != undefined) disableTrailingSlashRedirects = configJSON.disableTrailingSlashRedirects; if (configJSON.environmentVariables != undefined) environmentVariables = configJSON.environmentVariables; +if (configJSON.wwwrootPostfixesVHost != undefined) wwwrootPostfixesVHost = configJSON.wwwrootPostfixesVHost; +if (configJSON.wwwrootPostfixPrefixesVHost != undefined) wwwrootPostfixPrefixesVHost = configJSON.wwwrootPostfixPrefixesVHost; var wwwrootError = null; try { @@ -2065,12 +2069,21 @@ if (!cluster.isPrimary) { allowHTTP1: true, requireHostHeader: false, 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 { server = http2.createServer({ allowHTTP1: true, - requireHostHeader: false + requireHostHeader: false, + settings: configJSON.http2Settings }); } } else { @@ -2078,7 +2091,14 @@ if (!cluster.isPrimary) { server = https.createServer({ key: key, 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 { try { @@ -2315,11 +2335,12 @@ if (!cluster.isPrimary) { }); socket.on("error", function () {}); - var head = fs.existsSync("./.head") ? fs.readFileSync("./.head").toString() : (fs.existsSync("./head.html") ? fs.readFileSync("./head.html").toString() : ""); // header - var foot = fs.existsSync("./.foot") ? fs.readFileSync("./.foot").toString() : (fs.existsSync("./foot.html") ? fs.readFileSync("./foot.html").toString() : ""); // footer + // Header and footer placeholders + var head = ""; + var foot = ""; 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. res.write(head + body + foot); res.end(); } @@ -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.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " sent invalid request."); 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_SSL_HTTP_REQUEST" || err.message.indexOf("http request") != -1) { serverconsole.errmessage("Client sent HTTP request to HTTPS port."); @@ -2962,11 +2986,12 @@ if (!cluster.isPrimary) { var acceptEncoding = req.headers["accept-encoding"]; if (!acceptEncoding) acceptEncoding = ""; - var head = fs.existsSync("./.head") ? fs.readFileSync("./.head").toString() : (fs.existsSync("./head.html") ? fs.readFileSync("./head.html").toString() : ""); // header - var foot = fs.existsSync("./.foot") ? fs.readFileSync("./.foot").toString() : (fs.existsSync("./foot.html") ? fs.readFileSync("./foot.html").toString() : ""); // footer + // Header and footer placeholders + var head = ""; + var foot = ""; 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. res.write(head + body + foot); res.end(); } @@ -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 redirect(destination, isTemporary, keepMethod, customHeaders) { @@ -4189,7 +4220,7 @@ if (!cluster.isPrimary) { doCallback = false; 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 { mapEntry.replacements.forEach(function (replacement) { rewrittenURL = rewrittenURL.replace(createRegex(replacement.regex), replacement.replacement); @@ -4237,6 +4268,84 @@ if (!cluster.isPrimary) { 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 rewriteURL(req.url, rewriteMap, function(err, rewrittenURL) { if (err) { diff --git a/tests.html b/tests.html index 418fc9d..c9ddd91 100644 --- a/tests.html +++ b/tests.html @@ -1,7 +1,7 @@ - SVR.JS 3.13.1 Tests + SVR.JS 3.14.0 Tests -

SVR.JS 3.13.1 Tests

+

SVR.JS 3.14.0 Tests

Directory (without trailing slash)

Directory (with query)