commit 47068ba0b075101a34b87a76409150ddab3faee7 Author: Dorian Niemiec Date: Fri Feb 16 19:58:44 2024 +0100 Initial commit diff --git a/index.js b/index.js new file mode 100644 index 0000000..c1bc14f --- /dev/null +++ b/index.js @@ -0,0 +1,861 @@ +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 net = require("net"); +var stream = require("stream"); +var EventEmitter = require("events"); + +var version = "UNKNOWN"; +try { + version = JSON.parse(fs.readFileSync(__dirname + "/mod.info")).version; +} catch (ex) { + // Can't determine version +} +var configJSONS = {}; +try { + configJSONS = JSON.parse(fs.readFileSync(__dirname + "/../../../config.json")); // Read configuration JSON +} catch (ex) { + //GreenRhombus will not care about configJSONS in SVR.JS 3.x and newer + //SVR.JS 2.x and older will fail to start with broken configuration file anyway... +} +var fastcgiConf = {}; +try { + fastcgiConf = JSON.parse(fs.readFileSync(__dirname + "/../../../greenrhombus-config.json")); +} catch (ex) { + // Use defaults +} + +var scriptExts = []; +try { + scriptExts = JSON.parse(fs.readFileSync(__dirname + "/../../../greenrhombus-scriptexts.json")); +} catch (ex) { + +} + +function createFastCGIHandler(options) { + var requestID = options.requestID; + if (!requestID) requestID = 1; + + var BEGIN_REQUEST = 1; + var ABORT_REQUEST = 2; + var END_REQUEST = 3; + var PARAMS = 4; + var STDIN = 5; + var STDOUT = 6; + var STDERR = 7; + var DATA = 8; + var GET_VALUES = 9; + var GET_VALUES_RESULT = 10; + var UNKNOWN_TYPE = 11; + + var RESPONDER = 1; + var AUTHORIZER = 2; + var FILTER = 3; + + // Response codes + var REQUEST_COMPLETE = 0; + var CANT_MPX_CONN = 1; + var OVERLOADED = 2; + var UNKNOWN_ROLE = 3; + + function buildFastCGIPacket(type, requestID, content) { + var packet = Buffer.alloc(content.length + (content.length % 8) + 8); + packet.writeUInt8(1, 0); //version + packet.writeUInt8(type, 1); //type + packet.writeUInt16BE(requestID, 2); //requestId + packet.writeUInt16BE(content.length, 4); //contentLength + packet.writeUInt8(content.length % 8, 6); //paddingLength + packet.writeUInt8(0, 7); //reserved + Buffer.from(content).copy(packet, 8); //content + return packet; + } + + function parseFastCGIPacket(packet) { + var data = {}; + data.fcgiVersion = packet.readUInt8(0); //version + data.type = packet.readUInt8(1); //type + data.requestID = packet.readUInt16BE(2); //requestId + data.content = packet.subarray(8, 8 + packet.readUInt16BE(4)); //contentLength + return data; + } + + function writeFastCGIPacket(socket, type, requestID, content) { + if (content.length != 0) { + var contentSlices = Math.ceil(content.length / 65535); + var chunk = {}; + for (var i = 0; i < contentSlices; i++) { + var chunkOffset = 65536 * i; + var chunkSize = Math.min(65535, content.length - chunkOffset); + chunk = Buffer.alloc(chunkSize); + content.copy(chunk, 0, chunkOffset, chunkOffset + chunkSize); + socket.write(buildFastCGIPacket(type, requestID, chunk)); + } + } else { + socket.write(buildFastCGIPacket(type, requestID, Buffer.alloc(0))); + } + } + + function buildNameValuePair(name, value) { + if (typeof name == "undefined" || typeof value == "undefined") return Buffer.alloc(0); + name = String(name); + value = String(value); + var nameLength = name.length; + var valueLength = value.length; + var nameLengthBytes = nameLength > 127 ? 4 : 1; + var valueLengthBytes = valueLength > 127 ? 4 : 1; + var pair = Buffer.alloc(nameLength + valueLength + nameLengthBytes + valueLengthBytes); + + //nameLength + if (nameLengthBytes == 4) { + pair.writeUInt32BE(Math.min(0xFFFFFFFF, 0x80000000 + nameLength), 0); + } else { + pair.writeUInt8(nameLength, 0); + } + + //valueLength + if (valueLengthBytes == 4) { + pair.writeUInt32BE(Math.min(0xFFFFFFFF, 0x80000000 + valueLength), nameLengthBytes); + } else { + pair.writeUInt8(valueLength, nameLengthBytes); + } + + Buffer.from(name).copy(pair, nameLengthBytes + valueLengthBytes); //nameData + Buffer.from(value).copy(pair, nameLengthBytes + valueLengthBytes + nameLength); //valueData + + return pair; + } + + function fastCGISocketHandler(chunk) { + var chunkIndex = 0; + while (chunkIndex < chunk.length || (headerIndex == 8 && bodyIndex == packetBody.length && paddingLength == 0)) { + if (headerIndex < 8) { + chunk.copy(packetHeader, headerIndex, chunkIndex, Math.min(chunk.length, chunkIndex + 8 - headerIndex)); + var ic = Math.min(chunk.length - chunkIndex, 8 - headerIndex); + headerIndex += ic; + chunkIndex += ic; + if (headerIndex == 8) { + packetBody = Buffer.alloc(packetHeader.readUInt16BE(4)); + paddingLength = packetHeader.readUInt8(6); + } + } else if (headerIndex == 8 && bodyIndex < packetBody.length) { + chunk.copy(packetBody, bodyIndex, chunkIndex, Math.min(chunk.length, chunkIndex + packetBody.length - bodyIndex)); + var ic = Math.min(chunk.length - chunkIndex, packetBody.length - bodyIndex); + bodyIndex += ic; + chunkIndex += ic; + } else if (headerIndex == 8 && bodyIndex == packetBody.length && paddingIndex <= paddingLength) { + var ic = Math.min(chunk.length - chunkIndex, paddingLength - paddingIndex); + paddingIndex += ic; + chunkIndex += ic; + if (paddingIndex == paddingLength) { + headerIndex = 0; + bodyIndex = 0; + paddingIndex = 0; + var packet = Buffer.alloc(8 + packetBody.length + paddingLength); + packetHeader.copy(packet); + packetBody.copy(packet, 8); + processFastCGIPacket(packet); + } + } + } + } + + function processFastCGIPacket(packet) { + var processedPacket = parseFastCGIPacket(packet); + if (processedPacket.requestID != requestID) return; //Drop the packet + if (processedPacket.type == STDOUT) { + emulatedStdout.push(processedPacket.content); + } else if (processedPacket.type == STDERR) { + emulatedStderr.push(processedPacket.content); + } else if (processedPacket.type == END_REQUEST && processedPacket.content.length > 5) { + if (typeof socket !== "undefined") socket.removeListener("data", fastCGISocketHandler); + var appStatus = processedPacket.content.readUInt32BE(0); + var protocolStatus = processedPacket.content.readUInt8(4); + emulatedStdout.push(null); + emulatedStderr.push(null); + if (protocolStatus != REQUEST_COMPLETE) { + var err = new Error("Unknown error"); + if (protocolStatus == OVERLOADED) { + err = new Error("FastCGI server overloaded"); + err.code = "EMFILE"; + err.errno = 24; + } else if (protocolStatus == UNKNOWN_ROLE) { + err = new Error("Role not supported by the FastCGI application"); + } else if (protocolStatus == CANT_MPX_CONN) { + err = new Error("Multiplexed connections not supported by the FastCGI application"); + } + eventEmitter.emit("error", err); + } else { + eventEmitter.emit("exit", appStatus, null); + } + } + } + + var eventEmitter = new EventEmitter(); + var packetHeader = Buffer.alloc(8); + var packetBody = {}; + var paddingLength = 0; + var headerIndex = 0; + var bodyIndex = 0; + var paddingIndex = 0; + + var emulatedStdin = new stream.Writable({ + write: function (chunk, encoding, callback) { + try { + if (chunk.length != 0) { + writeFastCGIPacket(socket, STDIN, requestID, chunk); + } + callback(null); + } catch (err) { + callback(err); + } + }, + final: function (callback) { + try { + writeFastCGIPacket(socket, STDIN, requestID, Buffer.alloc(0)); + } catch (err) { + //writing failed + } + callback(); + } + }); + + var emulatedStdout = new stream.Readable({ + read: function () {} + }); + var emulatedStderr = new stream.Readable({ + read: function () {} + }); + + function init() { + //Begin the request + var beginPacket = Buffer.alloc(8); + beginPacket.writeUInt16BE(RESPONDER, 0); //FastCGI responder + beginPacket.writeUInt8(0, 2); //Don't keep alive + writeFastCGIPacket(socket, BEGIN_REQUEST, requestID, beginPacket); + + //Environment variables + var envPacket = Buffer.alloc(0); + Object.keys(options.env).forEach(function (key) { + envPacket = Buffer.concat([envPacket, buildNameValuePair(key, options.env[key])]); + }); + if(envPacket.length > 0) writeFastCGIPacket(socket, PARAMS, requestID, envPacket); + writeFastCGIPacket(socket, PARAMS, requestID, Buffer.alloc(0)); + } + + eventEmitter.stdin = emulatedStdin; + eventEmitter.stdout = emulatedStdout; + eventEmitter.stderr = emulatedStderr; + eventEmitter.init = init; + + //Create socket + var socket = net.createConnection(options, function () { + eventEmitter.emit("connect"); + }).on("error", function (err) { + emulatedStdout.push(null); + emulatedStderr.push(null); + eventEmitter.emit("error", err); + }).on("data", fastCGISocketHandler); + + return eventEmitter; +} + +// Load default configuration +if (fastcgiConf.path !== undefined) fastcgiConf.path = fastcgiConf.path.replace(/([^\/])\/+$/, "$1"); +if (fastcgiConf.socketPath === undefined) { + if (fastcgiConf.host === undefined) fastcgiConf.host = "localhost"; + if (fastcgiConf.port === undefined) fastcgiConf.port = 4000; +} + +var disableModExposeSupported = process.versions.svrjs && process.versions.svrjs.match(/^(?:Nightly-|(?:[4-9]|[123][0-9])[0-9]*\.|3\.(?:[1-9][0-9]+\.|9\.(?:[1-9])|4\.(?:(?:[3-9]|[12][0-9])[0-9]+|29)))/i); + +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, authUser) { + return function () { + if (!configJSON) { + configJSON = configJSONS; + } + + function checkIfThereIsA401Rule() { + var actually401 = false; + + function createRegex(regex) { + var regexObj = regex.split("/"); + if (regexObj.length == 0) throw new Error("Invalid regex!"); + var modifiers = regexObj.pop(); + regexObj.shift(); + var searchString = regexObj.join("/"); + return new RegExp(searchString, modifiers); + } + + if (configJSON.nonStandardCodes) { + configJSON.nonStandardCodes.every(function (nonscode) { + if (nonscode.scode == 401) { + if (nonscode.regex && (req.url.match(createRegex(nonscode.regex)) || href.match(createRegex(nonscode.regex)))) { + actually401 = true; + return true; + } else if (nonscode.url && (nonStandardCodes[i].url == href || (os.platform() == "win32" && nonStandardCodes[i].url.toLowerCase() == href.toLowerCase()))) { + actually401 = true; + return true; + } + } + return false; + }); + } + return actually401; + } + + 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)); + var socket = {}; + + function executeFastCGI(req, res, dh, nEnv) { + // Function to execute FastCGI 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 buffer = ""; + var stderr = ""; + var headerendline = -1; + var cned = false; + var dataHandler = function (data) { + if (!cned) 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(" "); + } + } + var hasLocation = false; + 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 { + if (headern.toLowerCase() == "location") hasLocation = true; + bheaderso[headern] = headerv; + } + } + + if ((code < 300 || code > 399) && hasLocation) { + code = 302; + msg = "Found"; + } + + try { + res.writeHead(code, msg, bheaderso); + res.write(buffer.substr(headerendline + eol.length), "latin1"); + } catch (ex) { + handler.removeAllListeners("exit"); + handler.stdout.removeAllListeners("dat"); + if (!callServerError) { + res.writeHead(500); + res.end(ex.stack); + } else { + callServerError(500, "GreenRhombus/" + version, ex); + } + return; + } + } else { + if (cned && !res.finished) { + res.write(data); + handler.stdout.removeListener("data", dataHandler); + handler.stdout.pipe(res, { + end: false + }); + } + } + }; + + var options = { + host: fastcgiConf.host, + port: fastcgiConf.port, + path: fastcgiConf.socketPath, + env: env + }; + + handler = createFastCGIHandler(options); + handler.on("error", function (error) { + var errorcode = (error.code == "ENOTFOUND" || error.code == "EHOSTUNREACH" || error.code == "ECONNREFUSED") ? 503 : 500; + if (!callServerError) { + res.writeHead(errorcode, { + "Content-Type": "text/html", + "Server": "GreenRhombus/" + version + }); + res.end("

GreenRhombus Error!

Reason: " + error.message + "

"); + } else { + callServerError(errorcode, "GreenRhombus/" + version, error); + } + }); + + handler.on("connect", function () { + handler.init(); + handler.stdout.on("data", dataHandler); + handler.stderr.on("data", function (data) { + stderr += data.toString(); + }); + req.pipe(handler.stdin); + handler.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, "GreenRhombus/" + version, ex); + } + } else { + var preparedStderr = stderr.trim(); + if (preparedStderr) { + serverconsole.errmessage("There were FastCGI application errors:"); + serverconsole.errmessage(preparedStderr); + } + handler.stdout.unpipe(res); //Prevent server crashes with write after the end + res.end(); + } + }); + }); + } + + function executeFastCGIWithEnv(a, b, req, res, pubip, port, software, dh, user, cPath) { + // Function to set up environment variables and execute sCGI scripts + var nEnv = {}; + if (typeof user != "undefined") { + if (user !== null) { + if (req.headers.authorization) nEnv["AUTH_TYPE"] = req.headers.authorization.split(" ")[0]; + nEnv["REMOTE_USER"] = user; + } + } else if (req.headers.authorization && (typeof checkIfThereIsA401Rule == "undefined" || checkIfThereIsA401Rule())) { + 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"] = "greenrhombus_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_greenrhombus_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["SCRIPT_NAME"] = cPath; + nEnv["SCRIPT_FILENAME"] = (process.cwd() + (require("os").platform == "win32" ? cPath.replace(/\//g, "\\") : cPath)).replace((require("os").platform == "win32" ? /\\\\/g : /\/\//g), (require("os").platform == "win32" ? "\\" : "/")); + nEnv["PATH_INFO"] = decodeURIComponent(b); + nEnv["PATH_TRANSLATED"] = b ? ((process.cwd() + decodeURIComponent(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["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, ""); + if (req.socket.realRemoteAddress && req.socket.realRemotePort) { + nEnv["REMOTE_PORT"] = req.socket.realRemotePort; + } else if (!(req.socket.realRemoteAddress && !req.socket.realRemotePort)) { + nEnv["REMOTE_PORT"] = req.socket.remotePort; + } + if (req.socket.encrypted) nEnv["HTTPS"] = "ON"; + if (req.headers["content-type"]) nEnv["CONTENT_TYPE"] = req.headers["content-type"]; + nEnv["CONTENT_LENGTH"] = "0"; + 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]]; + } + executeFastCGI(req, res, dh, nEnv); + } + + var isScriptExt = scriptExts.indexOf("." + ext) != -1; + + + if (fastcgiConf.path !== undefined && (href == fastcgiConf.path || href.indexOf(fastcgiConf.path + "/") == 0)) { + try { + executeFastCGIWithEnv( + decodeURIComponent(href), + href.replace(fastcgiConf.path, ""), + req, + res, + req.socket.localAddress, + req.socket.localPort, + getCustomHeaders ? + getCustomHeaders()["Server"] + + (disableModExposeSupported && (configJSON.exposeModsInErrorPages || configJSON.exposeModsInErrorPages === undefined) ? + " GreenRhombus/" + + version : "") : + "SVR.JS/" + + configJSON.version + + " (" + + os.platform()[0].toUpperCase() + + os.platform().slice(1) + + "; Node.JS/" + + process.version + + ") GreenRhombus/" + + version, + bheaders, + authUser, + fastcgiConf.path + ); + } 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 + + ") GreenRhombus/" + + version + + " " + + (req.headers.host == undefined ? "" : " on " + req.headers.host) + + "

" + ); + res.end(); + } else { + callServerError(500, "GreenRhombus/" + version, ex); + } + } + } else if ((href == "/greenrhombus-config.json" || (os.platform() == "win32" && href.toLowerCase() == "/greenrhombus-config.json")) && path.normalize(__dirname + "/../../..") == process.cwd()) { + if (!callServerError) { + res.writeHead(200, "OK", { + "Content-Type": "application/json", + "Server": "GreenRhombus/" + version + }); + res.end(JSON.stringify(exttointerpreteruser, null, 2)); + } else { + callServerError(200, "GreenRhombus/" + version, exttointerpreteruser); + } + } else { + fs.stat("." + decodeURIComponent(href), function (err, stats) { + if (!err) { + if (!stats.isFile()) { + if (scriptExts.indexOf(".php") != -1) { + fs.stat("." + decodeURIComponent(href) + "/index.php", function (e2, s2) { + if (!e2 && s2.isFile()) { + try { + executeFastCGIWithEnv( + (decodeURIComponent(href) + "/index.php").replace(/\/+/g, "/"), + "", + req, + res, + req.socket.localAddress, + req.socket.localPort, + getCustomHeaders ? + getCustomHeaders()["Server"] + + (disableModExposeSupported && (configJSON.exposeModsInErrorPages || configJSON.exposeModsInErrorPages === undefined) ? + " GreenRhombus/" + + version : "") : + "SVR.JS/" + + configJSON.version + + " (" + + os.platform()[0].toUpperCase() + + os.platform().slice(1) + + "; Node.JS/" + + process.version + + ") GreenRhombus/" + + version, + bheaders, + authUser, + (decodeURIComponent(href) + "/index.php").replace(/\/+/g, "/") + ); + } 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 + + ") GreenRhombus/" + + version + + " " + + (req.headers.host == undefined ? "" : " on " + req.headers.host) + + "

" + ); + res.end(); + } else { + callServerError(500, "GreenRhombus/" + version, ex); + } + } + } else { + elseCallback(); + } + }); + } else if (scriptExts.indexOf(".cgi") != -1) { + fs.stat("." + decodeURIComponent(href) + "/index.cgi", function (e3, s3) { + if (!e3 && s3.isFile()) { + try { + executeFastCGIWithEnv( + (decodeURIComponent(href) + "/index.cgi").replace(/\/+/g, "/"), + "", + req, + res, + req.socket.localAddress, + req.socket.localPort, + getCustomHeaders ? + getCustomHeaders()["Server"] + + (disableModExposeSupported && (configJSON.exposeModsInErrorPages || configJSON.exposeModsInErrorPages === undefined) ? + " GreenRhombus/" + + version : "") : + "SVR.JS/" + + configJSON.version + + " (" + + os.platform()[0].toUpperCase() + + os.platform().slice(1) + + "; Node.JS/" + + process.version + + ") GreenRhombus/" + + version, + bheaders, + authUser, + (decodeURIComponent(href) + "/index.cgi").replace(/\/+/g, "/") + ); + } 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 + + ") GreenRhombus/" + + version + + " " + + (req.headers.host == undefined ? "" : " on " + req.headers.host) + + "

