commit 7cebf8d0010dea8e1cc1830d8717820f38758f9b Author: sysadmin Date: Sat Jul 29 23:44:21 2023 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47d6e3b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +commit.sh diff --git a/index.js b/index.js new file mode 100644 index 0000000..d35ed0e --- /dev/null +++ b/index.js @@ -0,0 +1,304 @@ +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 { + spawn +} = require("child_process"); +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 callback(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 + function executeCGI(fname, req, res, dh, nEnv) { + var env = JSON.parse(JSON.stringify(process.env)); + var nEnvKeys = Object.keys(nEnv); + for(var i=0;i 1) lns.shift(); + fs.writeFileSync(__dirname + "/../../../temp/" + tempID, lns.join(require("os").EOL)); + args.push(fname); + filename = args.shift(); + } else { + filename = (process.cwd() + (os.platform() == "win32" ? "\\" + fname.replace(/\//g, "\\") : "/" + fname)).replace(os.platform() == "win32" ? /\\+/ : /\/+/, os.platform() == "win32" ? "\\" : "/") + args = []; + } + } else if(fl.indexOf("\x7fELF") == 0 || fl.indexOf("MZ") == 0) { + 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(fname); + filename = args.shift(); + } + + var wd = fname.split("/"); + wd[0] = ""; + wd[wd.length-1] = ""; + wd = wd.join(os.platform() == "win32" ? "\\" : "/"); + var interpreter = 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\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)/); + var bheaderso = {}; + if (dh) bheaderso = dh; + var code = 200; + var msg = "OK"; + if (bheaders[0].indexOf("HTTP/") == 0) { + var heada = bheaders.shift(); + code = heada.split(" ")[1]; + if (heada.split(" ")[2] !== undefined) msg = heada.split(" ").splice(2).join(" "); + } else if (bheaders[0].indexOf(":") == -1) { + var heada = bheaders.shift(); + code = heada.split(" ")[0]; + if (heada.split(" ")[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) { + var nEnv = {}; + 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; + nEnv["SERVER_PORT"] = port; + nEnv["SERVER_ADDR"] = pubip.replace(/^::ffff:/i, ""); + nEnv["SERVER_NAME"] = req.headers.host; + nEnv["DOCUMENT_ROOT"] = process.cwd(); + nEnv["PATH_INFO"] = b; + nEnv["PATH_TRANSLATED"] = (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"] = req.url; + 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.remoteAddress); + 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.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.indexOf("/cgi-bin") == 0) { + try { + if (fs.existsSync("." + href)) { + var invokeElseCallback = false; + try { + invokeElseCallback = !fs.statSync("." + href).isFile(); + } catch(ex) { } + if (invokeElseCallback) { + elseCallback(); + } else { + try { + 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 unexcepted execption. Below, stack of the error is shown:

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

Please contact with 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); + } + } + } catch (ex) { + if (!callServerError) { + res.writeHead(500); + res.end(ex.stack); + } else { + callServerError(500, "RedBrick/" + version, ex); + } + } + } + } else { + function checkPath(pth, a) { + var cpth = pth.split("/"); + if (cpth.length < 3) return false; + if(!a) b = []; + else var b = a.split("/"); + var isFile = false; + try { + isFile = fs.statSync(pth).isFile(); + } catch (ex) {} + if (fs.existsSync(pth) && isFile) { + return { + fpth: pth, + rpth: "/" + a + } + } else { + b.unshift(cpth.pop()); + return checkPath(cpth.join("/"), b.join("/")); + } + } + var pathp = checkPath("." + href); + if (pathp == false) { + 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 unexcepted execption. Below, stack of the error is shown:

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

Please contact with 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); + } + } + } + } + + } catch (ex) { + if (!callServerError) { + res.writeHead(500, "Internal Server Error", abheaders); + res.write("500 Internal Server Error

500 Internal Server Error

A server had unexcepted execption. Below, stack of the error is shown:

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

Please contact with 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(); + } + } +} +module.exports = Mod; diff --git a/mod.info b/mod.info new file mode 100755 index 0000000..3f975f9 --- /dev/null +++ b/mod.info @@ -0,0 +1,4 @@ +{ + "name": "DorianTech RedBrick CGI engine for SVR.JS", + "version": "2.1.0" +}