diff --git a/nodes/core/io/21-httpin.js b/nodes/core/io/21-httpin.js
index 76c10a7bf..d71a7fa29 100644
--- a/nodes/core/io/21-httpin.js
+++ b/nodes/core/io/21-httpin.js
@@ -26,6 +26,7 @@ module.exports = function(RED) {
var onHeaders = require('on-headers');
var typer = require('media-typer');
var isUtf8 = require('is-utf8');
+ var hashSum = require("hash-sum");
function rawBodyParser(req, res, next) {
if (req.skipRawBodyParser) { next(); } // don't parse this if told to skip
@@ -277,9 +278,19 @@ module.exports = function(RED) {
if (msg.res) {
var headers = RED.util.cloneMessage(node.headers);
if (msg.headers) {
- for (var h in msg.headers) {
- if (msg.headers.hasOwnProperty(h) && !headers.hasOwnProperty(h)) {
- headers[h] = msg.headers[h];
+ if (msg.headers.hasOwnProperty('x-node-red-request-node')) {
+ var headerHash = msg.headers['x-node-red-request-node'];
+ delete msg.headers['x-node-red-request-node'];
+ var hash = hashSum(msg.headers);
+ if (hash === headerHash) {
+ delete msg.headers;
+ }
+ }
+ if (msg.headers) {
+ for (var h in msg.headers) {
+ if (msg.headers.hasOwnProperty(h) && !headers.hasOwnProperty(h)) {
+ headers[h] = msg.headers[h];
+ }
}
}
}
diff --git a/nodes/core/io/21-httprequest.html b/nodes/core/io/21-httprequest.html
index 7beffe261..b910b6bd6 100644
--- a/nodes/core/io/21-httprequest.html
+++ b/nodes/core/io/21-httprequest.html
@@ -108,6 +108,12 @@
example.com/{{{topic}}}
, it will have the value of msg.topic
automatically inserted.
Using {{{...}}} prevents mustache from escaping characters like / & etc.
Note: If running behind a proxy, the standard http_proxy=...
environment variable should be set and Node-RED restarted.
In order to use more than one of these nodes in the same flow, care must be taken with
+ the msg.headers
property. The first node will set this property with
+ the response headers. The next node will then use those headers for its request - this
+ is not usually the right thing to do. The msg.headers
property must
+ be deleted with a change node in order for the requests to work as expected.
The cookies
property passed to the node must be an object of name/value pairs.
The value can be either a string to set the value of the cookie or it can be an
diff --git a/nodes/core/io/21-httprequest.js b/nodes/core/io/21-httprequest.js
index f38b8eecc..bc8c16a06 100644
--- a/nodes/core/io/21-httprequest.js
+++ b/nodes/core/io/21-httprequest.js
@@ -22,6 +22,7 @@ module.exports = function(RED) {
var mustache = require("mustache");
var querystring = require("querystring");
var cookie = require("cookie");
+ var hashSum = require("hash-sum");
function HTTPRequest(n) {
RED.nodes.createNode(this,n);
@@ -83,17 +84,27 @@ module.exports = function(RED) {
var ctSet = "Content-Type"; // set default camel case
var clSet = "Content-Length";
if (msg.headers) {
- for (var v in msg.headers) {
- if (msg.headers.hasOwnProperty(v)) {
- var name = v.toLowerCase();
- if (name !== "content-type" && name !== "content-length") {
- // only normalise the known headers used later in this
- // function. Otherwise leave them alone.
- name = v;
+ if (msg.headers.hasOwnProperty('x-node-red-request-node')) {
+ var headerHash = msg.headers['x-node-red-request-node'];
+ delete msg.headers['x-node-red-request-node'];
+ var hash = hashSum(msg.headers);
+ if (hash === headerHash) {
+ delete msg.headers;
+ }
+ }
+ if (msg.headers) {
+ for (var v in msg.headers) {
+ if (msg.headers.hasOwnProperty(v)) {
+ var name = v.toLowerCase();
+ if (name !== "content-type" && name !== "content-length") {
+ // only normalise the known headers used later in this
+ // function. Otherwise leave them alone.
+ name = v;
+ }
+ else if (name === 'content-type') { ctSet = v; }
+ else { clSet = v; }
+ opts.headers[name] = msg.headers[v];
}
- else if (name === 'content-type') { ctSet = v; }
- else { clSet = v; }
- opts.headers[name] = msg.headers[v];
}
}
}
@@ -207,7 +218,7 @@ module.exports = function(RED) {
})
}
-
+ msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
// msg.url = url; // revert when warning above finally removed
res.on('data',function(chunk) {
if (!Buffer.isBuffer(chunk)) {
diff --git a/package.json b/package.json
index 19277f5c8..f5d21cdc1 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"follow-redirects":"1.2.4",
"fs-extra": "1.0.0",
"fs.notify":"0.0.4",
+ "hash-sum":"1.0.2",
"i18next":"1.10.6",
"is-utf8":"0.2.1",
"js-yaml": "3.8.4",
@@ -48,7 +49,7 @@
"mqtt": "2.9.0",
"multer": "1.3.0",
"mustache": "2.3.0",
- "nopt": "4.0.1",
+ "nopt": "3.0.6",
"oauth2orize":"1.8.0",
"on-headers":"1.0.1",
"passport":"0.3.2",
diff --git a/test/nodes/core/io/21-httprequest_spec.js b/test/nodes/core/io/21-httprequest_spec.js
index 942ff1890..1d2dc5d71 100644
--- a/test/nodes/core/io/21-httprequest_spec.js
+++ b/test/nodes/core/io/21-httprequest_spec.js
@@ -21,6 +21,7 @@ var express = require("express");
var bodyParser = require('body-parser');
var helper = require("../../helper.js");
var httpRequestNode = require("../../../../nodes/core/io/21-httprequest.js");
+var hashSum = require("hash-sum");
describe('HTTP Request Node', function() {
var testApp;
@@ -399,4 +400,46 @@ describe('HTTP Request Node', function() {
});
})
+ it('ignores unmodified msg.headers property', function(done) {
+ var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
+ {id:"n2", type:"helper"}];
+ helper.load(httpRequestNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ try {
+ msg.payload.headers.should.have.property('content-type').which.startWith('application/json');
+ msg.payload.headers.should.not.have.property('x-node-red-request-node');
+ done();
+ } catch(err) {
+ done(err);
+ }
+ });
+ // Pass in a headers property with an unmodified x-node-red-request-node hash
+ // This should cause the node to ignore the headers
+ n1.receive({payload:{foo:"bar"}, headers: { 'content-type': 'text/plain', "x-node-red-request-node":"67690139"}});
+ });
+ })
+
+ it('uses modified msg.headers property', function(done) {
+ var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
+ {id:"n2", type:"helper"}];
+ helper.load(httpRequestNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ try {
+ msg.payload.headers.should.have.property('content-type').which.startWith('text/plain');
+ msg.payload.headers.should.not.have.property('x-node-red-request-node');
+ done();
+ } catch(err) {
+ done(err);
+ }
+ });
+ // Pass in a headers property with a x-node-red-request-node hash that doesn't match the contents
+ // This should cause the node to use the headers
+ n1.receive({payload:{foo:"bar"}, headers: { 'content-type': 'text/plain', "x-node-red-request-node":"INVALID_SUM"}});
+ });
+ })
+
});