DockerERTFF/lib/modules/api.js

148 lines
5.7 KiB
JavaScript

const { http, https } = require('follow-redirects');
const querystring = require('querystring');
const zlib = require('zlib');
const pkg = require('../../package.json');
const HttpError = require('../errors/httpError');
module.exports = {
send: async function(options) {
let url = this.parseRequired(options.url, 'string', 'api.send: url is required.');
let method = this.parseOptional(options.method, 'string', 'GET');
let data = this.parseOptional(options.data, '*', '');
let dataType = this.parseOptional(options.dataType, 'string', 'auto');
let verifySSL = this.parseOptional(options.verifySSL, 'boolean', false);
let params = this.parseOptional(options.params, 'object', null);
let headers = this.parseOptional(options.headers, 'object', {});
let username = this.parseOptional(options.username, 'string', '');
let password = this.parseOptional(options.password, 'string', '');
let oauth = this.parseOptional(options.oauth, 'string', '');
let throwErrors = this.parseOptional(options.throwErrors, 'boolean', false);
let passErrors = this.parseOptional(options.passErrors, 'boolean', true);
let timeout = this.parseOptional(options.timeout, 'number', 0);
if (params) {
url += '?' + querystring.stringify(params);
}
if (dataType == 'auto' && method == 'POST') {
dataType = 'x-www-form-urlencoded';
}
if (dataType != 'auto' && !headers['Content-Type']) {
headers['Content-Type'] = `application/${dataType}`;
}
if (dataType == 'x-www-form-urlencoded') {
data = querystring.stringify(data);
} else if (typeof data != 'string') {
data = JSON.stringify(data);
}
if (data) {
headers['Content-Length'] = Buffer.byteLength(data);
}
const Url = new URL(url);
const opts = { method, headers, rejectUnauthorized: !!verifySSL, maxBodyLength: 1_000_000_000 };
if (timeout > 0) {
opts.timeout = timeout;
}
if (username || password) {
opts.auth = `${username}:${password}`;
}
if (oauth) {
//const provider = this.oauth[oauth];
const provider = await this.getOAuthProvider(oauth);
if (provider && provider.access_token) {
headers['Authorization'] = 'Bearer ' + provider.access_token;
}
}
if (!headers['User-Agent']) headers['User-Agent'] = `${pkg.name}/${pkg.version}`;
if (!headers['Accept']) headers['Accept'] = 'application/json';
return new Promise((resolve, reject) => {
const req = (Url.protocol == 'https:' ? https : http).request(Url, opts, res => {
let body = '';
if (res.statusCode == 204 || res.headers['content-length'] == 0) {
return resolve({ status: res.statusCode, headers: res.headers, data: '' });
}
let output = res;
if (res.headers['content-encoding'] == 'br') {
output = res.pipe(zlib.createBrotliDecompress());
}
if (res.headers['content-encoding'] == 'gzip') {
output = res.pipe(zlib.createGunzip());
}
if (res.headers['content-encoding'] == 'deflate') {
output = res.pipe(zlib.createInflate());
}
output.setEncoding('utf8');
output.on('data', chunk => body += chunk);
output.on('end', () => {
if (passErrors && res.statusCode >= 400) {
if (passErrors) {
this.res.status(res.statusCode).send(body);
return resolve();
}
}
if (body.charCodeAt(0) === 0xFEFF) {
body = body.slice(1);
}
if (res.headers['content-type'] && res.headers['content-type'].includes('json')) {
try {
body = JSON.parse(body);
} catch(e) {
console.error(e);
}
}
if (throwErrors && res.statusCode >= 400) {
return reject(new HttpError({
url: url,
status: res.statusCode,
statusText: res.statusMessage,
body: body
}));
}
resolve({
status: res.statusCode,
headers: res.headers,
data: body
});
});
});
req.on('timeout', () => {
req.destroy(new Error(`Request timed out after ${timeout}ms`));
if (throwErrors) {
reject(new Error(`Request timed out after ${timeout}ms`));
} else if (passErrors) {
this.res.status(504).send(`Request timed out after ${timeout}ms`);
resolve();
} else {
resolve({
status: 504,
data: `Request timed out after ${timeout}ms`
});
}
});
req.on('error', reject);
req.write(data);
req.end();
});
},
};