diff --git a/nodes/core/io/21-httprequest.js b/nodes/core/io/21-httprequest.js index 4ddb1d3b9..28d67d077 100644 --- a/nodes/core/io/21-httprequest.js +++ b/nodes/core/io/21-httprequest.js @@ -83,6 +83,7 @@ module.exports = function(RED) { opts.headers = {}; opts.encoding = null; // Force NodeJs to return a Buffer (instead of a string) opts.maxRedirects = 21; + opts.jar = request.jar(); var ctSet = "Content-Type"; // set default camel case var clSet = "Content-Length"; if (msg.headers) { @@ -112,28 +113,42 @@ module.exports = function(RED) { } if (msg.hasOwnProperty('followRedirects')) { opts.followRedirect = msg.followRedirects; + } + if (!opts.hasOwnProperty('followRedirect') || opts.followRedirect) { + opts.followRedirect = function(res) { + if (this.headers.cookie) { + delete this.headers.cookie; + } + return true; + }; + } + if (opts.headers.hasOwnProperty('cookie')) { + var cookies = cookie.parse(opts.headers.cookie); + 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); + } + } } + delete opts.headers.cookie; + } if (msg.cookies) { - var cookies = []; - if (opts.headers.hasOwnProperty('cookie')) { - cookies.push(opts.headers.cookie); - } - for (var name in msg.cookies) { if (msg.cookies.hasOwnProperty(name)) { if (msg.cookies[name] === null || msg.cookies[name].value === null) { // This case clears a cookie for HTTP In/Response nodes. // Ignore for this node. } else if (typeof msg.cookies[name] === 'object') { - cookies.push(cookie.serialize(name,msg.cookies[name].value)); + opts.jar.setCookie(name + '=' + msg.cookies[name].value, url); } else { - cookies.push(cookie.serialize(name,msg.cookies[name])); + opts.jar.setCookie(name + '=' + msg.cookies[name], url); } } } - if (cookies.length > 0) { - opts.headers.cookie = cookies.join("; "); - } } if (this.credentials && this.credentials.user) { opts.auth = { diff --git a/test/nodes/core/io/21-httprequest_spec.js b/test/nodes/core/io/21-httprequest_spec.js index 8ca5f0a14..2eab428cd 100644 --- a/test/nodes/core/io/21-httprequest_spec.js +++ b/test/nodes/core/io/21-httprequest_spec.js @@ -46,6 +46,9 @@ describe('HTTP Request Node', function() { var preEnvNoProxyLowerCase; var preEnvNoProxyUpperCase; + //rediect cookie variables + var receivedCookies = {}; + function startServer(done) { testPort += 1; testServer = stoppable(http.createServer(testApp)); @@ -98,6 +101,10 @@ describe('HTTP Request Node', function() { return "https://localhost:"+testSslPort+url; } + function getDifferentTestURL(url) { + return "http://127.0.0.1:"+testPort+url; + } + function getSslTestURLWithoutProtocol(url) { return "localhost:"+testSslPort+url; } @@ -182,6 +189,24 @@ describe('HTTP Request Node', function() { testApp.options('/*', function(req,res) { res.status(200).end(); }); + testApp.get('/redirectToSameDomain', function(req, res) { + var key = req.headers.host + req.url; + receivedCookies[key] = req.cookies; + res.cookie('redirectToSameDomainCookie','same1'); + res.redirect(getTestURL('/redirectReturn')); + }); + testApp.get('/redirectToDifferentDomain', function(req, res) { + var key = req.headers.host + req.url; + receivedCookies[key] = req.cookies; + res.cookie('redirectToDifferentDomain','different1'); + res.redirect(getDifferentTestURL('/redirectReturn')); + }); + testApp.get('/redirectReturn', function(req, res) { + var key = req.headers.host + req.url; + receivedCookies[key] = req.cookies; + res.cookie('redirectReturn','return1'); + res.status(200).end(); + }); startServer(function(err) { if (err) { done(err); @@ -1240,4 +1265,162 @@ describe('HTTP Request Node', function() { }); }); }); + + describe('redirect-cookie', function() { + it('should send cookies to the same domain when redirected(no cookies)', function(done) { + var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:getTestURL('/redirectToSameDomain')}, + {id:"n2", type:"helper"}]; + receivedCookies = {}; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + var cookies1 = receivedCookies['localhost:'+testPort+'/redirectToSameDomain']; + var cookies2 = receivedCookies['localhost:'+testPort+'/redirectReturn']; + if (cookies1 && Object.keys(cookies1).length != 0) { + done(new Error('Invalid cookie(path:/rediectToSame)')); + return; + } + if ((cookies2 && Object.keys(cookies2).length != 1) || + cookies2['redirectToSameDomainCookie'] !== 'same1') { + done(new Error('Invalid cookie(path:/rediectReurn)')); + return; + } + done(); + }); + n1.receive({}); + }); + }); + it('should not send cookies to the different domain when redirected(no cookies)', function(done) { + var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:getTestURL('/redirectToDifferentDomain')}, + {id:"n2", type:"helper"}]; + receivedCookies = {}; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + var cookies1 = receivedCookies['localhost:'+testPort+'/redirectToSameDomain']; + var cookies2 = receivedCookies['127.0.0.1:'+testPort+'/redirectReturn']; + if (cookies1 && Object.keys(cookies1).length != 0) { + done(new Error('Invalid cookie(path:/rediectToDiffer)')); + return; + } + if (cookies2 && Object.keys(cookies2).length != 0) { + done(new Error('Invalid cookie(path:/rediectReurn)')); + return; + } + done(); + }); + n1.receive({}); + }); + }); + it('should send cookies to the same domain when redirected(msg.cookies)', function(done) { + var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:getTestURL('/redirectToSameDomain')}, + {id:"n2", type:"helper"}]; + receivedCookies = {}; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + var cookies1 = receivedCookies['localhost:'+testPort+'/redirectToSameDomain']; + var cookies2 = receivedCookies['localhost:'+testPort+'/redirectReturn']; + if ((cookies1 && Object.keys(cookies1).length != 1) || + cookies1['requestCookie'] !== 'request1') { + done(new Error('Invalid cookie(path:/rediectToSame)')); + return; + } + if ((cookies2 && Object.keys(cookies2).length != 2) || + cookies1['requestCookie'] !== 'request1' || + cookies2['redirectToSameDomainCookie'] !== 'same1') { + done(new Error('Invalid cookie(path:/rediectReurn)')); + return; + } + done(); + }); + n1.receive({ + cookies: { requestCookie: 'request1' } + }); + }); + }); + it('should not send cookies to the different domain when redirected(msg.cookies)', function(done) { + var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:getTestURL('/redirectToDifferentDomain')}, + {id:"n2", type:"helper"}]; + receivedCookies = {}; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + var cookies1 = receivedCookies['localhost:'+testPort+'/redirectToDifferentDomain']; + var cookies2 = receivedCookies['127.0.0.1:'+testPort+'/redirectReturn']; + if ((cookies1 && Object.keys(cookies1).length != 1) || + cookies1['requestCookie'] !== 'request1') { + done(new Error('Invalid cookie(path:/rediectToDiffer)')); + return; + } + if (cookies2 && Object.keys(cookies2).length != 0) { + done(new Error('Invalid cookie(path:/rediectReurn)')); + return; + } + done(); + }); + n1.receive({ + cookies: { requestCookie: 'request1' } + }); + }); + }); + it('should send cookies to the same domain when redirected(msg.headers.cookie)', function(done) { + var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:getTestURL('/redirectToSameDomain')}, + {id:"n2", type:"helper"}]; + receivedCookies = {}; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + var cookies1 = receivedCookies['localhost:'+testPort+'/redirectToSameDomain']; + var cookies2 = receivedCookies['localhost:'+testPort+'/redirectReturn']; + if ((cookies1 && Object.keys(cookies1).length != 1) || + cookies1['requestCookie'] !== 'request1') { + done(new Error('Invalid cookie(path:/rediectToSame)')); + return; + } + if ((cookies2 && Object.keys(cookies2).length != 2) || + cookies1['requestCookie'] !== 'request1' || + cookies2['redirectToSameDomainCookie'] !== 'same1') { + done(new Error('Invalid cookie(path:/rediectReurn)')); + return; + } + done(); + }); + n1.receive({ + headers: { cookie: 'requestCookie=request1' } + }); + }); + }); + it('should not send cookies to the different domain when redirected(msg.headers.cookie)', function(done) { + var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:getTestURL('/redirectToDifferentDomain')}, + {id:"n2", type:"helper"}]; + receivedCookies = {}; + helper.load(httpRequestNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + var cookies1 = receivedCookies['localhost:'+testPort+'/redirectToDifferentDomain']; + var cookies2 = receivedCookies['127.0.0.1:'+testPort+'/redirectReturn']; + if ((cookies1 && Object.keys(cookies1).length != 1) || + cookies1['requestCookie'] !== 'request1') { + done(new Error('Invalid cookie(path:/rediectToDiffer)')); + return; + } + if (cookies2 && Object.keys(cookies2).length != 0) { + done(new Error('Invalid cookie(path:/rediectReurn)')); + return; + } + done(); + }); + n1.receive({ + headers: { cookie: 'requestCookie=request1' } + }); + }); + }); + }); });