" + ); + res.end(); + } else { + callServerError(500, "GreenRhombus/" + version, ex); + } + } + } else { + elseCallback(); + } + }); + } else { + elseCallback(); + } + } else { + if (isScriptExt) { + try { + executeFastCGIWithEnv( + decodeURIComponent(href), + "", + req, + res, + req.socket.localAddress, + req.socket.localPort, + getCustomHeaders ? + getCustomHeaders()["Server"] + + (disableModExposeSupported && (configJSON.exposeModsInErrorPages || configJSON.exposeModsInErrorPages === undefined) ? + " GreenRhombus/" + + version : "") : + "SVR.JS/" + + configJSON.version + + " (" + + os.platform()[0].toUpperCase() + + os.platform().slice(1) + + "; Node.JS/" + + process.version + + ") GreenRhombus/" + + version, + bheaders, + authUser, + decodeURIComponent(href) + ); + } 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 + + ") GreenRhombus/" + + version + + " " + + (req.headers.host == undefined ? "" : " on " + req.headers.host) + + "

" + ); + res.end(); + } else { + callServerError(500, "GreenRhombus/" + version, ex); + } + } + } else { + elseCallback(); + } + } + } 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 < 2) { + 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 { + b.unshift(cpth.pop()); + return checkPath(cpth.join("/"), cb, b.join("/")); + } + }); + } + checkPath("." + decodeURIComponent(href), function (pathp) { + if (!pathp) { + elseCallback(); + } else { + var newext = path.extname(pathp.fpth); + if (scriptExts.indexOf(newext) != -1) { + try { + executeFastCGIWithEnv( + pathp.fpth.substr(1), + pathp.rpth, + req, + res, + req.socket.localAddress, + req.socket.localPort, + getCustomHeaders ? + getCustomHeaders()["Server"] + + (disableModExposeSupported && (configJSON.exposeModsInErrorPages || configJSON.exposeModsInErrorPages === undefined) ? + " GreenRhombus/" + + version : "") : + "SVR.JS/" + + configJSON.version + + " (" + + os.platform()[0].toUpperCase() + + os.platform().slice(1) + + "; Node.JS/" + + process.version + + ") GreenRhombus/" + + version, + bheaders, + authUser, + pathp.fpth.substr(1) + ); + } 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 + + ") GreenRhombus/" + + version + + " " + + (req.headers.host == undefined ? "" : " on " + req.headers.host) + + "

" + ); + res.end(); + } else { + callServerError(500, "GreenRhombus/" + version, ex); + } + } + } else { + elseCallback(); + } + } + }); + } else { + elseCallback(); //Invoke default error handler + } + }); + } + } +} + +module.exports = Mod; diff --git a/mod.info b/mod.info new file mode 100755 index 0000000..b3e3acb --- /dev/null +++ b/mod.info @@ -0,0 +1,4 @@ +{ + "name": "GreenRhombus FastCGI client for SVR.JS", + "version": "Nightly-GitMain" +}