From fdac5786787f3fc1d62b291591a016a2fe50aeec Mon Sep 17 00:00:00 2001 From: Dorian Niemiec Date: Sat, 2 Sep 2023 19:12:46 +0200 Subject: [PATCH] Dropped support for HTTP to HTTPS redirect bypass headers --- svr.js | 846 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 421 insertions(+), 425 deletions(-) diff --git a/svr.js b/svr.js index 4f2102d..b000b72 100644 --- a/svr.js +++ b/svr.js @@ -2108,221 +2108,198 @@ if (!cluster.isPrimary) { if (server2.requestTimeout !== undefined && server2.requestTimeout === 0) server2.requestTimeout = 300000; function redirhandler(req, res) { - if (req.headers["force-insecure"] == "true" || req.headers["x-force-insecure"] == "true" || req.headers["x-svr-js-force-insecure"] == "true") { - reqhandler(req, res, false); - } else { - var reqIdInt = Math.round(Math.random() * 16777216); - var reqId = "0".repeat(6 - reqIdInt.toString(16).length) + reqIdInt.toString(16); - var serverconsole = { - climessage: function (msg) { - if (msg.indexOf("\n") != -1) { - msg.split("\n").forEach(function (nmsg) { - serverconsole.climessage(nmsg); - }); - return; - } - console.log("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg); - LOG("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg); - return; - }, - reqmessage: function (msg) { - if (msg.indexOf("\n") != -1) { - msg.split("\n").forEach(function (nmsg) { - serverconsole.reqmessage(nmsg); - }); - return; - } - console.log("\x1b[34mSERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m"); - LOG("SERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg); - return; - }, - resmessage: function (msg) { - if (msg.indexOf("\n") != -1) { - msg.split("\n").forEach(function (nmsg) { - serverconsole.resmessage(nmsg); - }); - return; - } - console.log("\x1b[32mSERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m"); - LOG("SERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg); - return; - }, - errmessage: function (msg) { - if (msg.indexOf("\n") != -1) { - msg.split("\n").forEach(function (nmsg) { - serverconsole.errmessage(nmsg); - }); - return; - } - console.log("\x1b[31mSERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m"); - LOG("SERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg); - return; - }, - locerrmessage: function (msg) { - if (msg.indexOf("\n") != -1) { - msg.split("\n").forEach(function (nmsg) { - serverconsole.locerrmessage(nmsg); - }); - return; - } - console.log("\x1b[41mSERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m"); - LOG("SERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg); - return; - }, - locwarnmessage: function (msg) { - if (msg.indexOf("\n") != -1) { - msg.split("\n").forEach(function (nmsg) { - serverconsole.locwarnmessage(nmsg); - }); - return; - } - console.log("\x1b[43mSERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m"); - LOG("SERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg); - return; - }, - locmessage: function (msg) { - if (msg.indexOf("\n") != -1) { - msg.split("\n").forEach(function (nmsg) { - serverconsole.locmessage(nmsg); - }); - return; - } - console.log("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg); - LOG("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg); + var reqIdInt = Math.round(Math.random() * 16777216); + var reqId = "0".repeat(6 - reqIdInt.toString(16).length) + reqIdInt.toString(16); + var serverconsole = { + climessage: function (msg) { + if (msg.indexOf("\n") != -1) { + msg.split("\n").forEach(function (nmsg) { + serverconsole.climessage(nmsg); + }); return; } - }; + console.log("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg); + LOG("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg); + return; + }, + reqmessage: function (msg) { + if (msg.indexOf("\n") != -1) { + msg.split("\n").forEach(function (nmsg) { + serverconsole.reqmessage(nmsg); + }); + return; + } + console.log("\x1b[34mSERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m"); + LOG("SERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg); + return; + }, + resmessage: function (msg) { + if (msg.indexOf("\n") != -1) { + msg.split("\n").forEach(function (nmsg) { + serverconsole.resmessage(nmsg); + }); + return; + } + console.log("\x1b[32mSERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m"); + LOG("SERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg); + return; + }, + errmessage: function (msg) { + if (msg.indexOf("\n") != -1) { + msg.split("\n").forEach(function (nmsg) { + serverconsole.errmessage(nmsg); + }); + return; + } + console.log("\x1b[31mSERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m"); + LOG("SERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg); + return; + }, + locerrmessage: function (msg) { + if (msg.indexOf("\n") != -1) { + msg.split("\n").forEach(function (nmsg) { + serverconsole.locerrmessage(nmsg); + }); + return; + } + console.log("\x1b[41mSERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m"); + LOG("SERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg); + return; + }, + locwarnmessage: function (msg) { + if (msg.indexOf("\n") != -1) { + msg.split("\n").forEach(function (nmsg) { + serverconsole.locwarnmessage(nmsg); + }); + return; + } + console.log("\x1b[43mSERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m"); + LOG("SERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg); + return; + }, + locmessage: function (msg) { + if (msg.indexOf("\n") != -1) { + msg.split("\n").forEach(function (nmsg) { + serverconsole.locmessage(nmsg); + }); + return; + } + console.log("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg); + LOG("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg); + return; + } + }; - function matchHostname(hostname) { - if (typeof hostname == "undefined" || hostname == "*") { + function matchHostname(hostname) { + if (typeof hostname == "undefined" || hostname == "*") { + return true; + } else if (req.headers.host && hostname.indexOf("*.") == 0 && hostname != "*.") { + var hostnamesRoot = hostname.substr(2); + if (req.headers.host == hostnamesRoot || req.headers.host.indexOf("." + hostnamesRoot) == req.headers.host.length - hostnamesRoot.length - 1) { return true; - } else if (req.headers.host && hostname.indexOf("*.") == 0 && hostname != "*.") { - var hostnamesRoot = hostname.substr(2); - if (req.headers.host == hostnamesRoot || req.headers.host.indexOf("." + hostnamesRoot) == req.headers.host.length - hostnamesRoot.length - 1) { + } + } else if (req.headers.host && req.headers.host == hostname) { + return true; + } + return false; + } + + function getCustomHeaders() { + var ph = JSON.parse(JSON.stringify(customHeaders)); + if(configJSON.customHeadersVHost) { + var vhostP = null; + configJSON.customHeadersVHost.every(function(vhost) { + if(matchHostname(vhost.host)) { + vhostP = vhost; + return false; + } else { return true; } - } else if (req.headers.host && req.headers.host == hostname) { - return true; - } - return false; - } - - function getCustomHeaders() { - var ph = JSON.parse(JSON.stringify(customHeaders)); - if(configJSON.customHeadersVHost) { - var vhostP = null; - configJSON.customHeadersVHost.every(function(vhost) { - if(matchHostname(vhost.host)) { - vhostP = vhost; - return false; - } else { - return true; - } - }); - if(vhostP && vhostP.headers) { - var phNu = JSON.parse(JSON.stringify(vhostP.headers)); - Object.keys(phNu).forEach(function (phNuK) { - ph[phNuK] = phNu[phNuK]; - }); - } - } - Object.keys(ph).forEach(function (phk) { - if (typeof ph[phk] == "string") ph[phk] = ph[phk].replace(/\{path\}/g, req.url); }); - return ph; - } - - 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)) { - var headers = getCustomHeaders(); - res.writeHead(204, "No Content", headers); - res.end(); - return; - } - - req.url = fixNodeMojibakeURL(req.url); - - res.writeHeadNative = res.writeHead; - res.writeHead = function (a, b, c) { - if (parseInt(a) >= 400 && parseInt(a) <= 599) { - serverconsole.errmessage("Server responded with " + a.toString() + " code."); - } else { - serverconsole.resmessage("Server responded with " + a.toString() + " code."); - } - res.writeHeadNative(a, b, c); - }; - - var finished = false; - res.on("finish", function () { - if (!finished) { - finished = true; - serverconsole.locmessage("Client disconnected."); - } - }); - res.on("close", function () { - if (!finished) { - finished = true; - serverconsole.locmessage("Client disconnected."); + if(vhostP && vhostP.headers) { + var phNu = JSON.parse(JSON.stringify(vhostP.headers)); + Object.keys(phNu).forEach(function (phNuK) { + ph[phNuK] = phNu[phNuK]; + }); } + } + Object.keys(ph).forEach(function (phk) { + if (typeof ph[phk] == "string") ph[phk] = ph[phk].replace(/\{path\}/g, req.url); }); + return ph; + } - serverconsole.locmessage("Somebody connected to " + (typeof port == "number" ? "port " : "socket ") + port + "..."); + 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)) { + var headers = getCustomHeaders(); + res.writeHead(204, "No Content", headers); + res.end(); + return; + } - if (req.socket == null) { - serverconsole.errmessage("Client socket is null!!!"); - return; + req.url = fixNodeMojibakeURL(req.url); + + res.writeHeadNative = res.writeHead; + res.writeHead = function (a, b, c) { + if (parseInt(a) >= 400 && parseInt(a) <= 599) { + serverconsole.errmessage("Server responded with " + a.toString() + " code."); + } else { + serverconsole.resmessage("Server responded with " + a.toString() + " code."); } + res.writeHeadNative(a, b, c); + }; - var isProxy = false; - if (req.url.indexOf("/") != 0 && req.url != "*") isProxy = true; - - 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 - var fd = ""; - - function responseEnd(d) { - if (d === undefined) d = fd; - res.write(head + d + foot); - res.end(); + var finished = false; + res.on("finish", function () { + if (!finished) { + finished = true; + serverconsole.locmessage("Client disconnected."); } + }); + res.on("close", function () { + if (!finished) { + finished = true; + serverconsole.locmessage("Client disconnected."); + } + }); - //Error descriptions - var serverErrorDescs = { - 400: "The request you made is invalid.", - 417: "Expectation in Expect property couldn't be satisfied.", - 500: "The server had an unexpected error. Below, the error stack is shown:

{stack}

Please contact with developer/administrator at {contact}.", - 501: "The request requires use of a function, which isn't currently implemented by the server." - }; + serverconsole.locmessage("Somebody connected to " + (typeof port == "number" ? "port " : "socket ") + port + "..."); - //Server error calling method - function callServerError(errorCode, extName, stack, ch) { - function getErrorFileName(list, callback, _i) { - function medCallback(p) { - if(p) callback(p); - else { - if(errorCode == 404) { - fs.access(page404, fs.constants.F_OK, function(err) { - if(err) { - fs.access("." + errorCode.toString(), fs.constants.F_OK, function(err) { - try { - if(err) { - callback(errorCode.toString() + ".html"); - } else { - callback("." + errorCode.toString()); - } - } catch(err2) { - callServerError(500, undefined, generateErrorStack(err2)); - } - }); - } else { - try { - callback(page404); - } catch(err2) { - callServerError(500, undefined, generateErrorStack(err2)); - } - } - }); - } else { - fs.access("." + errorCode.toString(), fs.constants.F_OK, function(err) { + if (req.socket == null) { + serverconsole.errmessage("Client socket is null!!!"); + return; + } + + var isProxy = false; + if (req.url.indexOf("/") != 0 && req.url != "*") isProxy = true; + + 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 + var fd = ""; + + function responseEnd(d) { + if (d === undefined) d = fd; + res.write(head + d + foot); + res.end(); + } + + //Error descriptions + var serverErrorDescs = { + 400: "The request you made is invalid.", + 417: "Expectation in Expect property couldn't be satisfied.", + 500: "The server had an unexpected error. Below, the error stack is shown:

{stack}

Please contact with developer/administrator at {contact}.", + 501: "The request requires use of a function, which isn't currently implemented by the server." + }; + + //Server error calling method + function callServerError(errorCode, extName, stack, ch) { + function getErrorFileName(list, callback, _i) { + function medCallback(p) { + if(p) callback(p); + else { + if(errorCode == 404) { + fs.access(page404, fs.constants.F_OK, function(err) { + if(err) { + fs.access("." + errorCode.toString(), fs.constants.F_OK, function(err) { try { if(err) { callback(errorCode.toString() + ".html"); @@ -2333,248 +2310,267 @@ if (!cluster.isPrimary) { callServerError(500, undefined, generateErrorStack(err2)); } }); - } - } - } - - if(!_i) _i = 0; - if(_i >= list.length) { - medCallback(false); - return; - } - - if(list[_i].scode != errorCode || !matchHostname(list[_i].host)) { - getErrorFileName(list, callback, _i+1); - return; - } else { - fs.access(list[_i].path, fs.constants.F_OK, function(err) { - if(err) { - getErrorFileName(list, callback, _i+1); - } else { - medCallback(list[_i].path); - } - }); - } - } - - getErrorFileName(errorPages, function(errorFile) { - if (Object.prototype.toString.call(stack) === "[object Error]") stack = generateErrorStack(stack); - if (stack === undefined) stack = generateErrorStack(new Error("Unknown error")); - if (errorCode == 500 || errorCode == 502) { - serverconsole.errmessage("There was an error while processing the request!"); - serverconsole.errmessage("Stack:"); - serverconsole.errmessage(stack); - } - if (stackHidden) stack = "[error stack hidden]"; - if (serverErrorDescs[errorCode] === undefined) { - callServerError(501, extName, stack); - } else { - var cheaders = getCustomHeaders(); - if (ch) { - var chon = Object.keys(cheaders); - Object.keys(ch).forEach(function (chnS) { - var nhn = chnS; - for (var j = 0; j < chon.length; j++) { - if (chon[j].toLowerCase() == chnS.toLowerCase()) { - nhn = chon[j]; - break; + } else { + try { + callback(page404); + } catch(err2) { + callServerError(500, undefined, generateErrorStack(err2)); } } - if (ch[chnS]) cheaders[nhn] = ch[chnS]; }); + } else { + fs.access("." + errorCode.toString(), fs.constants.F_OK, function(err) { + try { + if(err) { + callback(errorCode.toString() + ".html"); + } else { + callback("." + errorCode.toString()); + } + } catch(err2) { + callServerError(500, undefined, generateErrorStack(err2)); + } + }); + } + } + } + + if(!_i) _i = 0; + if(_i >= list.length) { + medCallback(false); + return; + } + + if(list[_i].scode != errorCode || !matchHostname(list[_i].host)) { + getErrorFileName(list, callback, _i+1); + return; + } else { + fs.access(list[_i].path, fs.constants.F_OK, function(err) { + if(err) { + getErrorFileName(list, callback, _i+1); + } else { + medCallback(list[_i].path); } - cheaders["Content-Type"] = "text/html; charset=utf-8"; - if (errorCode == 405 && !cheaders["Allow"]) cheaders["Allow"] = "GET, POST, HEAD, OPTIONS"; - fs.readFile(errorFile, function (err, data) { - try { - if (err) throw err; - res.writeHead(errorCode, http.STATUS_CODES[errorCode], cheaders); - fd += data.toString().replace(/{errorMessage}/g, errorCode.toString() + " " + http.STATUS_CODES[errorCode]).replace(/{errorDesc}/g, serverErrorDescs[errorCode]).replace(/{stack}/g, stack.replace(/&/g, "&").replace(//g, ">").replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ {2}/g, "  ")).replace(/{path}/g, req.url.replace(/&/g, "&").replace(//g, ">")).replace(/{server}/g, "" + (exposeServerVersion ? "SVR.JS/" + version + " (" + getOS() + "; " + (process.isBun ? ("Bun/v" + process.versions.bun + "; like Node.JS/" + process.version) : ("Node.JS/" + process.version)) + ")" : "SVR.JS") + (extName == undefined ? "" : " " + extName) + ((req.headers.host == undefined || isProxy) ? "" : " on " + String(req.headers.host).replace(/&/g, "&").replace(//g, ">"))).replace(/{contact}/g, serverAdmin.replace(/\./g, "[dot]").replace(/@/g, "[at]")); - responseEnd(); - } catch (err) { - var additionalError = 500; - if (err.code == "ENOENT") { - additionalError = 404; - } else if (err.code == "ENOTDIR") { - additionalError = 404; // Assume that file doesn't exist - } else if (err.code == "EACCES") { - additionalError = 403; - } else if (err.code == "ENAMETOOLONG") { - additionalError = 414; - } else if (err.code == "EMFILE") { - additionalError = 503; - } else if (err.code == "ELOOP") { - additionalError = 508; + }); + } + } + + getErrorFileName(errorPages, function(errorFile) { + if (Object.prototype.toString.call(stack) === "[object Error]") stack = generateErrorStack(stack); + if (stack === undefined) stack = generateErrorStack(new Error("Unknown error")); + if (errorCode == 500 || errorCode == 502) { + serverconsole.errmessage("There was an error while processing the request!"); + serverconsole.errmessage("Stack:"); + serverconsole.errmessage(stack); + } + if (stackHidden) stack = "[error stack hidden]"; + if (serverErrorDescs[errorCode] === undefined) { + callServerError(501, extName, stack); + } else { + var cheaders = getCustomHeaders(); + if (ch) { + var chon = Object.keys(cheaders); + Object.keys(ch).forEach(function (chnS) { + var nhn = chnS; + for (var j = 0; j < chon.length; j++) { + if (chon[j].toLowerCase() == chnS.toLowerCase()) { + nhn = chon[j]; + break; } - res.writeHead(errorCode, http.STATUS_CODES[errorCode], cheaders); - res.write(("{errorMessage}

{errorMessage}

{errorDesc}

" + ((additionalError == 404) ? "" : "

Additionally, a {additionalError} error occurred while loading an error page.

") + "

{server}

").replace(/{errorMessage}/g, errorCode.toString() + " " + http.STATUS_CODES[errorCode]).replace(/{errorDesc}/g, serverErrorDescs[errorCode]).replace(/{stack}/g, stack.replace(/&/g, "&").replace(//g, ">").replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ {2}/g, "  ")).replace(/{path}/g, req.url.replace(/&/g, "&").replace(//g, ">")).replace(/{server}/g, "" + (exposeServerVersion ? "SVR.JS/" + version + " (" + getOS() + "; " + (process.isBun ? ("Bun/v" + process.versions.bun + "; like Node.JS/" + process.version) : ("Node.JS/" + process.version)) + ")" : "SVR.JS") + (extName == undefined ? "" : " " + extName) + ((req.headers.host == undefined || isProxy) ? "" : " on " + String(req.headers.host).replace(/&/g, "&").replace(//g, ">"))).replace(/{contact}/g, serverAdmin.replace(/\./g, "[dot]").replace(/@/g, "[at]")).replace(/{additionalError}/g, additionalError.toString())); - res.end(); } + if (ch[chnS]) cheaders[nhn] = ch[chnS]; }); } - }); - } - - var reqport = ""; - var reqip = ""; - var oldport = ""; - var oldip = ""; - if (req.headers["x-forwarded-for"] != undefined && enableIPSpoofing) { - reqport = null; - reqip = req.headers["x-forwarded-for"].split(",")[0].replace(/ /g, ""); - if (reqip.indexOf(":") == -1) reqip = "::ffff:" + reqip; - try { - oldport = req.socket.remotePort; - oldip = req.socket.remoteAddress; - req.socket.realRemotePort = reqport; - req.socket.realRemoteAddress = reqip; - req.socket.originalRemotePort = oldport; - req.socket.originalRemoteAddress = oldip; - res.socket.realRemotePort = reqport; - res.socket.realRemoteAddress = reqip; - res.socket.originalRemotePort = oldport; - res.socket.originalRemoteAddress = oldip; - } catch (err) { - //Nevermind... - } - } else { - reqip = req.socket.remoteAddress; - reqport = req.socket.remotePort; - } - reqcounter++; - 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); - else 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.url); - if (req.headers["user-agent"] != undefined) serverconsole.reqmessage("Client uses " + req.headers["user-agent"]); - - try { - if (req.headers["expect"] && req.headers["expect"] != "100-continue") { - serverconsole.errmessage("Expectation not satified!"); - callServerError(417); - return; - } - var hostx = req.headers.host; - if (hostx === undefined) { - serverconsole.errmessage("Bad request!"); - callServerError(400); - return; - } - - if (req.method == "CONNECT") { - callServerError(501); - serverconsole.errmessage("CONNECT requests aren't supported. Your JS runtime probably doesn't support 'connect' handler for HTTP library."); - return; - } - - if (isProxy) { - callServerError(501); - serverconsole.errmessage("This server will never be a proxy."); - return; - } - - function parseURL(uri) { - if (typeof URL != "undefined" && url.Url) { + cheaders["Content-Type"] = "text/html; charset=utf-8"; + if (errorCode == 405 && !cheaders["Allow"]) cheaders["Allow"] = "GET, POST, HEAD, OPTIONS"; + fs.readFile(errorFile, function (err, data) { try { - var uobject = new URL(uri, "http" + (req.socket.encrypted ? "s" : "") + "://" + (req.headers.host ? req.headers.host : (domain ? domain : "unknown.invalid"))); - var nuobject = new url.Url(); - if (uri.indexOf("/") != -1) nuobject.slashes = true; - if (uobject.protocol != "") nuobject.protocol = uobject.protocol; - if (uobject.username != "" && uobject.password != "") nuobject.auth = uobject.username + ":" + uobject.password; - if (uobject.host != "") nuobject.host = uobject.host; - if (uobject.hostname != "") nuobject.hostname = uobject.hostname; - if (uobject.port != "") nuobject.port = uobject.port; - if (uobject.pathname != "") nuobject.pathname = uobject.pathname; - if (uobject.search != "") nuobject.search = uobject.search; - if (uobject.hash != "") nuobject.hash = uobject.hash; - if (uobject.href != "") nuobject.href = uobject.href; - if (uri.indexOf("/") != 0) { - if (nuobject.pathname) { - nuobject.pathname = nuobject.pathname.substr(1); - nuobject.href = nuobject.pathname + (nuobject.search ? nuobject.search : ""); - } - } - if (nuobject.pathname) { - nuobject.path = nuobject.pathname + (nuobject.search ? nuobject.search : ""); - } - nuobject.query = {}; - uobject.searchParams.forEach(function (value, key) { - nuobject.query[key] = value; - }); - return nuobject; + if (err) throw err; + res.writeHead(errorCode, http.STATUS_CODES[errorCode], cheaders); + fd += data.toString().replace(/{errorMessage}/g, errorCode.toString() + " " + http.STATUS_CODES[errorCode]).replace(/{errorDesc}/g, serverErrorDescs[errorCode]).replace(/{stack}/g, stack.replace(/&/g, "&").replace(//g, ">").replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ {2}/g, "  ")).replace(/{path}/g, req.url.replace(/&/g, "&").replace(//g, ">")).replace(/{server}/g, "" + (exposeServerVersion ? "SVR.JS/" + version + " (" + getOS() + "; " + (process.isBun ? ("Bun/v" + process.versions.bun + "; like Node.JS/" + process.version) : ("Node.JS/" + process.version)) + ")" : "SVR.JS") + (extName == undefined ? "" : " " + extName) + ((req.headers.host == undefined || isProxy) ? "" : " on " + String(req.headers.host).replace(/&/g, "&").replace(//g, ">"))).replace(/{contact}/g, serverAdmin.replace(/\./g, "[dot]").replace(/@/g, "[at]")); + responseEnd(); } catch (err) { - return url.parse(uri, true); + var additionalError = 500; + if (err.code == "ENOENT") { + additionalError = 404; + } else if (err.code == "ENOTDIR") { + additionalError = 404; // Assume that file doesn't exist + } else if (err.code == "EACCES") { + additionalError = 403; + } else if (err.code == "ENAMETOOLONG") { + additionalError = 414; + } else if (err.code == "EMFILE") { + additionalError = 503; + } else if (err.code == "ELOOP") { + additionalError = 508; + } + res.writeHead(errorCode, http.STATUS_CODES[errorCode], cheaders); + res.write(("{errorMessage}

{errorMessage}

{errorDesc}

" + ((additionalError == 404) ? "" : "

Additionally, a {additionalError} error occurred while loading an error page.

") + "

{server}

").replace(/{errorMessage}/g, errorCode.toString() + " " + http.STATUS_CODES[errorCode]).replace(/{errorDesc}/g, serverErrorDescs[errorCode]).replace(/{stack}/g, stack.replace(/&/g, "&").replace(//g, ">").replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ {2}/g, "  ")).replace(/{path}/g, req.url.replace(/&/g, "&").replace(//g, ">")).replace(/{server}/g, "" + (exposeServerVersion ? "SVR.JS/" + version + " (" + getOS() + "; " + (process.isBun ? ("Bun/v" + process.versions.bun + "; like Node.JS/" + process.version) : ("Node.JS/" + process.version)) + ")" : "SVR.JS") + (extName == undefined ? "" : " " + extName) + ((req.headers.host == undefined || isProxy) ? "" : " on " + String(req.headers.host).replace(/&/g, "&").replace(//g, ">"))).replace(/{contact}/g, serverAdmin.replace(/\./g, "[dot]").replace(/@/g, "[at]")).replace(/{additionalError}/g, additionalError.toString())); + res.end(); } - } else { + }); + } + }); + } + + var reqport = ""; + var reqip = ""; + var oldport = ""; + var oldip = ""; + if (req.headers["x-forwarded-for"] != undefined && enableIPSpoofing) { + reqport = null; + reqip = req.headers["x-forwarded-for"].split(",")[0].replace(/ /g, ""); + if (reqip.indexOf(":") == -1) reqip = "::ffff:" + reqip; + try { + oldport = req.socket.remotePort; + oldip = req.socket.remoteAddress; + req.socket.realRemotePort = reqport; + req.socket.realRemoteAddress = reqip; + req.socket.originalRemotePort = oldport; + req.socket.originalRemoteAddress = oldip; + res.socket.realRemotePort = reqport; + res.socket.realRemoteAddress = reqip; + res.socket.originalRemotePort = oldport; + res.socket.originalRemoteAddress = oldip; + } catch (err) { + //Nevermind... + } + } else { + reqip = req.socket.remoteAddress; + reqport = req.socket.remotePort; + } + reqcounter++; + 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); + else 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.url); + if (req.headers["user-agent"] != undefined) serverconsole.reqmessage("Client uses " + req.headers["user-agent"]); + + try { + if (req.headers["expect"] && req.headers["expect"] != "100-continue") { + serverconsole.errmessage("Expectation not satified!"); + callServerError(417); + return; + } + var hostx = req.headers.host; + if (hostx === undefined) { + serverconsole.errmessage("Bad request!"); + callServerError(400); + return; + } + + if (req.method == "CONNECT") { + callServerError(501); + serverconsole.errmessage("CONNECT requests aren't supported. Your JS runtime probably doesn't support 'connect' handler for HTTP library."); + return; + } + + if (isProxy) { + callServerError(501); + serverconsole.errmessage("This server will never be a proxy."); + return; + } + + function parseURL(uri) { + if (typeof URL != "undefined" && url.Url) { + try { + var uobject = new URL(uri, "http" + (req.socket.encrypted ? "s" : "") + "://" + (req.headers.host ? req.headers.host : (domain ? domain : "unknown.invalid"))); + var nuobject = new url.Url(); + if (uri.indexOf("/") != -1) nuobject.slashes = true; + if (uobject.protocol != "") nuobject.protocol = uobject.protocol; + if (uobject.username != "" && uobject.password != "") nuobject.auth = uobject.username + ":" + uobject.password; + if (uobject.host != "") nuobject.host = uobject.host; + if (uobject.hostname != "") nuobject.hostname = uobject.hostname; + if (uobject.port != "") nuobject.port = uobject.port; + if (uobject.pathname != "") nuobject.pathname = uobject.pathname; + if (uobject.search != "") nuobject.search = uobject.search; + if (uobject.hash != "") nuobject.hash = uobject.hash; + if (uobject.href != "") nuobject.href = uobject.href; + if (uri.indexOf("/") != 0) { + if (nuobject.pathname) { + nuobject.pathname = nuobject.pathname.substr(1); + nuobject.href = nuobject.pathname + (nuobject.search ? nuobject.search : ""); + } + } + if (nuobject.pathname) { + nuobject.path = nuobject.pathname + (nuobject.search ? nuobject.search : ""); + } + nuobject.query = {}; + uobject.searchParams.forEach(function (value, key) { + nuobject.query[key] = value; + }); + return nuobject; + } catch (err) { return url.parse(uri, true); } - } - var urlp = parseURL("http://" + hostx); - try { - if (urlp.path.indexOf("//") == 0) { - urlp = parseURL("http:" + url.path); - } - } catch (err) { - //URL parse error... - } - if (urlp.host == "localhost" || urlp.host == "localhost:" + port.toString() || urlp.host == "127.0.0.1" || urlp.host == "127.0.0.1:" + port.toString() || urlp.host == "::1" || urlp.host == "::1:" + port.toString()) { - urlp.protocol = "https:"; - if (sport == 443) { - urlp.host = urlp.hostname; - } else { - urlp.host = urlp.hostname + ":" + sport.toString(); - urlp.port = sport.toString(); - } - } else if (urlp.host == (listenAddress ? listenAddress : host) || urlp.host == (listenAddress ? listenAddress : host) + ":" + port.toString()) { - urlp.protocol = "https:"; - if (sport == 443) { - urlp.host = urlp.hostname; - } else { - urlp.host = urlp.hostname + ":" + sport.toString(); - urlp.port = sport.toString(); - } - } else if (urlp.host == pubip || urlp.host == pubip + ":" + pubport.toString()) { - urlp.protocol = "https:"; - if (spubport == 443) { - urlp.host = urlp.hostname; - } else { - urlp.host = urlp.hostname + ":" + spubport.toString(); - urlp.port = spubport.toString(); - } - } else if (urlp.hostname == domain || urlp.hostname.indexOf(domain) != -1) { - urlp.protocol = "https:"; - if (spubport == 443) { - urlp.host = urlp.hostname; - } else { - urlp.host = urlp.hostname + ":" + spubport.toString(); - urlp.port = spubport.toString(); - } } else { - urlp.protocol = "https:"; + return url.parse(uri, true); } - urlp.path = null; - urlp.pathname = null; - var lloc = url.format(urlp); - var requestURL = req.url; - try { - if (requestURL.split("/")[1].indexOf(".onion") != -1) { - requestURL = requestURL.split("/"); - requestURL.shift(); - requestURL.shift(); - requestURL.unshift(""); - requestURL = requestURL.join("/"); - } - } catch (err) { - //Leave URL as it is... - } - var rheaders = getCustomHeaders(); - rheaders["Location"] = lloc + requestURL; - res.writeHead(301, "Redirect to HTTPS", rheaders); - res.end(); - } catch (err) { - serverconsole.errmessage("There was an error while processing the request!"); - serverconsole.errmessage("Stack:"); - serverconsole.errmessage(generateErrorStack(err)); - callServerError(500, undefined, generateErrorStack(err)); } + var urlp = parseURL("http://" + hostx); + try { + if (urlp.path.indexOf("//") == 0) { + urlp = parseURL("http:" + url.path); + } + } catch (err) { + //URL parse error... + } + if (urlp.host == "localhost" || urlp.host == "localhost:" + port.toString() || urlp.host == "127.0.0.1" || urlp.host == "127.0.0.1:" + port.toString() || urlp.host == "::1" || urlp.host == "::1:" + port.toString()) { + urlp.protocol = "https:"; + if (sport == 443) { + urlp.host = urlp.hostname; + } else { + urlp.host = urlp.hostname + ":" + sport.toString(); + urlp.port = sport.toString(); + } + } else if (urlp.host == (listenAddress ? listenAddress : host) || urlp.host == (listenAddress ? listenAddress : host) + ":" + port.toString()) { + urlp.protocol = "https:"; + if (sport == 443) { + urlp.host = urlp.hostname; + } else { + urlp.host = urlp.hostname + ":" + sport.toString(); + urlp.port = sport.toString(); + } + } else if (urlp.host == pubip || urlp.host == pubip + ":" + pubport.toString()) { + urlp.protocol = "https:"; + if (spubport == 443) { + urlp.host = urlp.hostname; + } else { + urlp.host = urlp.hostname + ":" + spubport.toString(); + urlp.port = spubport.toString(); + } + } else if (urlp.hostname == domain || urlp.hostname.indexOf(domain) != -1) { + urlp.protocol = "https:"; + if (spubport == 443) { + urlp.host = urlp.hostname; + } else { + urlp.host = urlp.hostname + ":" + spubport.toString(); + urlp.port = spubport.toString(); + } + } else { + urlp.protocol = "https:"; + } + urlp.path = null; + urlp.pathname = null; + var lloc = url.format(urlp); + var requestURL = req.url; + try { + if (requestURL.split("/")[1].indexOf(".onion") != -1) { + requestURL = requestURL.split("/"); + requestURL.shift(); + requestURL.shift(); + requestURL.unshift(""); + requestURL = requestURL.join("/"); + } + } catch (err) { + //Leave URL as it is... + } + var rheaders = getCustomHeaders(); + rheaders["Location"] = lloc + requestURL; + res.writeHead(301, "Redirect to HTTPS", rheaders); + res.end(); + } catch (err) { + serverconsole.errmessage("There was an error while processing the request!"); + serverconsole.errmessage("Stack:"); + serverconsole.errmessage(generateErrorStack(err)); + callServerError(500, undefined, generateErrorStack(err)); } }