1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Merge branch 'pr_2952' into dev

This commit is contained in:
Nick O'Leary 2021-06-08 11:09:56 +01:00
commit 7bf938901a
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
4 changed files with 295 additions and 147 deletions

View File

@ -43,9 +43,12 @@
"denque": "1.5.0", "denque": "1.5.0",
"express": "4.17.1", "express": "4.17.1",
"express-session": "1.17.2", "express-session": "1.17.2",
"form-data": "4.0.0",
"fs-extra": "10.0.0", "fs-extra": "10.0.0",
"fs.notify": "0.0.4", "fs.notify": "0.0.4",
"got": "11.8.2",
"hash-sum": "2.0.0", "hash-sum": "2.0.0",
"hpagent": "0.1.1",
"https-proxy-agent": "5.0.0", "https-proxy-agent": "5.0.0",
"i18next": "20.3.1", "i18next": "20.3.1",
"iconv-lite": "0.6.3", "iconv-lite": "0.6.3",
@ -72,8 +75,14 @@
"request": "2.88.0", "request": "2.88.0",
"semver": "7.3.5", "semver": "7.3.5",
"tar": "6.1.0", "tar": "6.1.0",
"tough-cookie": "4.0.0",
"uglify-js": "3.13.8", "uglify-js": "3.13.8",
"uuid": "8.3.2",
"ws": "7.4.6", "ws": "7.4.6",
"tough-cookie": "4.0.0",
"uglify-js": "3.13.3",
"uuid": "8.3.2",
"ws": "6.2.1",
"xml2js": "0.4.23" "xml2js": "0.4.23"
}, },
"optionalDependencies": { "optionalDependencies": {

View File

@ -16,7 +16,13 @@
module.exports = function(RED) { module.exports = function(RED) {
"use strict"; "use strict";
var request = require("request"); const got = require("got");
const {CookieJar} = require("tough-cookie");
const { HttpProxyAgent, HttpsProxyAgent } = require('hpagent');
const FormData = require('form-data');
const { v4: uuid } = require('uuid');
const crypto = require('crypto');
const URL = require("url").URL
var mustache = require("mustache"); var mustache = require("mustache");
var querystring = require("querystring"); var querystring = require("querystring");
var cookie = require("cookie"); var cookie = require("cookie");
@ -30,6 +36,8 @@ module.exports = function(RED) {
var nodeMethod = n.method || "GET"; var nodeMethod = n.method || "GET";
var paytoqs = false; var paytoqs = false;
var paytobody = false; var paytobody = false;
var redirectList = [];
var nodeHTTPPersistent = n["persist"]; var nodeHTTPPersistent = n["persist"];
if (n.tls) { if (n.tls) {
var tlsNode = RED.nodes.getNode(n.tls); var tlsNode = RED.nodes.getNode(n.tls);
@ -57,12 +65,15 @@ module.exports = function(RED) {
} }
this.on("input",function(msg,nodeSend,nodeDone) { this.on("input",function(msg,nodeSend,nodeDone) {
//reset redirectList on each request
redirectList = [];
var preRequestTimestamp = process.hrtime(); var preRequestTimestamp = process.hrtime();
node.status({fill:"blue",shape:"dot",text:"httpin.status.requesting"}); node.status({fill:"blue",shape:"dot",text:"httpin.status.requesting"});
var url = nodeUrl || msg.url; var url = nodeUrl || msg.url;
if (msg.url && nodeUrl && (nodeUrl !== msg.url)) { // revert change below when warning is finally removed if (msg.url && nodeUrl && (nodeUrl !== msg.url)) { // revert change below when warning is finally removed
node.warn(RED._("common.errors.nooverride")); node.warn(RED._("common.errors.nooverride"));
} }
if (isTemplatedUrl) { if (isTemplatedUrl) {
url = mustache.render(nodeUrl,msg); url = mustache.render(nodeUrl,msg);
} }
@ -71,6 +82,8 @@ module.exports = function(RED) {
nodeDone(); nodeDone();
return; return;
} }
// url must start http:// or https:// so assume http:// if not set // url must start http:// or https:// so assume http:// if not set
if (url.indexOf("://") !== -1 && url.indexOf("http") !== 0) { if (url.indexOf("://") !== -1 && url.indexOf("http") !== 0) {
node.warn(RED._("httpin.errors.invalid-transport")); node.warn(RED._("httpin.errors.invalid-transport"));
@ -86,6 +99,7 @@ module.exports = function(RED) {
} }
} }
var method = nodeMethod.toUpperCase() || "GET"; var method = nodeMethod.toUpperCase() || "GET";
if (msg.method && n.method && (n.method !== "use")) { // warn if override option not set if (msg.method && n.method && (n.method !== "use")) { // warn if override option not set
node.warn(RED._("common.errors.nooverride")); node.warn(RED._("common.errors.nooverride"));
@ -94,19 +108,19 @@ module.exports = function(RED) {
method = msg.method.toUpperCase(); // use the msg parameter method = msg.method.toUpperCase(); // use the msg parameter
} }
var isHttps = (/^https/i.test(url)); // var isHttps = (/^https/i.test(url));
var opts = {}; var opts = {};
opts.url = url;
// set defaultport, else when using HttpsProxyAgent, it's defaultPort of 443 will be used :(. // set defaultport, else when using HttpsProxyAgent, it's defaultPort of 443 will be used :(.
opts.defaultPort = isHttps?443:80; // Had to remove this to get http->https redirect to work
// opts.defaultPort = isHttps?443:80;
opts.timeout = node.reqTimeout; opts.timeout = node.reqTimeout;
opts.method = method; opts.method = method;
opts.headers = {}; opts.headers = {};
opts.encoding = null; // Force NodeJs to return a Buffer (instead of a string) opts.retry = 0;
opts.responseType = 'buffer';
opts.maxRedirects = 21; opts.maxRedirects = 21;
opts.jar = request.jar(); opts.cookieJar = new CookieJar();
opts.proxy = null;
opts.forever = nodeHTTPPersistent; opts.forever = nodeHTTPPersistent;
if (msg.requestTimeout !== undefined) { if (msg.requestTimeout !== undefined) {
if (isNaN(msg.requestTimeout)) { if (isNaN(msg.requestTimeout)) {
@ -117,6 +131,21 @@ module.exports = function(RED) {
opts.timeout = msg.requestTimeout; opts.timeout = msg.requestTimeout;
} }
} }
opts.hooks = {
beforeRedirect: [
(options, response) => {
let redirectInfo = {
location: response.headers.location
}
if (response.headers.hasOwnProperty('set-cookie')) {
redirectInfo.cookies = extractCookies(response.headers['set-cookie']);
}
redirectList.push(redirectInfo)
}
]
}
var ctSet = "Content-Type"; // set default camel case var ctSet = "Content-Type"; // set default camel case
var clSet = "Content-Length"; var clSet = "Content-Length";
if (msg.headers) { if (msg.headers) {
@ -144,30 +173,15 @@ module.exports = function(RED) {
} }
} }
} }
if (msg.hasOwnProperty('followRedirects')) { if (msg.hasOwnProperty('followRedirects')) {
opts.followRedirect = msg.followRedirects; opts.followRedirect = !!msg.followRedirects;
opts.followAllRedirects = !!opts.followRedirect;
}
var redirectList = [];
if (!opts.hasOwnProperty('followRedirect') || opts.followRedirect) {
opts.followRedirect = function(res) {
var redirectInfo = {
location: res.headers.location,
};
if (res.headers.hasOwnProperty('set-cookie')) {
redirectInfo.cookies = extractCookies(res.headers['set-cookie']);
}
redirectList.push(redirectInfo);
if (this.headers.cookie) {
delete this.headers.cookie;
}
return true;
};
} }
if (opts.headers.hasOwnProperty('cookie')) { if (opts.headers.hasOwnProperty('cookie')) {
var cookies = cookie.parse(opts.headers.cookie, {decode:String}); var cookies = cookie.parse(opts.headers.cookie, {decode:String});
for (var name in cookies) { for (var name in cookies) {
opts.jar.setCookie(cookie.serialize(name, cookies[name], {encode:String}), url); opts.cookieJar.setCookie(cookie.serialize(name, cookies[name], {encode:String}), url);
} }
delete opts.headers.cookie; delete opts.headers.cookie;
} }
@ -180,13 +194,13 @@ module.exports = function(RED) {
} else if (typeof msg.cookies[name] === 'object') { } else if (typeof msg.cookies[name] === 'object') {
if(msg.cookies[name].encode === false){ if(msg.cookies[name].encode === false){
// If the encode option is false, the value is not encoded. // If the encode option is false, the value is not encoded.
opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value, {encode: String}), url); opts.cookieJar.setCookie(cookie.serialize(name, msg.cookies[name].value, {encode: String}), url);
} else { } else {
// The value is encoded by encodeURIComponent(). // The value is encoded by encodeURIComponent().
opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value), url); opts.cookieJar.setCookie(cookie.serialize(name, msg.cookies[name].value), url);
} }
} else { } else {
opts.jar.setCookie(cookie.serialize(name, msg.cookies[name]), url); opts.cookieJar.setCookie(cookie.serialize(name, msg.cookies[name]), url);
} }
} }
} }
@ -194,52 +208,62 @@ module.exports = function(RED) {
if (this.credentials) { if (this.credentials) {
if (this.authType === "basic") { if (this.authType === "basic") {
if (this.credentials.user) { if (this.credentials.user) {
opts.auth = { opts.username = this.credentials.user;
user: this.credentials.user, }
pass: this.credentials.password || "" if (this.credentials.password) {
}; opts.password = this.credentials.password;
} }
} else if (this.authType === "digest") { } else if (this.authType === "digest") {
if (this.credentials.user) { let digestCreds = this.credentials;
// The first request will be sent without auth information. Based on the 401 response, the library can determine let sentCreds = false;
// which auth type is required by the server. Then the request is resubmitted with the appropriate auth header. opts.hooks.afterResponse = [(response, retry) => {
opts.auth = { if (response.statusCode === 401) {
user: this.credentials.user, if (sentCreds) {
pass: this.credentials.password || "", return response
sendImmediately: false }
}; const requestUrl = new URL(response.request.requestUrl);
} const options = response.request.options;
const normalisedHeaders = {};
Object.keys(response.headers).forEach(k => {
normalisedHeaders[k.toLowerCase()] = response.headers[k]
})
if (normalisedHeaders['www-authenticate']) {
let authHeader = buildDigestHeader(digestCreds.user,digestCreds.password, options.method, requestUrl.pathname, normalisedHeaders['www-authenticate'])
options.headers.authorization = authHeader;
}
sentCreds = true;
return retry(options);
}
return response
}];
} else if (this.authType === "bearer") { } else if (this.authType === "bearer") {
opts.auth = { opts.headers.Authorization = `Bearer ${this.credentials.password||""}`
bearer: this.credentials.password || ""
};
} }
} }
var payload = null; var payload = null;
if (method !== 'GET' && method !== 'HEAD' && typeof msg.payload !== "undefined") { if (method !== 'GET' && method !== 'HEAD' && typeof msg.payload !== "undefined") {
if (opts.headers['content-type'] == 'multipart/form-data' && typeof msg.payload === "object") { if (opts.headers['content-type'] == 'multipart/form-data' && typeof msg.payload === "object") {
opts.formData = {}; let formData = new FormData();
for (var opt in msg.payload) { for (var opt in msg.payload) {
if (msg.payload.hasOwnProperty(opt)) { if (msg.payload.hasOwnProperty(opt)) {
var val = msg.payload[opt]; var val = msg.payload[opt];
if (val !== undefined && val !== null) { if (val !== undefined && val !== null) {
if (typeof val === 'string' || Buffer.isBuffer(val)) { if (typeof val === 'string' || Buffer.isBuffer(val)) {
opts.formData[opt] = val; formData.append(opt, val);
} else if (typeof val === 'object' && val.hasOwnProperty('value')) { } else if (typeof val === 'object' && val.hasOwnProperty('value')) {
// Treat as file to upload - ensure it has an options object formData.append(opt,val.value,val.options || {});
// as request complains if it doesn't
if (!val.hasOwnProperty('options')) {
val.options = {};
}
opts.formData[opt] = val;
} else { } else {
opts.formData[opt] = JSON.stringify(val); formData.append(opt,JSON.stringify(val));
} }
} }
} }
} }
// GOT will only set the content-type header with the correct boundary
// if the header isn't set. So we delete it here, for GOT to reset it.
delete opts.headers['content-type'];
opts.body = formData;
} else { } else {
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) { if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
payload = msg.payload; payload = msg.payload;
@ -266,25 +290,29 @@ module.exports = function(RED) {
} }
} }
if (method == 'GET' && typeof msg.payload !== "undefined" && paytoqs) { if (method == 'GET' && typeof msg.payload !== "undefined" && paytoqs) {
if (typeof msg.payload === "object") { if (typeof msg.payload === "object") {
try { try {
if (opts.url.indexOf("?") !== -1) { if (url.indexOf("?") !== -1) {
opts.url += (opts.url.endsWith("?")?"":"&") + querystring.stringify(msg.payload); url += (url.endsWith("?")?"":"&") + querystring.stringify(msg.payload);
} else { } else {
opts.url += "?" + querystring.stringify(msg.payload); url += "?" + querystring.stringify(msg.payload);
} }
} catch(err) { } catch(err) {
node.error(RED._("httpin.errors.invalid-payload"),msg); node.error(RED._("httpin.errors.invalid-payload"),msg);
nodeDone(); nodeDone();
return; return;
} }
} else { } else {
node.error(RED._("httpin.errors.invalid-payload"),msg); node.error(RED._("httpin.errors.invalid-payload"),msg);
nodeDone(); nodeDone();
return; return;
} }
} else if ( method == "GET" && typeof msg.payload !== "undefined" && paytobody) { } else if ( method == "GET" && typeof msg.payload !== "undefined" && paytobody) {
opts.allowGetBody = true;
if (typeof msg.payload === "object") { if (typeof msg.payload === "object") {
opts.body = JSON.stringify(msg.payload); opts.body = JSON.stringify(msg.payload);
} else if (typeof msg.payload == "number") { } else if (typeof msg.payload == "number") {
@ -311,79 +339,97 @@ module.exports = function(RED) {
} }
} }
if (prox && !noproxy) { if (prox && !noproxy) {
var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i); var match = prox.match(/^(https?:\/\/)?(.+)?:([0-9]+)?/i);
if (match) { if (match) {
opts.proxy = prox; let proxyAgent;
let proxyURL = new URL(prox);
//set username/password to null to stop empty creds header
let proxyOptions = {
proxy: {
protocol: proxyURL.protocol,
hostname: proxyURL.hostname,
port: proxyURL.port,
username: null,
password: null
},
maxFreeSockets: 256,
maxSockets: 256,
keepAlive: true
}
if (proxyConfig && proxyConfig.credentials) {
let proxyUsername = proxyConfig.credentials.username || '';
let proxyPassword = proxyConfig.credentials.password || '';
if (proxyUsername || proxyPassword) {
proxyOptions.proxy.username = proxyUsername;
proxyOptions.proxy.password = proxyPassword;
}
}
//need both incase of http -> https redirect
opts.agent = {
http: new HttpProxyAgent(proxyOptions),
https: new HttpsProxyAgent(proxyOptions)
};
} else { } else {
node.warn("Bad proxy url: "+ prox); node.warn("Bad proxy url: "+ prox);
opts.proxy = null;
}
}
if (proxyConfig && proxyConfig.credentials && opts.proxy == proxyConfig.url) {
var proxyUsername = proxyConfig.credentials.username || '';
var proxyPassword = proxyConfig.credentials.password || '';
if (proxyUsername || proxyPassword) {
opts.headers['proxy-authorization'] =
'Basic ' +
Buffer.from(proxyUsername + ':' + proxyPassword).toString('base64');
} }
} }
if (tlsNode) { if (tlsNode) {
tlsNode.addTLSOptions(opts); opts.https = {};
tlsNode.addTLSOptions(opts.https);
} else { } else {
if (msg.hasOwnProperty('rejectUnauthorized')) { if (msg.hasOwnProperty('rejectUnauthorized')) {
opts.rejectUnauthorized = msg.rejectUnauthorized; opts.https = { rejectUnauthorized: msg.rejectUnauthorized };
} }
} }
request(opts, function(err, res, body) { got(url,opts).then(res => {
if(err){ msg.statusCode = res.statusCode;
if(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT') { msg.headers = res.headers;
node.error(RED._("common.notification.errors.no-response"), msg); msg.responseUrl = res.url;
node.status({fill:"red", shape:"ring", text:"common.notification.errors.no-response"}); msg.payload = res.body;
}else{ msg.redirectList = redirectList;
node.error(err,msg); msg.retry = 0;
node.status({fill:"red", shape:"ring", text:err.code});
}
msg.payload = err.toString() + " : " + url;
msg.statusCode = err.code;
nodeSend(msg);
nodeDone();
}else{
msg.statusCode = res.statusCode;
msg.headers = res.headers;
msg.responseUrl = res.request.uri.href;
msg.payload = body;
msg.redirectList = redirectList;
if (msg.headers.hasOwnProperty('set-cookie')) { if (msg.headers.hasOwnProperty('set-cookie')) {
msg.responseCookies = extractCookies(msg.headers['set-cookie']); msg.responseCookies = extractCookies(msg.headers['set-cookie']);
}
msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
// msg.url = url; // revert when warning above finally removed
if (node.metric()) {
// Calculate request time
var diff = process.hrtime(preRequestTimestamp);
var ms = diff[0] * 1e3 + diff[1] * 1e-6;
var metricRequestDurationMillis = ms.toFixed(3);
node.metric("duration.millis", msg, metricRequestDurationMillis);
if (res.client && res.client.bytesRead) {
node.metric("size.bytes", msg, res.client.bytesRead);
}
}
// Convert the payload to the required return type
if (node.ret !== "bin") {
msg.payload = msg.payload.toString('utf8'); // txt
if (node.ret === "obj") {
try { msg.payload = JSON.parse(msg.payload); } // obj
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
}
}
node.status({});
nodeSend(msg);
nodeDone();
} }
msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
// msg.url = url; // revert when warning above finally removed
if (node.metric()) {
// Calculate request time
var diff = process.hrtime(preRequestTimestamp);
var ms = diff[0] * 1e3 + diff[1] * 1e-6;
var metricRequestDurationMillis = ms.toFixed(3);
node.metric("duration.millis", msg, metricRequestDurationMillis);
if (res.client && res.client.bytesRead) {
node.metric("size.bytes", msg, res.client.bytesRead);
}
}
// Convert the payload to the required return type
if (node.ret !== "bin") {
msg.payload = msg.payload.toString('utf8'); // txt
if (node.ret === "obj") {
try { msg.payload = JSON.parse(msg.payload); } // obj
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
}
}
node.status({});
nodeSend(msg);
nodeDone();
}).catch(err => {
if(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT') {
node.error(RED._("common.notification.errors.no-response"), msg);
node.status({fill:"red", shape:"ring", text:"common.notification.errors.no-response"});
}else{
node.error(err,msg);
node.status({fill:"red", shape:"ring", text:err.code});
}
msg.payload = err.toString() + " : " + url;
msg.statusCode = err.code || (err.response?err.response.statusCode:undefined);
nodeSend(msg);
nodeDone();
}); });
}); });
@ -411,4 +457,69 @@ module.exports = function(RED) {
password: {type: "password"} password: {type: "password"}
} }
}); });
const md5 = (value) => { return crypto.createHash('md5').update(value).digest('hex') }
function ha1Compute(algorithm, user, realm, pass, nonce, cnonce) {
/**
* RFC 2617: handle both MD5 and MD5-sess algorithms.
*
* If the algorithm directive's value is "MD5" or unspecified, then HA1 is
* HA1=MD5(username:realm:password)
* If the algorithm directive's value is "MD5-sess", then HA1 is
* HA1=MD5(MD5(username:realm:password):nonce:cnonce)
*/
var ha1 = md5(user + ':' + realm + ':' + pass)
if (algorithm && algorithm.toLowerCase() === 'md5-sess') {
return md5(ha1 + ':' + nonce + ':' + cnonce)
} else {
return ha1
}
}
function buildDigestHeader(user, pass, method, path, authHeader) {
var challenge = {}
var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi
for (;;) {
var match = re.exec(authHeader)
if (!match) {
break
}
challenge[match[1]] = match[2] || match[3]
}
var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'
var nc = qop && '00000001'
var cnonce = qop && uuid().replace(/-/g, '')
var ha1 = ha1Compute(challenge.algorithm, user, challenge.realm, pass, challenge.nonce, cnonce)
var ha2 = md5(method + ':' + path)
var digestResponse = qop
? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2)
: md5(ha1 + ':' + challenge.nonce + ':' + ha2)
var authValues = {
username: user,
realm: challenge.realm,
nonce: challenge.nonce,
uri: path,
qop: qop,
response: digestResponse,
nc: nc,
cnonce: cnonce,
algorithm: challenge.algorithm,
opaque: challenge.opaque
}
authHeader = []
for (var k in authValues) {
if (authValues[k]) {
if (k === 'qop' || k === 'nc' || k === 'algorithm') {
authHeader.push(k + '=' + authValues[k])
} else {
authHeader.push(k + '="' + authValues[k] + '"')
}
}
}
authHeader = 'Digest ' + authHeader.join(', ')
return authHeader
}
} }

