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:
commit
7bf938901a
@ -43,9 +43,12 @@
|
||||
"denque": "1.5.0",
|
||||
"express": "4.17.1",
|
||||
"express-session": "1.17.2",
|
||||
"form-data": "4.0.0",
|
||||
"fs-extra": "10.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"got": "11.8.2",
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "0.1.1",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"i18next": "20.3.1",
|
||||
"iconv-lite": "0.6.3",
|
||||
@ -72,8 +75,14 @@
|
||||
"request": "2.88.0",
|
||||
"semver": "7.3.5",
|
||||
"tar": "6.1.0",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uglify-js": "3.13.8",
|
||||
"uuid": "8.3.2",
|
||||
"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"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
@ -16,7 +16,13 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"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 querystring = require("querystring");
|
||||
var cookie = require("cookie");
|
||||
@ -30,6 +36,8 @@ module.exports = function(RED) {
|
||||
var nodeMethod = n.method || "GET";
|
||||
var paytoqs = false;
|
||||
var paytobody = false;
|
||||
var redirectList = [];
|
||||
|
||||
var nodeHTTPPersistent = n["persist"];
|
||||
if (n.tls) {
|
||||
var tlsNode = RED.nodes.getNode(n.tls);
|
||||
@ -57,12 +65,15 @@ module.exports = function(RED) {
|
||||
}
|
||||
|
||||
this.on("input",function(msg,nodeSend,nodeDone) {
|
||||
//reset redirectList on each request
|
||||
redirectList = [];
|
||||
var preRequestTimestamp = process.hrtime();
|
||||
node.status({fill:"blue",shape:"dot",text:"httpin.status.requesting"});
|
||||
var url = nodeUrl || msg.url;
|
||||
if (msg.url && nodeUrl && (nodeUrl !== msg.url)) { // revert change below when warning is finally removed
|
||||
node.warn(RED._("common.errors.nooverride"));
|
||||
}
|
||||
|
||||
if (isTemplatedUrl) {
|
||||
url = mustache.render(nodeUrl,msg);
|
||||
}
|
||||
@ -71,6 +82,8 @@ module.exports = function(RED) {
|
||||
nodeDone();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// url must start http:// or https:// so assume http:// if not set
|
||||
if (url.indexOf("://") !== -1 && url.indexOf("http") !== 0) {
|
||||
node.warn(RED._("httpin.errors.invalid-transport"));
|
||||
@ -86,6 +99,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var method = nodeMethod.toUpperCase() || "GET";
|
||||
if (msg.method && n.method && (n.method !== "use")) { // warn if override option not set
|
||||
node.warn(RED._("common.errors.nooverride"));
|
||||
@ -94,19 +108,19 @@ module.exports = function(RED) {
|
||||
method = msg.method.toUpperCase(); // use the msg parameter
|
||||
}
|
||||
|
||||
var isHttps = (/^https/i.test(url));
|
||||
// var isHttps = (/^https/i.test(url));
|
||||
|
||||
var opts = {};
|
||||
opts.url = url;
|
||||
// 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.method = method;
|
||||
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.jar = request.jar();
|
||||
opts.proxy = null;
|
||||
opts.cookieJar = new CookieJar();
|
||||
opts.forever = nodeHTTPPersistent;
|
||||
if (msg.requestTimeout !== undefined) {
|
||||
if (isNaN(msg.requestTimeout)) {
|
||||
@ -117,6 +131,21 @@ module.exports = function(RED) {
|
||||
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 clSet = "Content-Length";
|
||||
if (msg.headers) {
|
||||
@ -144,30 +173,15 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.hasOwnProperty('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;
|
||||
};
|
||||
opts.followRedirect = !!msg.followRedirects;
|
||||
}
|
||||
|
||||
if (opts.headers.hasOwnProperty('cookie')) {
|
||||
var cookies = cookie.parse(opts.headers.cookie, {decode:String});
|
||||
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;
|
||||
}
|
||||
@ -180,13 +194,13 @@ module.exports = function(RED) {
|
||||
} else if (typeof msg.cookies[name] === 'object') {
|
||||
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);
|
||||
opts.cookieJar.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);
|
||||
opts.cookieJar.setCookie(cookie.serialize(name, msg.cookies[name].value), url);
|
||||
}
|
||||
} 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.authType === "basic") {
|
||||
if (this.credentials.user) {
|
||||
opts.auth = {
|
||||
user: this.credentials.user,
|
||||
pass: this.credentials.password || ""
|
||||
};
|
||||
opts.username = this.credentials.user;
|
||||
}
|
||||
if (this.credentials.password) {
|
||||
opts.password = this.credentials.password;
|
||||
}
|
||||
} else if (this.authType === "digest") {
|
||||
if (this.credentials.user) {
|
||||
// The first request will be sent without auth information. Based on the 401 response, the library can determine
|
||||
// which auth type is required by the server. Then the request is resubmitted with the appropriate auth header.
|
||||
opts.auth = {
|
||||
user: this.credentials.user,
|
||||
pass: this.credentials.password || "",
|
||||
sendImmediately: false
|
||||
};
|
||||
}
|
||||
let digestCreds = this.credentials;
|
||||
let sentCreds = false;
|
||||
opts.hooks.afterResponse = [(response, retry) => {
|
||||
if (response.statusCode === 401) {
|
||||
if (sentCreds) {
|
||||
return response
|
||||
}
|
||||
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") {
|
||||
opts.auth = {
|
||||
bearer: this.credentials.password || ""
|
||||
};
|
||||
opts.headers.Authorization = `Bearer ${this.credentials.password||""}`
|
||||
}
|
||||
}
|
||||
var payload = null;
|
||||
|
||||
|
||||
if (method !== 'GET' && method !== 'HEAD' && typeof msg.payload !== "undefined") {
|
||||
if (opts.headers['content-type'] == 'multipart/form-data' && typeof msg.payload === "object") {
|
||||
opts.formData = {};
|
||||
|
||||
let formData = new FormData();
|
||||
for (var opt in msg.payload) {
|
||||
if (msg.payload.hasOwnProperty(opt)) {
|
||||
var val = msg.payload[opt];
|
||||
if (val !== undefined && val !== null) {
|
||||
if (typeof val === 'string' || Buffer.isBuffer(val)) {
|
||||
opts.formData[opt] = val;
|
||||
formData.append(opt, val);
|
||||
} else if (typeof val === 'object' && val.hasOwnProperty('value')) {
|
||||
// Treat as file to upload - ensure it has an options object
|
||||
// as request complains if it doesn't
|
||||
if (!val.hasOwnProperty('options')) {
|
||||
val.options = {};
|
||||
}
|
||||
opts.formData[opt] = val;
|
||||
formData.append(opt,val.value,val.options || {});
|
||||
} 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 {
|
||||
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
|
||||
payload = msg.payload;
|
||||
@ -266,25 +290,29 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (method == 'GET' && typeof msg.payload !== "undefined" && paytoqs) {
|
||||
if (typeof msg.payload === "object") {
|
||||
try {
|
||||
if (opts.url.indexOf("?") !== -1) {
|
||||
opts.url += (opts.url.endsWith("?")?"":"&") + querystring.stringify(msg.payload);
|
||||
if (url.indexOf("?") !== -1) {
|
||||
url += (url.endsWith("?")?"":"&") + querystring.stringify(msg.payload);
|
||||
} else {
|
||||
opts.url += "?" + querystring.stringify(msg.payload);
|
||||
url += "?" + querystring.stringify(msg.payload);
|
||||
}
|
||||
} catch(err) {
|
||||
|
||||
node.error(RED._("httpin.errors.invalid-payload"),msg);
|
||||
nodeDone();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
node.error(RED._("httpin.errors.invalid-payload"),msg);
|
||||
nodeDone();
|
||||
return;
|
||||
}
|
||||
} else if ( method == "GET" && typeof msg.payload !== "undefined" && paytobody) {
|
||||
opts.allowGetBody = true;
|
||||
if (typeof msg.payload === "object") {
|
||||
opts.body = JSON.stringify(msg.payload);
|
||||
} else if (typeof msg.payload == "number") {
|
||||
@ -311,79 +339,97 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
if (prox && !noproxy) {
|
||||
var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i);
|
||||
var match = prox.match(/^(https?:\/\/)?(.+)?:([0-9]+)?/i);
|
||||
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 {
|
||||
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) {
|
||||
tlsNode.addTLSOptions(opts);
|
||||
opts.https = {};
|
||||
tlsNode.addTLSOptions(opts.https);
|
||||
} else {
|
||||
if (msg.hasOwnProperty('rejectUnauthorized')) {
|
||||
opts.rejectUnauthorized = msg.rejectUnauthorized;
|
||||
opts.https = { rejectUnauthorized: msg.rejectUnauthorized };
|
||||
}
|
||||
}
|
||||
request(opts, function(err, res, body) {
|
||||
if(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;
|
||||
nodeSend(msg);
|
||||
nodeDone();
|
||||
}else{
|
||||
msg.statusCode = res.statusCode;
|
||||
msg.headers = res.headers;
|
||||
msg.responseUrl = res.request.uri.href;
|
||||
msg.payload = body;
|
||||
msg.redirectList = redirectList;
|
||||
got(url,opts).then(res => {
|
||||
msg.statusCode = res.statusCode;
|
||||
msg.headers = res.headers;
|
||||
msg.responseUrl = res.url;
|
||||
msg.payload = res.body;
|
||||
msg.redirectList = redirectList;
|
||||
msg.retry = 0;
|
||||
|
||||
if (msg.headers.hasOwnProperty('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();
|
||||
if (msg.headers.hasOwnProperty('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();
|
||||
}).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"}
|
||||
}
|
||||
});
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,12 @@
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
"denque": "1.5.0",
|
||||
"form-data": "4.0.0",
|
||||
"fs-extra": "10.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"got": "11.8.2",
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "0.1.1",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.14.0",
|
||||
@ -39,6 +42,8 @@
|
||||
"on-headers": "1.0.2",
|
||||
"raw-body": "2.4.1",
|
||||
"request": "2.88.0",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uuid":"8.3.2",
|
||||
"ws": "7.4.6",
|
||||
"xml2js": "0.4.23",
|
||||
"iconv-lite": "0.6.3"
|
||||
|
@ -138,8 +138,6 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
testApp.use(fileUploadApp);
|
||||
|
||||
|
||||
|
||||
testApp.use(bodyParser.raw({type:"*/*"}));
|
||||
testApp.use(cookieParser(undefined,{decode:String}));
|
||||
testApp.get('/statusCode204', function(req,res) { res.status(204).end();});
|
||||
@ -166,11 +164,16 @@ describe('HTTP Request Node', function() {
|
||||
res.send("");
|
||||
});
|
||||
testApp.get('/authenticate', function(req, res){
|
||||
var user = auth.parse(req.headers['authorization']);
|
||||
var result = {
|
||||
user: user.name,
|
||||
pass: user.pass,
|
||||
};
|
||||
let result;
|
||||
let authHeader = req.headers['authorization'];
|
||||
if (/^Basic/.test(authHeader)) {
|
||||
result = auth.parse(authHeader);
|
||||
result.user = result.name;
|
||||
} else if (/^Bearer/.test(authHeader)) {
|
||||
result = {
|
||||
token: authHeader.substring(7)
|
||||
}
|
||||
}
|
||||
res.json(result);
|
||||
});
|
||||
testApp.get('/proxyAuthenticate', function(req, res){
|
||||
@ -891,7 +894,8 @@ describe('HTTP Request Node', function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
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) {
|
||||
return evt[0].type == 'http request';
|
||||
});
|
||||
@ -917,7 +921,8 @@ describe('HTTP Request Node', function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
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) {
|
||||
return evt[0].type == 'http request';
|
||||
});
|
||||
@ -1380,7 +1385,6 @@ describe('HTTP Request Node', function() {
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should use http_proxy', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
|
||||
{id:"n2", type:"helper"}];
|
||||
@ -1565,9 +1569,8 @@ describe('HTTP Request Node', 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')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
@ -1587,7 +1590,25 @@ describe('HTTP Request Node', function() {
|
||||
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) {
|
||||
var flow = [{id:"n1",type:"http request", wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/proxyAuthenticate')},
|
||||
{id:"n2", type:"helper"}];
|
||||
@ -1740,22 +1761,24 @@ describe('HTTP Request Node', 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) ||
|
||||
try {
|
||||
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;
|
||||
}
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://localhost:'+testPort+'/redirectReturn');
|
||||
redirect1.cookies.redirectToSameDomainCookie.Path.should.equal('/');
|
||||
redirect1.cookies.redirectToSameDomainCookie.value.should.equal('same1');
|
||||
done();
|
||||
done(new Error('Invalid cookie(path:/rediectReurn)'));
|
||||
return;
|
||||
}
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://localhost:'+testPort+'/redirectReturn');
|
||||
redirect1.cookies.redirectToSameDomainCookie.Path.should.equal('/');
|
||||
redirect1.cookies.redirectToSameDomainCookie.value.should.equal('same1');
|
||||
done();
|
||||
} catch(err) { done(err)}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user