refactor: update rawBody label to skipBodyParsing and adjust related UI elements

This commit is contained in:
Debadutta Panda
2025-03-18 18:42:27 +05:30
parent 8543c88f2b
commit 16d095397c
12 changed files with 40 additions and 74 deletions

View File

@@ -33,9 +33,9 @@
<input type="checkbox" id="node-input-upload" style="margin-right: 5%; margin-bottom: 5%;">
<label for="node-input-upload" style="text-wrap: nowrap;" data-i18n="httpin.label.upload"></label>
</div>
<div id="form-row-http-in-rawdata" class="hide" style="display: flex;">
<input type="checkbox" id="node-input-includeRawBody" style="margin-right: 5%; margin-bottom: 5%;">
<label for="node-input-includeRawBody" style="text-wrap: nowrap;" data-i18n="httpin.label.rawBody"></label>
<div id="form-row-http-in-parsing" class="hide" style="display: flex;">
<input type="checkbox" id="node-input-skipBodyParsing" style="margin-right: 5%; margin-bottom: 5%;">
<label for="node-input-skipBodyParsing" style="text-wrap: nowrap;" data-i18n="httpin.label.parsing"></label>
</div>
</div>
</div>
@@ -85,7 +85,7 @@
label:RED._("node-red:httpin.label.url")},
method: {value:"get",required:true},
upload: {value:false},
includeRawBody: {value:false},
skipBodyParsing: {value:false},
swaggerDoc: {type:"swagger-doc", required:false}
},
inputs:0,
@@ -130,14 +130,14 @@
var method = $(this).val();
if(["post", "put", "patch","delete"].includes(method)){
$("#form-reqBody-http-in-controller").show();
$("#form-row-http-in-rawdata").show();
$("#form-row-http-in-parsing").show();
if (method === "post") {
$("#form-row-http-in-upload").show();
} else {
$("#form-row-http-in-upload").hide();
}
} else {
$("#form-row-http-in-rawdata").hide();
$("#form-row-http-in-parsing").hide();
$("#form-row-http-in-upload").hide();
$("#form-reqBody-http-in-controller").hide();
}

View File

@@ -37,11 +37,15 @@ module.exports = function(RED) {
* @param {import('express').NextFunction} next
* @returns
*/
function rawBodyParser(req, _res, next) {
if (!req._nodeRedReqStream) {
return next();
}
var isText = true, checkUTF = false;
function rawBodyParser(req, res, next) {
if (req.skipRawBodyParser) { next(); } // don't parse this if told to skip
if (req._body) { return next(); }
req.body = "";
req._body = true;
var isText = true;
var checkUTF = false;
if (req.headers['content-type']) {
var contentType = typer.parse(req.headers['content-type'])
if (contentType.type) {
@@ -57,26 +61,23 @@ module.exports = function(RED) {
&& (parsedType.subtype !== "x-protobuf")) {
checkUTF = true;
} else {
// application/octet-stream or application/cbor
isText = false;
}
}
}
getBody(req._nodeRedReqStream, {
getBody(req, {
length: req.headers['content-length'],
encoding: isText ? "utf8" : null
}, function (err, buf) {
if (err) {
return next(err);
}
if (err) { return next(err); }
if (!isText && checkUTF && isUtf8(buf)) {
buf = buf.toString()
}
Object.defineProperty(req, "rawRequestBody", {
value: buf,
enumerable: true
});
return next();
req.body = buf;
next();
});
}
@@ -115,49 +116,23 @@ module.exports = function(RED) {
var routeKey = getRouteKey({ method: req.method, url: req._parsedUrl.pathname });
// Check if routeKey exist in rawDataRoutes
if (rawDataRoutes.has(routeKey)) {
// Create a PassThrough stream to capture the request body
var cloneStream = new PassThrough();
// Function to handle 'data' event
function onData(chunk) {
// Safely call clone stream write
if (cloneStream.writable) {
cloneStream.write(chunk);
}
}
// Function to handle 'end' or 'error' events
function onEnd(err) {
// Convert the request stream to buffer
getBody(req, {
length: req.headers['content-length'],
encoding: typer.parse(req).parameters.charset
}, function (err, buf) {
if (err) {
// Safely call clone stream destroy method
if (!cloneStream.destroyed) {
cloneStream.destroy(err);
}
} else {
// Safely call clone stream end method
if (cloneStream.writable) {
cloneStream.end();
}
return next(err);
}
}
// Attach event listeners to the request stream
req.on('data', onData)
.once('end', onEnd)
.once('error', onEnd)
// Remove listeners once the request is closed
.once('close', () => {
req.removeListener('data', onData);
});
// Attach the clone stream to the request
Object.defineProperty(req, "_nodeRedReqStream", {
value: cloneStream
});
req.body = buf;
// Skip the body parsing
req.skipRawBodyParser = true;
req._body = true;
next();
})
} else {
next();
}
// Proceed to the next middleware
return next();
}
if(typeof RED.httpNode === 'function' && (rootApp = getRootApp(RED.httpNode))) {
@@ -283,14 +258,14 @@ module.exports = function(RED) {
}
this.method = n.method;
this.upload = n.upload;
this.includeRawBody = n.includeRawBody;
this.skipBodyParsing = n.skipBodyParsing;
this.swaggerDoc = n.swaggerDoc;
var node = this;
var routeKey = getRouteKey({method: this.method, url: RED.httpNode.path() + this.url});
// If the user enables raw body, add it to the raw data routes.
if(this.includeRawBody) {
if(this.skipBodyParsing) {
rawDataRoutes.add(routeKey);
}