View File

@ -26,9 +26,12 @@
"cors": "2.8.5", "cors": "2.8.5",
"cronosjs": "1.7.1", "cronosjs": "1.7.1",
"denque": "1.5.0", "denque": "1.5.0",
"form-data": "4.0.0",
"fs-extra": "10.0.0", "fs-extra": "10.0.0",
"fs.notify": "0.0.4", "fs.notify": "0.0.4",
"got": "11.8.2",
"hash-sum": "2.0.0", "hash-sum": "2.0.0",
"hpagent": "0.1.1",
"https-proxy-agent": "5.0.0", "https-proxy-agent": "5.0.0",
"is-utf8": "0.2.1", "is-utf8": "0.2.1",
"js-yaml": "3.14.0", "js-yaml": "3.14.0",
@ -39,6 +42,8 @@
"on-headers": "1.0.2", "on-headers": "1.0.2",
"raw-body": "2.4.1", "raw-body": "2.4.1",
"request": "2.88.0", "request": "2.88.0",
"tough-cookie": "4.0.0",
"uuid":"8.3.2",
"ws": "7.4.6", "ws": "7.4.6",
"xml2js": "0.4.23", "xml2js": "0.4.23",
"iconv-lite": "0.6.3" "iconv-lite": "0.6.3"

View File

@ -138,8 +138,6 @@ describe('HTTP Request Node', function() {
}); });
testApp.use(fileUploadApp); testApp.use(fileUploadApp);
testApp.use(bodyParser.raw({type:"*/*"})); testApp.use(bodyParser.raw({type:"*/*"}));
testApp.use(cookieParser(undefined,{decode:String})); testApp.use(cookieParser(undefined,{decode:String}));
testApp.get('/statusCode204', function(req,res) { res.status(204).end();}); testApp.get('/statusCode204', function(req,res) { res.status(204).end();});
@ -166,11 +164,16 @@ describe('HTTP Request Node', function() {
res.send(""); res.send("");
}); });
testApp.get('/authenticate', function(req, res){ testApp.get('/authenticate', function(req, res){
var user = auth.parse(req.headers['authorization']); let result;
var result = { let authHeader = req.headers['authorization'];
user: user.name, if (/^Basic/.test(authHeader)) {
pass: user.pass, result = auth.parse(authHeader);
}; result.user = result.name;
} else if (/^Bearer/.test(authHeader)) {
result = {
token: authHeader.substring(7)
}
}
res.json(result); res.json(result);
}); });
testApp.get('/proxyAuthenticate', function(req, res){ testApp.get('/proxyAuthenticate', function(req, res){
@ -891,7 +894,8 @@ describe('HTTP Request Node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
n2.on("input", function(msg) { n2.on("input", function(msg) {
try { try {
msg.should.have.property('statusCode','ESOCKETTIMEDOUT'); msg.should.have.property('statusCode');
/TIMEDOUT/.test(msg.statusCode).should.be.true();
var logEvents = helper.log().args.filter(function(evt) { var logEvents = helper.log().args.filter(function(evt) {
return evt[0].type == 'http request'; return evt[0].type == 'http request';
}); });
@ -917,7 +921,8 @@ describe('HTTP Request Node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
n2.on("input", function(msg) { n2.on("input", function(msg) {
try { try {
msg.should.have.property('statusCode','ESOCKETTIMEDOUT'); msg.should.have.property('statusCode');
/TIMEDOUT/.test(msg.statusCode).should.be.true();
var logEvents = helper.log().args.filter(function(evt) { var logEvents = helper.log().args.filter(function(evt) {
return evt[0].type == 'http request'; return evt[0].type == 'http request';
}); });
@ -1380,7 +1385,6 @@ describe('HTTP Request Node', function() {
n1.receive({payload:"foo"}); n1.receive({payload:"foo"});
}); });
}); });
it('should use http_proxy', function(done) { it('should use http_proxy', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')}, var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
{id:"n2", type:"helper"}]; {id:"n2", type:"helper"}];
@ -1565,9 +1569,8 @@ describe('HTTP Request Node', function() {
}); });
}); });
}); });
describe('authentication', function() { describe('authentication', function() {
it('should authenticate on server', function(done) { it('should authenticate on server - basic', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/authenticate')}, var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/authenticate')},
{id:"n2", type:"helper"}]; {id:"n2", type:"helper"}];
helper.load(httpRequestNode, flow, function() { helper.load(httpRequestNode, flow, function() {
@ -1587,7 +1590,25 @@ describe('HTTP Request Node', function() {
n1.receive({payload:"foo"}); n1.receive({payload:"foo"});
}); });
}); });
it('should authenticate on server - bearer', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",authType:"bearer", url:getTestURL('/authenticate')},
{id:"n2", type:"helper"}];
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.credentials = {password:'passwordfoo'};
n2.on("input", function(msg) {
try {
msg.should.have.property('statusCode',200);
msg.payload.should.have.property('token', 'passwordfoo');
done();
} catch(err) {
done(err);
}
});
n1.receive({payload:"foo"});
});
});
it('should authenticate on proxy server', function(done) { it('should authenticate on proxy server', function(done) {
var flow = [{id:"n1",type:"http request", wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/proxyAuthenticate')}, var flow = [{id:"n1",type:"http request", wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/proxyAuthenticate')},
{id:"n2", type:"helper"}]; {id:"n2", type:"helper"}];
@ -1740,22 +1761,24 @@ describe('HTTP Request Node', function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
n2.on("input", function(msg) { n2.on("input", function(msg) {
var cookies1 = receivedCookies['localhost:'+testPort+'/redirectToSameDomain']; try {
var cookies2 = receivedCookies['localhost:'+testPort+'/redirectReturn']; var cookies1 = receivedCookies['localhost:'+testPort+'/redirectToSameDomain'];
if (cookies1 && Object.keys(cookies1).length != 0) { var cookies2 = receivedCookies['localhost:'+testPort+'/redirectReturn'];
done(new Error('Invalid cookie(path:/rediectToSame)')); if (cookies1 && Object.keys(cookies1).length != 0) {
return; done(new Error('Invalid cookie(path:/rediectToSame)'));
} return;
if ((cookies2 && Object.keys(cookies2).length != 1) || }
if ((cookies2 && Object.keys(cookies2).length != 1) ||
cookies2['redirectToSameDomainCookie'] !== 'same1') { cookies2['redirectToSameDomainCookie'] !== 'same1') {
done(new Error('Invalid cookie(path:/rediectReurn)')); done(new Error('Invalid cookie(path:/rediectReurn)'));
return; return;
} }
var redirect1 = msg.redirectList[0]; var redirect1 = msg.redirectList[0];
redirect1.location.should.equal('http://localhost:'+testPort+'/redirectReturn'); redirect1.location.should.equal('http://localhost:'+testPort+'/redirectReturn');
redirect1.cookies.redirectToSameDomainCookie.Path.should.equal('/'); redirect1.cookies.redirectToSameDomainCookie.Path.should.equal('/');
redirect1.cookies.redirectToSameDomainCookie.value.should.equal('same1'); redirect1.cookies.redirectToSameDomainCookie.value.should.equal('same1');
done(); done();
} catch(err) { done(err)}
}); });
n1.receive({}); n1.receive({});
}); });