Rename createRouteId to getRouteId and update related references; improve raw body capture stream handling

This commit is contained in:
Debadutta Panda 2025-02-08 10:59:37 +05:30
parent 90328ef75e
commit 7321cd20db

View File

@ -78,7 +78,7 @@ module.exports = function(RED) {
return getRootApp(app.parent) return getRootApp(app.parent)
} }
function createRouteId(req) { function getRouteId(req) {
var method = req.method.toLowerCase(), url = req.url; var method = req.method.toLowerCase(), url = req.url;
return `${method}:${url}`; return `${method}:${url}`;
} }
@ -94,49 +94,63 @@ module.exports = function(RED) {
rootApp.set('httpInNodes', httpInNodes); rootApp.set('httpInNodes', httpInNodes);
// This middleware must always be at the root to handle the raw request body correctly /**
* This middleware must always be at the root to handle the raw request body correctly
* @param {import('express').Request} req
* @param {import('express').Response} _res
* @param {import('express').NextFunction} next
* @returns
*/
function setupRawBodyCapture(req, _res, next) { function setupRawBodyCapture(req, _res, next) {
var httpInNodeId = createRouteId(req) var httpInNodeId = getRouteId(req)
// Check if settings for this ID exist // Check if settings for this ID exist
if (httpInNodes.has(httpInNodeId)) { if (httpInNodes.has(httpInNodeId)) {
// Get the httpInNode by routeId
var httpInNode = httpInNodes.get(httpInNodeId); var httpInNode = httpInNodes.get(httpInNodeId);
// If raw body inclusion is disabled, skip the processing // If raw body inclusion is disabled, skip the processing
if (!httpInNode.includeRawBody) { if (!httpInNode.includeRawBody) {
return next(); return next();
} }
// Create a PassThrough stream to capture the request body // Create a PassThrough stream to capture the request body
var passThrough = new PassThrough(); var cloneStream = new PassThrough();
// Function to handle 'data' event // Function to handle 'data' event
function onData(chunk) { function onData(chunk) {
passThrough.write(chunk); // Continue pushing chunks into clone stream if it is writable.
if (!cloneStream.writable) {
cloneStream.write(chunk);
}
} }
// Function to handle 'end' or 'error' events // Function to handle 'end' or 'error' events
function onEnd(err) { function onEnd(err) {
if (err) { if (err) {
passThrough.destroy(err); // If clone stream is already destroyed don't call destory function again
if (!cloneStream.destroyed) {
cloneStream.destroy(err);
}
} else { } else {
passThrough.end(); cloneStream.end();
} }
} }
// Attach event listeners to the request stream // Attach event listeners to the request stream
req.on('data', onData); req.on('data', onData)
req.once('end', onEnd); .once('end', onEnd)
req.once('error', onEnd); .once('error', onEnd)
// Remove listeners once the request is closed
.once('close', () => {
req.removeListener('data', onData);
})
// Remove listeners once the request is closed // Attach the clone stream to the request
req.once('close', function () {
req.removeListener('data', onData);
});
// Attach the passThrough stream to the request
Object.defineProperty(req, "_nodeRedReqStream", { Object.defineProperty(req, "_nodeRedReqStream", {
value: passThrough value: cloneStream
}); });
// Proceed to the next middleware if no settings found
return next(); return next();
} }
// Proceed to the next middleware if no settings found // Proceed to the next middleware if no settings found
@ -351,7 +365,7 @@ module.exports = function(RED) {
} }
// unique id for httpInNode based on method name and url path // unique id for httpInNode based on method name and url path
var httpInNodeId = createRouteId({url: this.url, method: this.method}) var httpInNodeId = getRouteId({url: this.url, method: this.method})
// get httpInNode from RED.httpNode // get httpInNode from RED.httpNode
var httpInNodes = rootApp.get('httpInNodes') var httpInNodes = rootApp.get('httpInNodes')