Compare commits
8 commits
Author | SHA1 | Date | |
---|---|---|---|
91d9a355d8 | |||
86e2b00c25 | |||
55ec899621 | |||
9207c28a5c | |||
ae8ae208c4 | |||
6b2e88c6ab | |||
da71e8d868 | |||
003421eaf2 |
2 changed files with 98 additions and 20 deletions
114
index.js
114
index.js
|
@ -130,6 +130,7 @@ function createFastCGIHandler(options) {
|
||||||
|
|
||||||
function fastCGISocketHandler(chunk) {
|
function fastCGISocketHandler(chunk) {
|
||||||
var chunkIndex = 0;
|
var chunkIndex = 0;
|
||||||
|
|
||||||
while (chunkIndex < chunk.length || (headerIndex == 8 && bodyIndex == packetBody.length && paddingLength == 0)) {
|
while (chunkIndex < chunk.length || (headerIndex == 8 && bodyIndex == packetBody.length && paddingLength == 0)) {
|
||||||
if (headerIndex < 8) {
|
if (headerIndex < 8) {
|
||||||
chunk.copy(packetHeader, headerIndex, chunkIndex, Math.min(chunk.length, chunkIndex + 8 - headerIndex));
|
chunk.copy(packetHeader, headerIndex, chunkIndex, Math.min(chunk.length, chunkIndex + 8 - headerIndex));
|
||||||
|
@ -166,11 +167,27 @@ function createFastCGIHandler(options) {
|
||||||
var processedPacket = parseFastCGIPacket(packet);
|
var processedPacket = parseFastCGIPacket(packet);
|
||||||
if (processedPacket.requestID != requestID) return; //Drop the packet
|
if (processedPacket.requestID != requestID) return; //Drop the packet
|
||||||
if (processedPacket.type == STDOUT) {
|
if (processedPacket.type == STDOUT) {
|
||||||
if(processedPacket.content.length > 0) emulatedStdout.push(processedPacket.content);
|
try {
|
||||||
|
if(processedPacket.content.length > 0) stdoutPush(processedPacket.content);
|
||||||
|
} catch (err) {
|
||||||
|
//STDOUT will be lost instead of crashing the server
|
||||||
|
}
|
||||||
} else if (processedPacket.type == STDERR) {
|
} else if (processedPacket.type == STDERR) {
|
||||||
|
try {
|
||||||
if(processedPacket.content.length > 0) emulatedStderr.push(processedPacket.content);
|
if(processedPacket.content.length > 0) emulatedStderr.push(processedPacket.content);
|
||||||
|
} catch (err) {
|
||||||
|
//STDERR will be lost anyway...
|
||||||
|
}
|
||||||
} else if (processedPacket.type == END_REQUEST && processedPacket.content.length > 5) {
|
} else if (processedPacket.type == END_REQUEST && processedPacket.content.length > 5) {
|
||||||
if (typeof socket !== "undefined") socket.removeListener("data", fastCGISocketHandler);
|
if (typeof socket !== "undefined") {
|
||||||
|
socket.removeListener("data", fastCGISocketHandler);
|
||||||
|
processFastCGIPacket = function() {};
|
||||||
|
try {
|
||||||
|
socket.end(); //Fixes connection not closing properly in Bun
|
||||||
|
} catch (err) {
|
||||||
|
//It is already closed
|
||||||
|
}
|
||||||
|
}
|
||||||
var appStatus = processedPacket.content.readUInt32BE(0);
|
var appStatus = processedPacket.content.readUInt32BE(0);
|
||||||
var protocolStatus = processedPacket.content.readUInt8(4);
|
var protocolStatus = processedPacket.content.readUInt8(4);
|
||||||
if (protocolStatus != REQUEST_COMPLETE) {
|
if (protocolStatus != REQUEST_COMPLETE) {
|
||||||
|
@ -184,23 +201,25 @@ function createFastCGIHandler(options) {
|
||||||
} else if (protocolStatus == CANT_MPX_CONN) {
|
} else if (protocolStatus == CANT_MPX_CONN) {
|
||||||
err = new Error("Multiplexed connections not supported by the FastCGI application");
|
err = new Error("Multiplexed connections not supported by the FastCGI application");
|
||||||
}
|
}
|
||||||
emulatedStdout.push(null);
|
stdoutPush(null);
|
||||||
emulatedStderr.push(null);
|
if (emulatedStdout._readableState && emulatedStdout._readableState.flowing !== null && !emulatedStdout.endEmitted) {
|
||||||
if (emulatedStdout._readableState && emulatedStdout._readableState.length > 0 && emulatedStdout._readableState.flowing !== null) {
|
|
||||||
emulatedStdout.on("end", function() {
|
emulatedStdout.on("end", function() {
|
||||||
|
emulatedStderr.push(null);
|
||||||
eventEmitter.emit("error", err);
|
eventEmitter.emit("error", err);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
emulatedStderr.push(null);
|
||||||
eventEmitter.emit("error", err);
|
eventEmitter.emit("error", err);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emulatedStdout.push(null);
|
stdoutPush(null);
|
||||||
emulatedStderr.push(null);
|
if (emulatedStdout._readableState && emulatedStdout._readableState.flowing !== null && !emulatedStdout.endEmitted) {
|
||||||
if (emulatedStdout._readableState && emulatedStdout._readableState.length > 0 && emulatedStdout._readableState.flowing !== null) {
|
|
||||||
emulatedStdout.on("end", function() {
|
emulatedStdout.on("end", function() {
|
||||||
|
emulatedStderr.push(null);
|
||||||
eventEmitter.emit("exit", appStatus, null);
|
eventEmitter.emit("exit", appStatus, null);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
emulatedStderr.push(null);
|
||||||
eventEmitter.emit("exit", appStatus, null);
|
eventEmitter.emit("exit", appStatus, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,9 +255,48 @@ function createFastCGIHandler(options) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function stdoutPush(data) {
|
||||||
|
if(data === null) {
|
||||||
|
stdoutToEnd = true;
|
||||||
|
} else {
|
||||||
|
stdoutBuffer = Buffer.concat([stdoutBuffer, Buffer.from(data)]);
|
||||||
|
}
|
||||||
|
var hpLength = hp.length;
|
||||||
|
for(var i = 0; i < hpLength; i++) {
|
||||||
|
var func = hp.shift();
|
||||||
|
if(func) func();
|
||||||
|
}
|
||||||
|
emulatedStdout.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
var zeroed = false;
|
||||||
|
var stdoutBuffer = Buffer.alloc(0);
|
||||||
|
var stdoutToEnd = false;
|
||||||
|
var hp = [];
|
||||||
var emulatedStdout = new stream.Readable({
|
var emulatedStdout = new stream.Readable({
|
||||||
read: function () {}
|
read: function (n) {
|
||||||
|
var s = this;
|
||||||
|
var handler = function () {
|
||||||
|
if (stdoutBuffer.length == 0) {
|
||||||
|
if (!stdoutToEnd) {
|
||||||
|
hp.push(handler);
|
||||||
|
s.pause();
|
||||||
|
} else {
|
||||||
|
s.push(null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var bytesToPush = Math.min(stdoutBuffer.length, n);
|
||||||
|
var bufferToPush = stdoutBuffer.subarray(0, bytesToPush);
|
||||||
|
stdoutBuffer = stdoutBuffer.subarray(bytesToPush);
|
||||||
|
s.push(bufferToPush);
|
||||||
|
if (stdoutBuffer.length == 0 && !stdoutToEnd) s.pause();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (n != 0) handler();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
emulatedStdout.pause(); //Reduce backpressure
|
||||||
|
|
||||||
var emulatedStderr = new stream.Readable({
|
var emulatedStderr = new stream.Readable({
|
||||||
read: function () {}
|
read: function () {}
|
||||||
});
|
});
|
||||||
|
@ -268,11 +326,14 @@ function createFastCGIHandler(options) {
|
||||||
var socket = net.createConnection(options, function () {
|
var socket = net.createConnection(options, function () {
|
||||||
eventEmitter.emit("connect");
|
eventEmitter.emit("connect");
|
||||||
}).on("error", function (err) {
|
}).on("error", function (err) {
|
||||||
emulatedStdout.push(null);
|
stdoutPush(null);
|
||||||
emulatedStderr.push(null);
|
emulatedStderr.push(null);
|
||||||
|
eventEmitter.removeAllListeners("exit");
|
||||||
eventEmitter.emit("error", err);
|
eventEmitter.emit("error", err);
|
||||||
}).on("data", fastCGISocketHandler);
|
}).on("data", fastCGISocketHandler);
|
||||||
|
|
||||||
|
eventEmitter.socket = socket;
|
||||||
|
|
||||||
return eventEmitter;
|
return eventEmitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,10 +465,10 @@ Mod.prototype.callback = function (req, res, serverconsole, responseEnd, href, e
|
||||||
|
|
||||||
try {
|
try {
|
||||||
res.writeHead(code, msg, bheaderso);
|
res.writeHead(code, msg, bheaderso);
|
||||||
res.write(buffer.substr(headerendline + eol.length), "latin1");
|
res.write(Buffer.from(buffer.substr(headerendline + eol.length), "latin1"));
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
handler.removeAllListeners("exit");
|
handler.removeAllListeners("exit");
|
||||||
handler.stdout.removeAllListeners("dat");
|
handler.stdout.removeAllListeners("data");
|
||||||
if (!callServerError) {
|
if (!callServerError) {
|
||||||
res.writeHead(500);
|
res.writeHead(500);
|
||||||
res.end(ex.stack);
|
res.end(ex.stack);
|
||||||
|
@ -423,6 +484,7 @@ Mod.prototype.callback = function (req, res, serverconsole, responseEnd, href, e
|
||||||
handler.stdout.pipe(res, {
|
handler.stdout.pipe(res, {
|
||||||
end: false
|
end: false
|
||||||
});
|
});
|
||||||
|
dataHandler = function () {}; //Prevent event listener memory leaks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -434,9 +496,16 @@ Mod.prototype.callback = function (req, res, serverconsole, responseEnd, href, e
|
||||||
env: env
|
env: env
|
||||||
};
|
};
|
||||||
|
|
||||||
handler = createFastCGIHandler(options);
|
var handler = createFastCGIHandler(options);
|
||||||
handler.on("error", function (error) {
|
handler.on("error", function (error) {
|
||||||
var errorcode = (error.code == "ENOTFOUND" || error.code == "EHOSTUNREACH" || error.code == "ECONNREFUSED") ? 503 : 500;
|
var errorcode = 0;
|
||||||
|
if (error.code == "ENOTFOUND" || error.code == "EHOSTUNREACH" || error.code == "ECONNREFUSED") {
|
||||||
|
errorcode = 503;
|
||||||
|
} else if (error.code == "EMFILE") {
|
||||||
|
errorcode = 429;
|
||||||
|
} else {
|
||||||
|
errorcode = 500;
|
||||||
|
}
|
||||||
if (!callServerError) {
|
if (!callServerError) {
|
||||||
res.writeHead(errorcode, {
|
res.writeHead(errorcode, {
|
||||||
"Content-Type": "text/html",
|
"Content-Type": "text/html",
|
||||||
|
@ -448,12 +517,18 @@ Mod.prototype.callback = function (req, res, serverconsole, responseEnd, href, e
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("connect", function () {
|
res.prependListener("close", function() {
|
||||||
handler.init();
|
if(handler.stdout) handler.stdout.unpipe(res); //Prevent server crashes with write after the end
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on("error", function() {}); //Suppress response stream errors
|
||||||
|
|
||||||
|
function handlerConnection() {
|
||||||
handler.stdout.on("data", dataHandler);
|
handler.stdout.on("data", dataHandler);
|
||||||
handler.stderr.on("data", function (data) {
|
handler.stderr.on("data", function (data) {
|
||||||
stderr += data.toString();
|
stderr += data.toString();
|
||||||
});
|
});
|
||||||
|
handler.init();
|
||||||
req.pipe(handler.stdin);
|
req.pipe(handler.stdin);
|
||||||
handler.on("exit", function (code, signal) {
|
handler.on("exit", function (code, signal) {
|
||||||
if (!cned && (signal || code !== 0)) {
|
if (!cned && (signal || code !== 0)) {
|
||||||
|
@ -470,11 +545,14 @@ Mod.prototype.callback = function (req, res, serverconsole, responseEnd, href, e
|
||||||
serverconsole.errmessage("There were FastCGI application errors:");
|
serverconsole.errmessage("There were FastCGI application errors:");
|
||||||
serverconsole.errmessage(preparedStderr);
|
serverconsole.errmessage(preparedStderr);
|
||||||
}
|
}
|
||||||
|
handler.stdout.removeListener("data", dataHandler);
|
||||||
handler.stdout.unpipe(res); //Prevent server crashes with write after the end
|
handler.stdout.unpipe(res); //Prevent server crashes with write after the end
|
||||||
res.end();
|
if(!res.finished) res.end();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
if(typeof handler.socket.connecting == "undefined" || handler.socket.connecting) handler.on("connect", handlerConnection);
|
||||||
|
else if(!handler.socket.destroyed) handlerConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeFastCGIWithEnv(a, b, req, res, pubip, port, software, dh, user, cPath) {
|
function executeFastCGIWithEnv(a, b, req, res, pubip, port, software, dh, user, cPath) {
|
||||||
|
|
2
mod.info
2
mod.info
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"name": "GreenRhombus FastCGI client for SVR.JS",
|
"name": "GreenRhombus FastCGI client for SVR.JS",
|
||||||
"version": "Nightly-GitMain"
|
"version": "1.0.7"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue