From 2037741b54a56149f36e38c851e1a5d46d55dbcf Mon Sep 17 00:00:00 2001 From: Hiroki Uchikawa Date: Wed, 30 Jan 2019 19:24:19 +0900 Subject: [PATCH 1/3] Revert cookie encoding behavior --- .../@node-red/nodes/core/io/21-httprequest.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js b/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js index ea81987a9..6987c670b 100644 --- a/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js +++ b/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js @@ -148,16 +148,9 @@ module.exports = function(RED) { }; } if (opts.headers.hasOwnProperty('cookie')) { - var cookies = cookie.parse(opts.headers.cookie); + var cookies = cookie.parse(opts.headers.cookie, {decode:String}); for (var name in cookies) { - if (cookies.hasOwnProperty(name)) { - if (cookies[name] === null) { - // This case clears a cookie for HTTP In/Response nodes. - // Ignore for this node. - } else { - opts.jar.setCookie(name + '=' + cookies[name], url); - } - } + opts.jar.setCookie(cookie.serialize(name, cookies[name], {encode:String}), url); } delete opts.headers.cookie; } @@ -168,9 +161,9 @@ module.exports = function(RED) { // This case clears a cookie for HTTP In/Response nodes. // Ignore for this node. } else if (typeof msg.cookies[name] === 'object') { - opts.jar.setCookie(name + '=' + msg.cookies[name].value, url); + opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value), url); } else { - opts.jar.setCookie(name + '=' + msg.cookies[name], url); + opts.jar.setCookie(cookie.serialize(name, msg.cookies[name]), url); } } } From 7c6eb7c7940d2fc4ed737deb2a6eef05fd6e6e9b Mon Sep 17 00:00:00 2001 From: Hiroki Uchikawa Date: Wed, 30 Jan 2019 19:33:23 +0900 Subject: [PATCH 2/3] Allow http request node to change cookie value encoding --- .../@node-red/nodes/core/io/21-httprequest.js | 4 +- test/nodes/core/io/21-httprequest_spec.js | 131 +++++++++++++++++- 2 files changed, 128 insertions(+), 7 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js b/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js index 6987c670b..d1d9fe440 100644 --- a/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js +++ b/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js @@ -161,7 +161,9 @@ module.exports = function(RED) { // This case clears a cookie for HTTP In/Response nodes. // Ignore for this node. } else if (typeof msg.cookies[name] === 'object') { - opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value), url); + // If the encode option is specified, pass it. + var options = msg.cookies[name].encode ? {encode: msg.cookies[name].encode} : undefined; + opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value, options), url); } else { opts.jar.setCookie(cookie.serialize(name, msg.cookies[name]), url); } diff --git a/test/nodes/core/io/21-httprequest_spec.js b/test/nodes/core/io/21-httprequest_spec.js index 1f20b5ca1..5562127d1 100644 --- a/test/nodes/core/io/21-httprequest_spec.js +++ b/test/nodes/core/io/21-httprequest_spec.js @@ -120,7 +120,7 @@ describe('HTTP Request Node', function() { before(function(done) { testApp = express(); testApp.use(bodyParser.raw({type:"*/*"})); - testApp.use(cookieParser()); + testApp.use(cookieParser(undefined,{decode:String})); testApp.get('/statusCode204', function(req,res) { res.status(204).end();}); testApp.get('/text', function(req, res){ res.send('hello'); }); testApp.get('/redirectToText', function(req, res){ res.status(302).set('Location', getTestURL('/text')).end(); }); @@ -138,8 +138,7 @@ describe('HTTP Request Node', function() { }, 50); }); testApp.get('/checkCookie', function(req, res){ - var value = req.cookies.data; - res.send(value); + res.send(req.cookies); }); testApp.get('/setCookie', function(req, res){ res.cookie('data','hello'); @@ -1001,7 +1000,7 @@ describe('HTTP Request Node', function() { var n2 = helper.getNode("n2"); n2.on("input", function(msg) { try { - msg.should.have.property('payload','abc'); + msg.payload.should.have.property('data','abc'); msg.should.have.property('statusCode',200); done(); } catch(err) { @@ -1012,6 +1011,26 @@ describe('HTTP Request Node', function() { }); }); + it('should send multiple cookies with string', function(done) { + var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, + {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.should.have.property('data','abc'); + msg.payload.should.have.property('foo','bar'); + msg.should.have.property('statusCode',200); + done(); + } catch(err) { + done(err); + } + }); + n1.receive({payload:"foo", cookies:{data:'abc',foo:'bar'}}); + }); + }); + it('should send cookie with object data', function(done) { var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, {id:"n2", type:"helper"}]; @@ -1020,7 +1039,7 @@ describe('HTTP Request Node', function() { var n2 = helper.getNode("n2"); n2.on("input", function(msg) { try { - msg.should.have.property('payload','abc'); + msg.payload.should.have.property('data','abc'); msg.should.have.property('statusCode',200); done(); } catch(err) { @@ -1031,6 +1050,86 @@ describe('HTTP Request Node', function() { }); }); + it('should send multiple cookies with object data', function(done) { + var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, + {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.should.have.property('data','abc'); + msg.payload.should.have.property('foo','bar'); + msg.should.have.property('statusCode',200); + done(); + } catch(err) { + done(err); + } + }); + n1.receive({payload:"foo", cookies:{data:{value:'abc'},foo:{value:'bar'}}}); + }); + }); + + it('should encode cookie value', function(done) { + var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, + {id:"n2", type:"helper"}]; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + var value = ';,/?:@ &=+$#'; + n2.on("input", function(msg) { + try { + msg.payload.should.have.property('data',encodeURIComponent(value)); + msg.should.have.property('statusCode',200); + done(); + } catch(err) { + done(err); + } + }); + n1.receive({payload:"foo", cookies:{data:value}}); + }); + }); + + it('should encode cookie object', function(done) { + var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, + {id:"n2", type:"helper"}]; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + var value = ';,/?:@ &=+$#'; + n2.on("input", function(msg) { + try { + msg.payload.should.have.property('data',encodeURIComponent(value)); + msg.should.have.property('statusCode',200); + done(); + } catch(err) { + done(err); + } + }); + n1.receive({payload:"foo", cookies:{data:{value:value}}}); + }); + }); + + it('should encode cookie by specified function', function(done) { + var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, + {id:"n2", type:"helper"}]; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + var value = ',/?:@ &+$#'; + n2.on("input", function(msg) { + try { + msg.payload.should.have.property('data',encodeURI(value)); + msg.should.have.property('statusCode',200); + done(); + } catch(err) { + done(err); + } + }); + n1.receive({payload:"foo", cookies:{data:{value:value,encode:encodeURI}}}); + }); + }); + it('should send cookie by msg.headers', function(done) { var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, {id:"n2", type:"helper"}]; @@ -1039,7 +1138,7 @@ describe('HTTP Request Node', function() { var n2 = helper.getNode("n2"); n2.on("input", function(msg) { try { - msg.should.have.property('payload','abc'); + msg.payload.should.have.property('data','abc'); msg.should.have.property('statusCode',200); done(); } catch(err) { @@ -1050,6 +1149,26 @@ describe('HTTP Request Node', function() { }); }); + it('should send multiple cookies by msg.headers', function(done) { + var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, + {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.should.have.property('data','abc'); + msg.payload.should.have.property('foo','bar'); + msg.should.have.property('statusCode',200); + done(); + } catch(err) { + done(err); + } + }); + n1.receive({payload:"foo", cookies:{boo:'123'}, headers:{'cookie':'data=abc; foo=bar;'}}); + }); + }); + it('should convert all HTTP headers into lower case', function(done) { var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')}, {id:"n2", type:"helper"}]; From f3d2053878837ff95a66e5f5bde4dd4c6a0949ff Mon Sep 17 00:00:00 2001 From: Hiroki Uchikawa Date: Fri, 1 Feb 2019 17:15:07 +0900 Subject: [PATCH 3/3] Make the encode option a boolean value to determine whether to encode --- .../@node-red/nodes/core/io/21-httprequest.js | 10 +++++++--- test/nodes/core/io/21-httprequest_spec.js | 10 +++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js b/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js index d1d9fe440..633f3a7a9 100644 --- a/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js +++ b/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js @@ -161,9 +161,13 @@ module.exports = function(RED) { // This case clears a cookie for HTTP In/Response nodes. // Ignore for this node. } else if (typeof msg.cookies[name] === 'object') { - // If the encode option is specified, pass it. - var options = msg.cookies[name].encode ? {encode: msg.cookies[name].encode} : undefined; - opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value, options), url); + if(msg.cookies[name].encode === false){ + // If the encode option is false, the value is not encoded. + opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value, {encode: String}), url); + } else { + // The value is encoded by encodeURIComponent(). + opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value), url); + } } else { opts.jar.setCookie(cookie.serialize(name, msg.cookies[name]), url); } diff --git a/test/nodes/core/io/21-httprequest_spec.js b/test/nodes/core/io/21-httprequest_spec.js index 5562127d1..04b191e2d 100644 --- a/test/nodes/core/io/21-httprequest_spec.js +++ b/test/nodes/core/io/21-httprequest_spec.js @@ -1106,27 +1106,27 @@ describe('HTTP Request Node', function() { done(err); } }); - n1.receive({payload:"foo", cookies:{data:{value:value}}}); + n1.receive({payload:"foo", cookies:{data:{value:value, encode:true}}}); }); }); - it('should encode cookie by specified function', function(done) { + it('should not encode cookie when encode option is false', function(done) { var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')}, {id:"n2", type:"helper"}]; helper.load(httpRequestNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); - var value = ',/?:@ &+$#'; + var value = '!#$%&\'()*+-./:<>?@[]^_`{|}~'; n2.on("input", function(msg) { try { - msg.payload.should.have.property('data',encodeURI(value)); + msg.payload.should.have.property('data',value); msg.should.have.property('statusCode',200); done(); } catch(err) { done(err); } }); - n1.receive({payload:"foo", cookies:{data:{value:value,encode:encodeURI}}}); + n1.receive({payload:"foo", cookies:{data:{value:value, encode:false}}}); }); });