var https = require("https"); var os = require("os"); var http = require("http"); var url = require("url"); var fs = require("fs"); var path = require("path"); var childProcess = require("child_process"); var readline = require("readline"); var version = "UNKNOWN"; try { version = JSON.parse(fs.readFileSync(__dirname + "/mod.info")).version; } catch (ex) { // Can't determine version } var configJSONS = JSON.parse(fs.readFileSync("config.json")); // Read configuration JSON function Mod() {} Mod.prototype.callback = function (req, res, serverconsole, responseEnd, href, ext, uobject, search, defaultpage, users, page404, head, foot, fd, elseCallback, configJSON, callServerError, getCustomHeaders, origHref, redirect, parsePostData) { return function () { if (!configJSON) { configJSON = configJSONS; } if (!getCustomHeaders) { var bheaders = JSON.parse(JSON.stringify(configJSON.customHeaders)); } else { var bheaders = getCustomHeaders(); } bheaders["Content-Type"] = "text/html"; // HTML output if (!getCustomHeaders) { bheaders["Server"] = "SVR.JS/" + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + ")"; // Add Server header } var abheaders = JSON.parse(JSON.stringify(bheaders)); function executeCGI(fname, req, res, dh, nEnv) { // Function to execute CGI scripts var env = JSON.parse(JSON.stringify(process.env)); var nEnvKeys = Object.keys(nEnv); for (var i = 0; i < nEnvKeys.length; i++) { env[nEnvKeys[i]] = nEnv[nEnvKeys[i]]; } var exttointerpreter = { ".pl": ["perl"], ".py": ["python"], ".sh": ["bash"], ".ksh": ["ksh"], ".csh": ["csh"], ".bat": ["cmd", "/c"], ".cmd": ["cmd", "/c"], ".vbs": ["cscript"], ".jar": ["java"], ".pyw": ["python"], ".rb": ["ruby"], ".php": ["php-cgi"] }; var exttointerpreteruser = {}; fs.readFile(__dirname + "/../../../redbrick-interpreters.json", function (err, data) { if (!err) { try { exttointerpreteruser = JSON.parse(data.toString()); } catch (ex) {} } fs.stat(fname, function (err, stats) { if (err) { if (!callServerError) { res.writeHead(500, { "Content-Type": "text/html", "Server": "RedBrick/" + version }); res.end("

RedBrick Error!

Reason: " + err.message + "

"); } else { callServerError(500, "RedBrick/" + version, err); } return; } if (stats.size == 0) { afterShebangCallback(false); return; } var s = fs.createReadStream(fname); s.on("error", function (err) { if (!callServerError) { res.writeHead(500, { "Content-Type": "text/html", "Server": "RedBrick/" + version }); res.end("

RedBrick Error!

Reason: " + err.message + "

"); } else { callServerError(500, "RedBrick/" + version, err); } return; }).on("open", function () { var rl = readline.createInterface({ input: s, }); rl.once("line", function (line) { rl.close(); if (line.substr(0, 2) == "#!") { var args = line.substr(2).match(/(?:[^" ]|\\(?:.|$)|"[^"]*(?:"|$))+/g); if (!args) args = []; args = args.map(function (arg) { return arg.replace(/"/g, ""); }); afterShebangCallback(args); } else if (line.substr(0, 2) == "MZ" || line.substr(0, 4) == "\x7fELF") { afterShebangCallback("binary"); } else { afterShebangCallback(false); } }); }); }); function afterShebangCallback(passedArgs) { var ext = path.extname(fname); var args = []; var buffer = ""; var stderr = ""; var headerendline = -1; var cned = false; args.push(fname); if (passedArgs == "binary") { filename = (process.cwd() + (os.platform() == "win32" ? "\\" + fname.replace(/\//g, "\\") : "/" + fname)).replace(os.platform() == "win32" ? /\\+/ : /\/+/, os.platform() == "win32" ? "\\" : "/"); args = []; } else if (passedArgs) { if (os.platform() == "win32") { args = passedArgs; args.push((process.cwd() + ("\\" + fname.replace(/\//g, "\\"))).replace(/\\+/, "\\")); filename = args.shift(); } else { filename = (process.cwd() + (os.platform() == "win32" ? "\\" + fname.replace(/\//g, "\\") : "/" + fname)).replace(os.platform() == "win32" ? /\\+/ : /\/+/, os.platform() == "win32" ? "\\" : "/"); args = []; } } else { args = exttointerpreteruser[ext]; if (!args) { args = exttointerpreter[ext]; if (!args) { elseCallback(); return; } } args.push((process.cwd() + (os.platform() == "win32" ? "\\" + fname.replace(/\//g, "\\") : "/" + fname)).replace(os.platform() == "win32" ? /\\+/ : /\/+/, os.platform() == "win32" ? "\\" : "/")); filename = args.shift(); } var wd = fname.split("/"); wd[0] = ""; wd[wd.length - 1] = ""; wd = wd.join(os.platform() == "win32" ? "\\" : "/"); var interpreter = childProcess.spawn(filename, args, { cwd: (process.cwd() + wd).replace(os.platform() == "win32" ? /\\+/ : /\/+/, os.platform() == "win32" ? "\\" : "/"), env: env }); interpreter.on("error", (error) => { if (!callServerError) { res.writeHead(500, { "Content-Type": "text/html", "Server": "RedBrick/" + version }); res.end("

RedBrick Error!

Reason: " + error.message + "

"); } else { callServerError(500, "RedBrick/" + version, error); } }); var dataHandler = function (data) { buffer += data.toString("latin1"); var m = null; if (!cned) m = buffer.match(/(?:\r\n\r\n|\n\r\n\r|\n\n|\r\r)/); if (!cned && m) { cned = true; eol = m[0]; headerendline = m.index; var bheaders = buffer.substr(0, headerendline).split(/(?:\r\n|\n\r|\n|\r)/); var bheaderso = {}; if (dh) bheaderso = dh; var code = 200; var msg = "OK"; if (bheaders[0].indexOf("HTTP/") == 0) { var heada = bheaders.shift(); var hso = heada.split(" "); code = hso[1]; if (hso[2] !== undefined) msg = heada.split(" ").splice(2).join(" "); } else if (bheaders[0].indexOf(":") == -1) { var heada = bheaders.shift(); var hso = heada.split(" "); if (hso[0].match(/^[0-9]{3}$/)) { code = hso[0]; if (hso[1] !== undefined) msg = heada.split(" ").splice(1).join(" "); } } for (var i = 0; i < bheaders.length; i++) { var headerp = bheaders[i].split(": "); var headern = headerp.shift(); var headerv = headerp.join(": "); if (headern.toLowerCase() == "status") { code = headerv.split(" ")[0]; if (headerv.split(" ")[1] !== undefined) msg = headerv.split(" ").splice(1).join(" "); } else if (headern.toLowerCase() == "set-cookie") { if (!bheaderso["Set-Cookie"]) bheaderso["Set-Cookie"] = []; bheaderso["Set-Cookie"].push(headerv); } else { bheaderso[headern] = headerv; } } if (code == 200 && (bheaderso["Location"] || bheaderso["location"])) { code = 302; msg = "Found"; } try { res.writeHead(code, msg, bheaderso); res.write(buffer.substr(headerendline + eol.length), "latin1"); } catch (ex) { if (!callServerError) { res.writeHead(500); res.end(ex.stack); } else { callServerError(500, "RedBrick/" + version, ex); } return; } } else { if (cned && !res.finished) res.write(data); } }; if (interpreter.stdout) { interpreter.stdout.on("data", dataHandler); interpreter.stderr.on("data", function (data) { stderr += data.toString(); }); req.pipe(interpreter.stdin); interpreter.on("exit", (code, signal) => { if (!cned && (signal || code !== 0)) { var ex = new Error("Process execution failed!" + (stderr ? " Reason: " + stderr.trim() : "")); if (!callServerError) { res.writeHead(500); res.end(ex.stack); } else { callServerError(500, "RedBrick/" + version, ex); } } else { res.end(); } }); } } }); } function executeCGIWithEnv(a, b, req, res, pubip, port, software, dh) { // Function to set up environment variables and execute CGI scripts var nEnv = {}; if (req.headers.authorization) { nEnv["AUTH_TYPE"] = req.headers.authorization.split(" ")[0]; if (nEnv["AUTH_TYPE"] == "Basic") { var remoteCred = req.headers.authorization.split(" ")[1]; if (!remoteCred) { nEnv["REMOTE_USER"] = "redbrick_cgi_invalid_user"; } else { var remoteCredDecoded = Buffer.from(remoteCred, "base64").toString("utf8"); nEnv["REMOTE_USER"] = remoteCredDecoded.split(":")[0]; } } else { nEnv["REMOTE_USER"] = "svrjs_this_property_is_not_yet_supported_by_redbrick_cgi"; } } nEnv["QUERY_STRING"] = req.url.split("?")[1]; if (nEnv["QUERY_STRING"] == undefined || nEnv["QUERY_STRING"] == "undefined") nEnv["QUERY_STRING"] = ""; nEnv["SERVER_SOFTWARE"] = software; nEnv["SERVER_PROTOCOL"] = "HTTP/" + req.httpVersion; if (pubip && (port !== null && port !== undefined)) { nEnv["SERVER_PORT"] = port; nEnv["SERVER_ADDR"] = pubip.replace(/^::ffff:/i, ""); if (nEnv["SERVER_ADDR"].indexOf(":") != -1) nEnv["SERVER_ADDR"] = "[" + nEnv["SERVER_ADDR"] + "]"; } if(configJSON.serverAdministratorEmail && configJSON.serverAdministratorEmail != "[no contact information]") { nEnv["SERVER_ADMIN"] = configJSON.serverAdministratorEmail; } nEnv["SERVER_NAME"] = req.headers.host; nEnv["DOCUMENT_ROOT"] = process.cwd(); nEnv["PATH_INFO"] = decodeURI(b); nEnv["PATH_TRANSLATED"] = b ? decodeURI((process.cwd() + (require("os").platform == "win32" ? b.replace(/\//g, "\\") : b)).replace((require("os").platform == "win32" ? /\\\\/g : /\/\//g), (require("os").platform == "win32" ? "\\" : "/"))) : ""; nEnv["REQUEST_METHOD"] = req.method; nEnv["GATEWAY_INTERFACE"] = "CGI/1.1"; nEnv["REQUEST_URI"] = (!origHref || origHref == href) ? req.url : (origHref + (uobject.search ? ("?" + uobject.search) : "")); nEnv["REMOTE_ADDR"] = (req.socket.realRemoteAddress ? req.socket.realRemoteAddress : ((req.headers["x-forwarded-for"] && configJSON.enableIPSpoofing) ? req.headers["x-forwarded-for"].split(",")[0].replace(/ /g, "") : req.socket.remoteAddress)).replace(/^::ffff:/i, ""); nEnv["REMOTE_PORT"] = (req.socket.realRemotePort ? req.socket.realRemotePort : req.socket.remotePort); nEnv["SCRIPT_NAME"] = a; nEnv["SCRIPT_FILENAME"] = (process.cwd() + (require("os").platform == "win32" ? a.replace(/\//g, "\\") : a)).replace((require("os").platform == "win32" ? /\\\\/g : /\/\//g), (require("os").platform == "win32" ? "\\" : "/")); if (req.socket.encrypted) nEnv["HTTPS"] = "ON"; if (req.headers["content-type"]) nEnv["CONTENT_TYPE"] = req.headers["content-type"]; if (req.headers["content-length"]) nEnv["CONTENT_LENGTH"] = req.headers["content-length"]; var nh = JSON.parse(JSON.stringify(req.headers)); delete nh["content-type"]; delete nh["content-length"]; var nhKeys = Object.keys(nh); for (var i = 0; i < nhKeys.length; i++) { nEnv["HTTP_" + nhKeys[i].replace(/[^0-9A-Za-z]+/g, "_").toUpperCase()] = req.headers[nhKeys[i]]; } executeCGI("." + a, req, res, dh, nEnv); } if (href.match(new RegExp("/cgi-bin(?:$|[?#/])", os.platform() == "win32" ? "i" : ""))) { fs.stat("." + href, function (err, stats) { if (!err) { if (!stats.isFile()) { fs.stat("." + href + "/index.php", function (e2, s2) { if (!e2 && s2.isFile()) { try { executeCGIWithEnv( (href + "/index.php").replace(/\/+/g, "/"), "", req, res, req.socket.localAddress, req.socket.localPort, getCustomHeaders ? getCustomHeaders()["Server"] + " RedBrick/" + version : "SVR.JS/" + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version, bheaders ); } catch (ex) { if (!callServerError) { res.writeHead(500, "Internal Server Error", abheaders); res.write( "500 Internal Server Error

500 Internal Server Error

A server had unexpected exception. Below, the stack trace of the error is shown:

" + ex.stack.replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ /g, " ") + "

Please contact the developer/administrator of the website.

SVR.JS " + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version + " " + (req.headers.host == undefined ? "" : " on " + req.headers.host) + "

" ); res.end(); } else { callServerError(500, "RedBrick/" + version, ex); } } } else { fs.stat("." + href + "/index.cgi", function (e3, s3) { if (!e3 && s3.isFile()) { try { executeCGIWithEnv( (href + "/index.cgi").replace(/\/+/g, "/"), "", req, res, req.socket.localAddress, req.socket.localPort, getCustomHeaders ? getCustomHeaders()["Server"] + " RedBrick/" + version : "SVR.JS/" + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version, bheaders ); } catch (ex) { if (!callServerError) { res.writeHead(500, "Internal Server Error", abheaders); res.write( "500 Internal Server Error

500 Internal Server Error

A server had unexpected exception. Below, the stack trace of the error is shown:

" + ex.stack.replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ /g, " ") + "

Please contact the developer/administrator of the website.

SVR.JS " + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version + " " + (req.headers.host == undefined ? "" : " on " + req.headers.host) + "

" ); res.end(); } else { callServerError(500, "RedBrick/" + version, ex); } } } else { elseCallback(); } }); } }); } else { try { executeCGIWithEnv( href, "", req, res, req.socket.localAddress, req.socket.localPort, getCustomHeaders ? getCustomHeaders()["Server"] + " RedBrick/" + version : "SVR.JS/" + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version, bheaders ); } catch (ex) { if (!callServerError) { res.writeHead(500, "Internal Server Error", abheaders); res.write( "500 Internal Server Error

500 Internal Server Error

A server had unexpected exception. Below, the stack trace of the error is shown:

" + ex.stack.replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ /g, " ") + "

Please contact the developer/administrator of the website.

SVR.JS " + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version + " " + (req.headers.host == undefined ? "" : " on " + req.headers.host) + "

" ); res.end(); } else { callServerError(500, "RedBrick/" + version, ex); } } } } else if (err && err.code == "ENOTDIR") { function checkPath(pth, cb, a) { // Function to check the path of the file and execute CGI script var cpth = pth.split("/"); if (cpth.length < 3) { cb(false); return; } if (!a) b = []; else var b = a.split("/"); var isFile = false; fs.stat(pth, function (err, stats) { if (!err && stats.isFile()) { cb({ fpth: pth, rpth: (a !== undefined ? "/" + a : "") }) } else { fs.stat(pth + "/index.php", function (e2, s2) { if (!e2 && s2.isFile()) { cb({ fpth: (pth + "/index.php").replace(/\/+/g, "/"), rpth: (a !== undefined ? "/" + a : "") }) } else { fs.stat(pth + "/index.cgi", function (e3, s3) { if (!e3 && s3.isFile()) { cb({ fpth: (pth + "/index.cgi").replace(/\/+/g, "/"), rpth: (a !== undefined ? "/" + a : "") }) } else { b.unshift(cpth.pop()); return checkPath(cpth.join("/"), cb, b.join("/")); } }); } }); } }); } checkPath("." + href, function (pathp) { if (!pathp) { elseCallback(); } else { try { executeCGIWithEnv( pathp.fpth.substr(1), pathp.rpth, req, res, req.socket.localAddress, req.socket.localPort, getCustomHeaders ? getCustomHeaders()["Server"] + " RedBrick/" + version : "SVR.JS/" + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version, bheaders ); } catch (ex) { if (!callServerError) { res.writeHead(500, "Internal Server Error", abheaders); res.write( "500 Internal Server Error

500 Internal Server Error

A server had unexpected exception. Below, the stack trace of the error is shown:

" + ex.stack.replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ /g, " ") + "

Please contact the developer/administrator of the website.

SVR.JS " + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version + " " + (req.headers.host == undefined ? "" : " on " + req.headers.host) + "

" ); res.end(); } else { callServerError(500, "RedBrick/" + version, ex); } } } }); } else if (err && err.code == "ENOENT") { elseCallback(); //Invoke default error handler } else { if (!callServerError) { res.writeHead(500, "Internal Server Error", abheaders); res.write( "500 Internal Server Error

500 Internal Server Error

A server had unexpected exception. Below, the stack trace of the error is shown:

" + err.stack.replace(/\r\n/g, "
").replace(/\n/g, "
").replace(/\r/g, "
").replace(/ /g, " ") + "

Please contact the developer/administrator of the website.

SVR.JS " + configJSON.version + " (" + os.platform()[0].toUpperCase() + os.platform().slice(1) + "; Node.JS/" + process.version + ") RedBrick/" + version + " " + (req.headers.host == undefined ? "" : " on " + req.headers.host) + "

" ); res.end(); } else { callServerError(500, "RedBrick/" + version, err); } } }); } else if ((href == "/redbrick-interpreters.json" || (os.platform() == "win32" && href.toLowerCase() == "/redbrick-interpreters.json")) && path.normalize(__dirname + "/../../..") == process.cwd()) { if (!callServerError) { res.writeHead(200, "OK", { "Content-Type": "application/json", "Server": "RedBrick/" + version }); res.end(JSON.stringify(exttointerpreteruser, null, 2)); } else { callServerError(200, "RedBrick/" + version, exttointerpreteruser); } } else { elseCallback(); } } } module.exports = Mod;