lib/net/request.js (51 lines of code) (raw):
const {http, https} = require('follow-redirects');
const HttpMessage = require('./httpmessage');
/**
* @typedef {import('http').ClientRequest} ClientRequest
*/
/**
* @param {string | URL} message
* @param {{ method?: string; headers?: * }} options
* @param {(error: (Error & {statusCode?: number})|null, data?: *) => void} fn
* @returns ClientRequest
*/
function request(message, options, fn) {
message = HttpMessage(message);
const updatedOptions = updateOptions(options);
const netProvider = message.protocol === 'http:' ? http : https;
const req = netProvider.request(message, updatedOptions, onResponse);
req.on('error', (error) => {
fn && fn(error, null);
});
return closeMaybe(/**@type ClientRequest */(req), updatedOptions);
/**
* @param {import('http').IncomingMessage} res
*/
function onResponse(res) {
/**@type {*}*/
let data = '';
/**@type {(Error & {statusCode?: number, data?: *})|null}*/
let error = null;
res.on('data', (chunk) => {
data += chunk.toString();
});
res.on('end', function() {
const contentType = res.headers['content-type'] || '';
if (contentType.indexOf('application/json') > -1) {
data = JSON.parse(data);
}
if (res.statusCode && (res.statusCode < 200 || res.statusCode > 299)) {
const errorDesc = data.error_description || '';
error = new Error('[' + res.statusCode + '] ' + (errorDesc || res.statusMessage));
error.statusCode = res.statusCode;
error.data = data;
}
fn && fn(error, data);
});
res.on('error', (error) => {
fn && fn(error, data);
});
}
}
/**
* @param {import('http').ClientRequest} req
* @param {{ method: string; headers: {} }} options
* @returns ClientRequest
*/
function closeMaybe(req, options) {
if (options.method === 'GET') req.end();
return req;
}
/**
* @param {{ method?: string; headers?: *}} options
*/
function updateOptions(options) {
return {
method: options?.method ?? 'GET',
headers: {
'User-Agent': options?.headers?.['User-Agent'] ??
[`Nodejs/${process.versions.node}`,
`YouTrackCLI/${require('../../package.json').version}`].join(' '),
...options.headers
}
};
}
module.exports = request;