New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

teepee

Package Overview
Dependencies
Maintainers
5
Versions
77
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

teepee - npm Package Compare versions

Comparing version 2.31.2 to 3.0.0

.eslintrc

1639

lib/Teepee.js

@@ -1,47 +0,45 @@

/*global JSON, setTimeout, setImmediate*/
var EventEmitter = require('events').EventEmitter,
Promise = require('bluebird'),
util = require('util'),
urlModule = require('url'),
fs = require('fs'),
zlib = require('zlib'),
HttpError = require('httperrors'),
SocketError = require('socketerrors'),
DnsError = require('dnserrors'),
createError = require('createerror'),
os = require('os'),
passError = require('passerror'),
isStream = require('is-stream'),
FormData = require('form-data'),
http = require('http'),
https = require('https'),
SelfRedirectError = createError({name: 'SelfRedirect'}),
omit = require('lodash.omit'),
assign = require('lodash.assign'),
uniq = require('lodash.uniq'),
clone = require('lodash.clone'),
defaults = require('lodash.defaults');
/* global JSON, setTimeout, setImmediate */
const EventEmitter = require('events').EventEmitter;
const util = require('util');
const urlModule = require('url');
const fs = require('fs');
const zlib = require('zlib');
const HttpError = require('httperrors');
const SocketError = require('socketerrors');
const DnsError = require('dnserrors');
const createError = require('createerror');
const os = require('os');
const passError = require('passerror');
const isStream = require('is-stream');
const FormData = require('form-data');
const http = require('http');
const https = require('https');
const SelfRedirectError = createError({ name: 'SelfRedirect' });
const omit = require('lodash.omit');
const uniq = require('lodash.uniq');
const clone = require('lodash.clone');
const defaults = require('lodash.defaults');
function isContentTypeJson(contentType) {
return /^application\/json\b|\+json\b/i.test(contentType);
return /^application\/json\b|\+json\b/i.test(contentType);
}
function resolveCertKeyOrCa(value) {
if (typeof value === 'string') {
return fs.readFileSync(value.replace(/\{hostname\}/g, os.hostname()));
} else if (Array.isArray(value)) {
// An array of ca file names
return value.map(resolveCertKeyOrCa);
} else {
return value;
}
if (typeof value === 'string') {
return fs.readFileSync(value.replace(/\{hostname\}/g, os.hostname()));
} else if (Array.isArray(value)) {
// An array of ca file names
return value.map(resolveCertKeyOrCa);
} else {
return value;
}
}
function safeDecodeURIComponent(str) {
try {
return decodeURIComponent(str);
} catch (e) {
// Assume URIError: URI malformed (percent encoded octets that don't decode as UTF-8)
return str;
}
try {
return decodeURIComponent(str);
} catch (e) {
// Assume URIError: URI malformed (percent encoded octets that don't decode as UTF-8)
return str;
}
}

@@ -69,49 +67,53 @@

function Teepee(config) {
if (!(this instanceof Teepee)) {
// Invoked without new, shorthand for issuing a request
var args = Array.prototype.slice.call(arguments);
var teepee;
if (typeof args[0] === 'string' || (args[0] && typeof args[0] === 'object')) {
teepee = new Teepee(args.shift());
}
return teepee.request.apply(teepee, args);
if (!(this instanceof Teepee)) {
// Invoked without new, shorthand for issuing a request
const args = Array.prototype.slice.call(arguments);
let teepee;
if (
typeof args[0] === 'string' ||
(args[0] && typeof args[0] === 'object')
) {
teepee = new Teepee(args.shift());
}
return teepee.request.apply(teepee, args);
}
EventEmitter.call(this);
EventEmitter.call(this);
if (typeof config === 'string') {
config = { url: config };
}
if (typeof config === 'string') {
config = { url: config };
}
this._userSuppliedConfigOptionNames = [];
if (config) {
Object.keys(config).forEach(function (key) {
var value = config[key];
if (typeof value !== 'undefined') {
if (key === 'agent' && typeof value !== 'boolean') {
var protocol = config.url && /^https:/.test(config.url) ? 'https' : 'http';
this.agentByProtocol = this.agentByProtocol || {};
this.agentByProtocol[protocol] = value;
} else if (key === 'cert' || key === 'key' || key === 'ca') {
this[key] = resolveCertKeyOrCa(value);
this._userSuppliedConfigOptionNames.push(key);
} else if (typeof this[key] === 'undefined') {
this[key] = value;
this._userSuppliedConfigOptionNames.push(key);
} else {
// Ignore unsupported property that would overwrite or shadow for a built-in property or method
}
}
}, this);
}
this._userSuppliedConfigOptionNames = [];
if (config) {
Object.keys(config).forEach(function(key) {
const value = config[key];
if (typeof value !== 'undefined') {
if (key === 'agent' && typeof value !== 'boolean') {
const protocol =
config.url && /^https:/.test(config.url) ? 'https' : 'http';
this.agentByProtocol = this.agentByProtocol || {};
this.agentByProtocol[protocol] = value;
} else if (key === 'cert' || key === 'key' || key === 'ca') {
this[key] = resolveCertKeyOrCa(value);
this._userSuppliedConfigOptionNames.push(key);
} else if (typeof this[key] === 'undefined') {
this[key] = value;
this._userSuppliedConfigOptionNames.push(key);
} else {
// Ignore unsupported property that would overwrite or shadow for a built-in property or method
}
}
}, this);
}
if (typeof this.url === 'string') {
if (/^[A-Z]+ /.test(this.url)) {
var urlFragments = this.url.split(' ');
if (urlFragments.length > 1) {
this.method = urlFragments.shift();
this.url = urlFragments.join(' ');
}
}
if (typeof this.url === 'string') {
if (/^[A-Z]+ /.test(this.url)) {
const urlFragments = this.url.split(' ');
if (urlFragments.length > 1) {
this.method = urlFragments.shift();
this.url = urlFragments.join(' ');
}
}
}
}

@@ -121,180 +123,230 @@

Teepee.prototype.subsidiary = function (config) {
var subsidiary = new this.constructor(config);
Teepee.prototype.subsidiary = function(config) {
const subsidiary = new this.constructor(config);
if (this.headers) {
if (subsidiary.headers) {
defaults(subsidiary.headers, this.headers);
} else {
subsidiary.headers = clone(this.headers);
}
if (this.headers) {
if (subsidiary.headers) {
defaults(subsidiary.headers, this.headers);
} else {
subsidiary.headers = clone(this.headers);
}
}
if (this.query) {
if (subsidiary.query) {
defaults(subsidiary.query, this.query);
} else {
subsidiary.query = clone(this.query);
}
if (this.query) {
if (subsidiary.query) {
defaults(subsidiary.query, this.query);
} else {
subsidiary.query = clone(this.query);
}
}
// Make sure that the subsidiary will get the same object so all agents are shared:
this.agentByProtocol = this.agentByProtocol || {};
// Make sure that the subsidiary will get the same object so all agents are shared:
this.agentByProtocol = this.agentByProtocol || {};
var that = this,
subsidiaryEmit = subsidiary.emit;
subsidiary.emit = function () {
subsidiaryEmit.apply(this, arguments);
that.emit.apply(that, arguments);
};
const that = this;
const subsidiaryEmit = subsidiary.emit;
subsidiary.emit = function() {
subsidiaryEmit.apply(this, arguments);
that.emit.apply(that, arguments);
};
defaults(subsidiary, this);
defaults(subsidiary, this);
if (this._userSuppliedConfigOptionNames.length > 0) {
if (subsidiary._userSuppliedConfigOptionNames.length > 0) {
subsidiary._userSuppliedConfigOptionNames = uniq(this._userSuppliedConfigOptionNames.concat(subsidiary._userSuppliedConfigOptionNames));
} else {
subsidiary._userSuppliedConfigOptionNames = this._userSuppliedConfigOptionNames;
}
if (this._userSuppliedConfigOptionNames.length > 0) {
if (subsidiary._userSuppliedConfigOptionNames.length > 0) {
subsidiary._userSuppliedConfigOptionNames = uniq(
this._userSuppliedConfigOptionNames.concat(
subsidiary._userSuppliedConfigOptionNames
)
);
} else {
subsidiary._userSuppliedConfigOptionNames = this._userSuppliedConfigOptionNames;
}
}
return subsidiary;
return subsidiary;
};
Teepee.prototype.extractNonRequestOptions = function (obj) {
var result = {};
if (obj) {
Object.keys(obj).forEach(function (key) {
if (key !== 'method' && key !== 'headers' && key !== 'path' && key !== 'query' && key !== 'streamRows' && key !== 'eventEmitter' && key !== 'url' && key !== 'path') {
result[key] = obj[key];
}
});
}
return result;
Teepee.prototype.extractNonRequestOptions = obj => {
const result = {};
if (obj) {
Object.keys(obj).forEach(key => {
if (
key !== 'method' &&
key !== 'headers' &&
key !== 'path' &&
key !== 'query' &&
key !== 'streamRows' &&
key !== 'eventEmitter' &&
key !== 'url' &&
key !== 'path'
) {
result[key] = obj[key];
}
});
}
return result;
};
Teepee.prototype.preprocessQueryStringParameterValue = function (queryStringParameterValue, queryStringParameterName) {
return queryStringParameterValue;
};
Teepee.prototype.preprocessQueryStringParameterValue = (
queryStringParameterValue,
queryStringParameterName
) => queryStringParameterValue;
Teepee.prototype.stringifyJsonRequestBody = JSON.stringify;
Teepee.prototype._addQueryStringToUrl = function (url, query) {
if (typeof query !== 'undefined') {
if (typeof query === 'string') {
if (query.length > 0) {
url += (url.indexOf('?') === -1 ? '?' : '&') + query;
}
} else {
// Assume object
var params = [];
Object.keys(query).forEach(function (key) {
var value = query[key];
if (Array.isArray(value)) {
// Turn query: {foo: ['a', 'b']} into ?foo=a&foo=b
value.forEach(function (valueArrayItem) {
params.push(encodeURIComponent(key) + '=' + encodeURIComponent(this.preprocessQueryStringParameterValue(valueArrayItem, key)));
}, this);
} else if (typeof value !== 'undefined') {
params.push(encodeURIComponent(key) + '=' + encodeURIComponent(this.preprocessQueryStringParameterValue(value, key)));
}
}, this);
Teepee.prototype._addQueryStringToUrl = function(url, query) {
if (typeof query !== 'undefined') {
if (typeof query === 'string') {
if (query.length > 0) {
url += (url.indexOf('?') === -1 ? '?' : '&') + query;
}
} else {
// Assume object
const params = [];
Object.keys(query).forEach(function(key) {
const value = query[key];
if (Array.isArray(value)) {
// Turn query: {foo: ['a', 'b']} into ?foo=a&foo=b
value.forEach(function(valueArrayItem) {
params.push(
`${encodeURIComponent(key)}=${encodeURIComponent(
this.preprocessQueryStringParameterValue(valueArrayItem, key)
)}`
);
}, this);
} else if (typeof value !== 'undefined') {
params.push(
`${encodeURIComponent(key)}=${encodeURIComponent(
this.preprocessQueryStringParameterValue(value, key)
)}`
);
}
}, this);
if (params.length > 0) {
url += (url.indexOf('?') === -1 ? '?' : '&') + params.join('&');
}
}
if (params.length > 0) {
url += (url.indexOf('?') === -1 ? '?' : '&') + params.join('&');
}
}
return url;
}
return url;
};
Teepee.prototype.getPlaceholderValue = function (placeholderName, requestOptions) {
if (typeof requestOptions[placeholderName] !== 'undefined') {
return requestOptions[placeholderName];
Teepee.prototype.getPlaceholderValue = function(
placeholderName,
requestOptions
) {
if (typeof requestOptions[placeholderName] !== 'undefined') {
return requestOptions[placeholderName];
} else {
const type = typeof this[placeholderName];
if (type === 'undefined') {
return `{${placeholderName}}`;
} else {
var type = typeof this[placeholderName];
if (type === 'undefined') {
return '{' + placeholderName + '}';
} else {
var value = this[placeholderName];
if (typeof value === 'function') {
return value.call(this, requestOptions, placeholderName);
} else {
return String(value);
}
}
const value = this[placeholderName];
if (typeof value === 'function') {
return value.call(this, requestOptions, placeholderName);
} else {
return String(value);
}
}
}
};
Teepee.prototype.expandUrl = function (url, requestOptions) {
requestOptions = requestOptions || {};
var that = this;
var expandedUrl = url.replace(/\{((?:[^\{\}]+|\{\w+\})*)\}/g, function ($0, placeholderName) {
if (/^\w+$/.test(placeholderName)) {
return that.getPlaceholderValue(placeholderName, requestOptions, $0);
} else {
var methodName = '__placeholder_fn_' + placeholderName;
if (!that[methodName]) {
that[methodName] = new Function('requestOptions', 'return ' + placeholderName.replace(/\{(\w+)\}/g, 'this.getPlaceholderValue("$1", requestOptions)') + ';');
}
return that[methodName](requestOptions);
Teepee.prototype.expandUrl = function(url, requestOptions) {
requestOptions = requestOptions || {};
const that = this;
let expandedUrl = url.replace(
/\{((?:[^{}]+|\{\w+\})*)\}/g,
($0, placeholderName) => {
if (/^\w+$/.test(placeholderName)) {
return that.getPlaceholderValue(placeholderName, requestOptions, $0);
} else {
const methodName = `__placeholder_fn_${placeholderName}`;
if (!that[methodName]) {
// eslint-disable-next-line no-new-func
that[methodName] = new Function(
'requestOptions',
`return ${placeholderName.replace(
/\{(\w+)\}/g,
'this.getPlaceholderValue("$1", requestOptions)'
)};`
);
}
});
if (!/^[a-z+]+:\/\//i.test(expandedUrl)) {
expandedUrl = 'http://' + expandedUrl;
return that[methodName](requestOptions);
}
}
return expandedUrl;
);
if (!/^[a-z+]+:\/\//i.test(expandedUrl)) {
expandedUrl = `http://${expandedUrl}`;
}
return expandedUrl;
};
Teepee.prototype.getAgent = function (protocol) {
if (!this.agentByProtocol) {
this.agentByProtocol = {};
}
if (this.agent || this.Agent || this.AgentByProtocol || (this.agentByProtocol && this.agentByProtocol[protocol])) {
if (!this.agentByProtocol[protocol]) {
var agentOptions = {};
// Pass all instance variables that originate from the user-supplied config object to the Agent constructor:
this._userSuppliedConfigOptionNames.forEach(function setAgentOptions(userSuppliedConfigOptionName) {
var value = this[userSuppliedConfigOptionName];
if (typeof value !== 'undefined') {
agentOptions[userSuppliedConfigOptionName] = value;
}
}, this);
var Agent = this.Agent || (this.AgentByProtocol && this.AgentByProtocol[protocol]) || (protocol === 'https' ? https : http).Agent;
this.agentByProtocol[protocol] = new Agent(agentOptions);
Teepee.prototype.getAgent = function(protocol) {
if (!this.agentByProtocol) {
this.agentByProtocol = {};
}
if (
this.agent ||
this.Agent ||
this.AgentByProtocol ||
(this.agentByProtocol && this.agentByProtocol[protocol])
) {
if (!this.agentByProtocol[protocol]) {
const agentOptions = {};
// Pass all instance variables that originate from the user-supplied config object to the Agent constructor:
this._userSuppliedConfigOptionNames.forEach(function setAgentOptions(
userSuppliedConfigOptionName
) {
const value = this[userSuppliedConfigOptionName];
if (typeof value !== 'undefined') {
agentOptions[userSuppliedConfigOptionName] = value;
}
return this.agentByProtocol[protocol];
},
this);
const Agent =
this.Agent ||
(this.AgentByProtocol && this.AgentByProtocol[protocol]) ||
(protocol === 'https' ? https : http).Agent;
this.agentByProtocol[protocol] = new Agent(agentOptions);
}
return this.agentByProtocol[protocol];
}
};
Teepee.prototype.resolveUrl = function (baseUrl, url, options) {
if (url && /^https?:\/\//.test(url)) {
return this.expandUrl(url, options);
} else if (baseUrl) {
baseUrl = this.expandUrl(baseUrl, options);
if (typeof url === 'string') {
if (/^\/\//.test(url) || /^\.\.?(?:$|\/)/.test(url)) {
// Protocol-relative or relative starting with a . or .. fragment, resolve it:
return urlModule.resolve(baseUrl, url);
} else {
// Borrowed from request: Handle all cases to make sure that there's only one slash between the baseUrl and url:
var baseUrlEndsWithSlash = baseUrl.lastIndexOf('/') === baseUrl.length - 1,
urlStartsWithSlash = url.indexOf('/') === 0;
Teepee.prototype.resolveUrl = function(baseUrl, url, options) {
if (url && /^https?:\/\//.test(url)) {
return this.expandUrl(url, options);
} else if (baseUrl) {
baseUrl = this.expandUrl(baseUrl, options);
if (typeof url === 'string') {
if (/^\/\//.test(url) || /^\.\.?(?:$|\/)/.test(url)) {
// Protocol-relative or relative starting with a . or .. fragment, resolve it:
// eslint-disable-next-line node/no-deprecated-api
return urlModule.resolve(baseUrl, url);
} else {
// Borrowed from request: Handle all cases to make sure that there's only one slash between the baseUrl and url:
const baseUrlEndsWithSlash =
baseUrl.lastIndexOf('/') === baseUrl.length - 1;
const urlStartsWithSlash = url.indexOf('/') === 0;
if (baseUrlEndsWithSlash && urlStartsWithSlash) {
return baseUrl + url.slice(1);
} else if (baseUrlEndsWithSlash || urlStartsWithSlash) {
return baseUrl + url;
} else if (url === '') {
return baseUrl;
} else {
return baseUrl + '/' + url;
}
}
if (baseUrlEndsWithSlash && urlStartsWithSlash) {
return baseUrl + url.slice(1);
} else if (baseUrlEndsWithSlash || urlStartsWithSlash) {
return baseUrl + url;
} else if (url === '') {
return baseUrl;
} else {
return baseUrl;
return `${baseUrl}/${url}`;
}
}
} else {
throw new Error('An absolute request url must be given when no base url is available');
return baseUrl;
}
} else {
throw new Error(
'An absolute request url must be given when no base url is available'
);
}
};

@@ -314,534 +366,660 @@

*/
Teepee.prototype.request = function (url, options, cb) {
if (typeof options === 'function') {
cb = options;
options = undefined;
} else if (typeof url === 'function') {
cb = url;
url = undefined;
options = undefined;
Teepee.prototype.request = function(url, options, cb) {
if (typeof options === 'function') {
cb = options;
options = undefined;
} else if (typeof url === 'function') {
cb = url;
url = undefined;
options = undefined;
}
if (typeof url === 'string') {
if (options && typeof options === 'object') {
options.url = url;
url = undefined;
} else if (typeof options === 'undefined') {
options = { url };
url = undefined;
} else {
throw new Error(
`Teepee#request: options cannot be passed as ${typeof options}`
);
}
if (typeof url === 'string') {
if (options && typeof options === 'object') {
options.url = url;
url = undefined;
} else if (typeof options === 'undefined') {
options = { url: url };
url = undefined;
} else {
throw new Error('Teepee#request: options cannot be passed as ' + typeof options);
}
} else if (url && typeof url === 'object') {
options = url;
url = undefined;
}
options = options || {};
} else if (url && typeof url === 'object') {
options = url;
url = undefined;
}
options = options || {};
var numRetriesLeft = options.streamRows ? 0 : typeof options.numRetries !== 'undefined' ? options.numRetries : this.numRetries || 0,
retryDelayMilliseconds = typeof options.retryDelayMilliseconds !== 'undefined' ? options.retryDelayMilliseconds : this.retryDelayMilliseconds || 0,
timeout = typeof options.timeout !== 'undefined' ? options.timeout : this.timeout,
username = typeof options.username !== 'undefined' ? options.username : this.username,
password = typeof options.password !== 'undefined' ? options.password : this.password,
body = typeof options.body !== 'undefined' ? options.body : this.body,
retry = typeof options.retry !== 'undefined' ? options.retry : this.retry || [],
rejectUnauthorized = typeof options.rejectUnauthorized !== 'undefined' ? options.rejectUnauthorized : this.rejectUnauthorized,
headers = {},
// Gotcha: A query specified as a string overrides this.query
query = typeof options.query === 'string' ? options.query : assign({}, this.query, options.query),
method = options.method,
requestUrl = typeof options.path === 'string' ? options.path : options.url,
autoDecodeJson = typeof options.json !== 'undefined' ? options.json !== false : this.json !== false; // Defaults to true
let numRetriesLeft = options.streamRows
? 0
: typeof options.numRetries !== 'undefined'
? options.numRetries
: this.numRetries || 0;
const retryDelayMilliseconds =
typeof options.retryDelayMilliseconds !== 'undefined'
? options.retryDelayMilliseconds
: this.retryDelayMilliseconds || 0;
const timeout =
typeof options.timeout !== 'undefined' ? options.timeout : this.timeout;
let username =
typeof options.username !== 'undefined' ? options.username : this.username;
let password =
typeof options.password !== 'undefined' ? options.password : this.password;
let body = typeof options.body !== 'undefined' ? options.body : this.body;
let retry =
typeof options.retry !== 'undefined' ? options.retry : this.retry || [];
const rejectUnauthorized =
typeof options.rejectUnauthorized !== 'undefined'
? options.rejectUnauthorized
: this.rejectUnauthorized;
const headers = {};
// Gotcha: A query specified as a string overrides this.query
const query =
typeof options.query === 'string'
? options.query
: { ...this.query, ...options.query };
let method = options.method;
let requestUrl =
typeof options.path === 'string' ? options.path : options.url;
const autoDecodeJson =
typeof options.json !== 'undefined'
? options.json !== false
: this.json !== false; // Defaults to true
var headerObjs = [this.headers, options.headers];
const headerObjs = [this.headers, options.headers];
if (options && options.formData) {
if (typeof body !== 'undefined') {
throw new Error('Teepee#request: The "body" and "formData" options are not supported together');
}
body = new FormData();
Object.keys(options.formData).forEach(function (name) {
var value = options.formData[name],
partOptions = {};
if (isStream.readable(value) && value.path) {
partOptions.filename = value.path;
} else if (typeof value === 'object' && !Buffer.isBuffer(value)) {
partOptions = assign({}, value);
value = partOptions.value;
delete partOptions.value;
if (partOptions.fileName) {
partOptions.filename = partOptions.fileName;
delete partOptions.fileName;
}
}
body.append(name, value, partOptions);
});
headerObjs.push(body.getHeaders());
if (options && options.formData) {
if (typeof body !== 'undefined') {
throw new Error(
'Teepee#request: The "body" and "formData" options are not supported together'
);
}
body = new FormData();
Object.keys(options.formData).forEach(name => {
let value = options.formData[name];
let partOptions = {};
headerObjs.forEach(function (headersObj) {
if (headersObj) {
Object.keys(headersObj).forEach(function (headerName) {
var headerValue = headersObj[headerName];
if (typeof headerValue === 'undefined') {
return;
}
headers[headerName.toLowerCase()] = headerValue;
});
if (isStream.readable(value) && value.path) {
partOptions.filename = value.path;
} else if (typeof value === 'object' && !Buffer.isBuffer(value)) {
partOptions = Object.assign({}, value);
value = partOptions.value;
delete partOptions.value;
if (partOptions.fileName) {
partOptions.filename = partOptions.fileName;
delete partOptions.fileName;
}
}
body.append(name, value, partOptions);
});
headerObjs.push(body.getHeaders());
}
if (typeof retry !== 'undefined' && !Array.isArray(retry)) {
retry = [ retry ];
}
if (typeof requestUrl === 'string') {
if (/^[A-Z]+ /.test(requestUrl)) {
var requestPathFragments = requestUrl.split(' ');
// Error out if they conflict?
method = method || requestPathFragments.shift();
requestUrl = requestPathFragments.join(' ');
headerObjs.forEach(headersObj => {
if (headersObj) {
Object.keys(headersObj).forEach(headerName => {
const headerValue = headersObj[headerName];
if (typeof headerValue === 'undefined') {
return;
}
headers[headerName.toLowerCase()] = headerValue;
});
}
});
method = method || this.method || 'GET';
if (typeof retry !== 'undefined' && !Array.isArray(retry)) {
retry = [retry];
}
if (Buffer.isBuffer(body)) {
headers['content-length'] = body.length; // Disables chunked encoding for buffered body or strings
} else if (typeof body === 'string') {
headers['content-length'] = Buffer.byteLength(body); // Disables chunked encoding for string body
} else if (typeof body === 'object') {
if (typeof body.pipe === 'function') {
// Hack to prevent the response handling code from discarding the response
body._teepeePipeDue = true;
} else {
body = this.stringifyJsonRequestBody(body);
headers['content-type'] = headers['content-type'] || 'application/json';
headers['content-length'] = Buffer.byteLength(body); // Disables chunked encoding for json body
}
} else if (!body) {
headers['content-length'] = 0; // Disables chunked encoding if there is no body
if (typeof requestUrl === 'string') {
if (/^[A-Z]+ /.test(requestUrl)) {
const requestPathFragments = requestUrl.split(' ');
// Error out if they conflict?
method = method || requestPathFragments.shift();
requestUrl = requestPathFragments.join(' ');
}
}
url = this._addQueryStringToUrl(this.resolveUrl(this.url, requestUrl, options), query);
var auth;
// https://github.com/joyent/node/issues/25353 url.parse() fails if auth contain a colon,
// parse it separately:
url = url.replace(/^([a-z+-]+:\/\/)([^:@/]+(?::[^@/]*?))@/i, function ($0, before, _auth) {
auth = _auth;
return before;
});
method = method || this.method || 'GET';
var urlObj = urlModule.parse(url);
if (Buffer.isBuffer(body)) {
headers['content-length'] = body.length; // Disables chunked encoding for buffered body or strings
} else if (typeof body === 'string') {
headers['content-length'] = Buffer.byteLength(body); // Disables chunked encoding for string body
} else if (typeof body === 'object') {
if (typeof body.pipe === 'function') {
// Hack to prevent the response handling code from discarding the response
body._teepeePipeDue = true;
} else {
body = this.stringifyJsonRequestBody(body);
headers['content-type'] = headers['content-type'] || 'application/json';
headers['content-length'] = Buffer.byteLength(body); // Disables chunked encoding for json body
}
} else if (!body) {
headers['content-length'] = 0; // Disables chunked encoding if there is no body
}
if (!urlObj) {
throw new Error('Invalid url: ' + url);
url = this._addQueryStringToUrl(
this.resolveUrl(this.url, requestUrl, options),
query
);
let auth;
// https://github.com/joyent/node/issues/25353 url.parse() fails if auth contain a colon,
// parse it separately:
url = url.replace(
/^([a-z+-]+:\/\/)([^:@/]+(?::[^@/]*?))@/i,
($0, before, _auth) => {
auth = _auth;
return before;
}
var protocol = urlObj.protocol.replace(/:$/, ''),
host = urlObj.hostname,
port = urlObj.port,
path = urlObj.pathname,
queryString = urlObj.search || '';
);
if (!('host' in headers) && (host || port)) {
headers.host = (host || '') + (port ? ':' + port : '');
// new urlModule.URL does not accept a url without a hostname
// eslint-disable-next-line node/no-deprecated-api
const urlObj = urlModule.parse(url);
if (!urlObj) {
throw new Error(`Invalid url: ${url}`);
}
const protocol = urlObj.protocol.replace(/:$/, '');
const host = urlObj.hostname;
let port = urlObj.port;
const path = urlObj.pathname;
const queryString = urlObj.search || '';
if (!('host' in headers) && (host || port)) {
headers.host = (host || '') + (port ? `:${port}` : '');
}
if (port !== undefined && port !== null) {
port = parseInt(port, 10);
} else if (protocol === 'https') {
port = 443;
} else {
port = 80;
}
if (
typeof auth === 'string' &&
auth.length > 0 &&
!('authorization' in headers)
) {
const authFragments = auth.split(':');
username = username || safeDecodeURIComponent(authFragments.shift());
if (authFragments.length > 0) {
password = safeDecodeURIComponent(authFragments.join(':'));
}
if (typeof port !== 'null') {
port = parseInt(port, 10);
} else if (protocol === 'https') {
port = 443;
} else {
port = 80;
}
if (typeof auth === 'string' && auth.length > 0 && !('authorization' in headers)) {
var authFragments = auth.split(':');
username = username || safeDecodeURIComponent(authFragments.shift());
if (authFragments.length > 0) {
password = safeDecodeURIComponent(authFragments.join(':'));
}
}
}
if (username) {
headers.authorization = 'Basic ' + new Buffer(username + (password ? ':' + password : ''), 'utf-8').toString('base64');
if (username) {
headers.authorization = `Basic ${Buffer.from(
username + (password ? `:${password}` : ''),
'utf-8'
).toString('base64')}`;
}
let requestOptions = {
protocol,
host,
port,
method,
path: path + queryString,
headers,
rejectUnauthorized
};
const agent = this.getAgent(protocol);
if (agent) {
requestOptions.agent = agent;
} else {
['cert', 'key', 'ca'].forEach(function setRequestOptions(key) {
if (this[key]) {
requestOptions[key] = this[key];
}
}, this);
}
let that = this;
let currentRequest;
let currentResponse;
let responseError;
let responseBodyChunks;
const eventEmitter = new EventEmitter();
function disposeRequestOrResponse(obj) {
if (obj) {
obj.removeAllListeners();
obj.on('error', () => {});
}
}
var requestOptions = {
protocol: protocol,
host: host,
port: port,
method: method,
path: path + queryString,
headers: headers,
rejectUnauthorized: rejectUnauthorized
};
function cleanUp() {
responseBodyChunks = null;
disposeRequestOrResponse(currentRequest);
currentRequest = null;
disposeRequestOrResponse(currentResponse);
currentResponse = null;
responseError = undefined;
}
var agent = this.getAgent(protocol);
if (agent) {
requestOptions.agent = agent;
let promise;
eventEmitter.then = function() {
if (cb && !promise) {
throw new Error('You cannot use .then() and a callback at the same time');
} else {
['cert', 'key', 'ca'].forEach(function setRequestOptions(key) {
if (this[key]) {
requestOptions[key] = this[key];
if (!promise) {
promise = new Promise((resolve, reject) => {
if (currentRequest) {
throw new Error(
'.then() must be called in the same tick as the request is initiated'
);
}
cb = (err, response, body) => {
if (err) {
reject(err);
} else {
resolve(response);
}
}, this);
};
});
}
return promise.then.apply(promise, arguments);
}
};
var that = this,
currentRequest,
currentResponse,
responseError,
responseBodyChunks;
eventEmitter.done = false;
var eventEmitter = new EventEmitter();
function disposeRequestOrResponse(obj) {
if (obj) {
obj.removeAllListeners();
obj.on('error', function () {});
}
eventEmitter.abort = () => {
eventEmitter.done = true;
if (currentRequest) {
currentRequest.abort();
cleanUp();
eventEmitter.removeAllListeners();
requestOptions = null;
that = null;
}
};
function cleanUp() {
responseBodyChunks = null;
disposeRequestOrResponse(currentRequest);
currentRequest = null;
disposeRequestOrResponse(currentResponse);
currentResponse = null;
responseError = undefined;
}
eventEmitter.error = err => {
if (!eventEmitter.done) {
eventEmitter.done = true;
var promise;
eventEmitter.then = function () {
if (cb && !promise) {
throw new Error('You cannot use .then() and a callback at the same time');
// if what came up was a plain error convert it to an httpError
if (!err.statusCode) {
if (SocketError.supports(err)) {
err = new SocketError(err);
} else if (DnsError.supports(err)) {
err = new DnsError(err);
} else {
if (!promise) {
promise = new Promise(function (resolve, reject) {
if (currentRequest) {
throw new Error('.then() must be called in the same tick as the request is initiated');
}
cb = function (err, response, body) {
if (err) {
reject(err);
} else {
resolve(response);
}
};
});
}
return promise.then.apply(promise, arguments);
// convert to a 500 internal server error
err = new HttpError[500](err.message);
}
};
}
eventEmitter.done = false;
that.emit('failedRequest', {
url,
requestOptions,
response: currentResponse,
err,
numRetriesLeft
});
if (cb) {
// Could we pass 'response' as an argument to this method always instead, so we don't need the pseudo-global currentResponse variable?
cb(err, currentResponse, currentResponse && currentResponse.body);
} else if (
eventEmitter.listeners('error').length > 0 ||
eventEmitter.listeners('response').length === 0
) {
eventEmitter.emit('error', err);
}
setImmediate(() => {
cleanUp();
eventEmitter.removeAllListeners();
requestOptions = null;
that = null;
});
}
};
eventEmitter.abort = function () {
eventEmitter.done = true;
if (currentRequest) {
currentRequest.abort();
cleanUp();
eventEmitter.removeAllListeners();
requestOptions = null;
that = null;
}
};
eventEmitter.success = response => {
if (!eventEmitter.done) {
eventEmitter.done = true;
that.emit('successfulRequest', {
url,
requestOptions,
response
});
eventEmitter.emit('end');
if (cb) {
cb(null, response, response && response.body);
}
setImmediate(() => {
cleanUp();
eventEmitter.removeAllListeners();
requestOptions = null;
that = null;
});
}
};
eventEmitter.error = function (err) {
if (!eventEmitter.done) {
eventEmitter.done = true;
if (this.preprocessRequestOptions) {
this.preprocessRequestOptions(
requestOptions,
options,
passError(eventEmitter.error, dispatchRequest)
);
} else {
setImmediate(dispatchRequest);
}
// if what came up was a plain error convert it to an httpError
if (!err.statusCode) {
if (SocketError.supports(err)) {
err = new SocketError(err);
} else if (DnsError.supports(err)) {
err = new DnsError(err);
} else {
// convert to a 500 internal server error
err = new HttpError[500](err.message);
}
}
function dispatchRequest() {
if (currentRequest) {
disposeRequestOrResponse(currentRequest);
}
currentRequest = (requestOptions.protocol === 'https'
? https
: http
).request(omit(requestOptions, 'protocol'));
that.emit('request', { requestOptions, url });
if (currentResponse) {
disposeRequestOrResponse(currentResponse);
}
currentResponse = null;
responseError = undefined;
if (eventEmitter.listeners('request').length > 0) {
numRetriesLeft = 0;
eventEmitter.emit('request', currentRequest, requestOptions, url);
}
let requestBody = body;
if (typeof requestBody === 'function') {
requestBody = requestBody();
}
if (requestBody && typeof requestBody.pipe === 'function') {
if (typeof body !== 'function') {
numRetriesLeft = 0;
}
requestBody.pipe(currentRequest);
} else {
currentRequest.end(requestBody);
}
that.emit('failedRequest', { url: url, requestOptions: requestOptions, response: currentResponse, err: err, numRetriesLeft: numRetriesLeft });
if (cb) {
// Could we pass 'response' as an argument to this method always instead, so we don't need the pseudo-global currentResponse variable?
cb(err, currentResponse, currentResponse && currentResponse.body);
} else if (eventEmitter.listeners('error').length > 0 || eventEmitter.listeners('response').length === 0) {
eventEmitter.emit('error', err);
}
setImmediate(function () {
cleanUp();
eventEmitter.removeAllListeners();
requestOptions = null;
that = null;
});
}
};
if (typeof timeout === 'number') {
currentRequest.setTimeout(timeout, () => {
// This callback will be added as a one time listener for the 'timeout' event.
currentRequest.destroy();
cleanUp();
handleRequestError(new SocketError.ETIMEDOUT());
});
}
eventEmitter.success = function (response) {
if (!eventEmitter.done) {
eventEmitter.done = true;
that.emit('successfulRequest', { url: url, requestOptions: requestOptions, response: response });
eventEmitter.emit('end');
if (cb) {
cb(null, response, response && response.body);
}
setImmediate(function () {
cleanUp();
eventEmitter.removeAllListeners();
requestOptions = null;
that = null;
});
}
};
function retryUponError(err) {
cleanUp();
numRetriesLeft -= 1;
setTimeout(() => {
that.emit('retriedRequest', {
requestOptions,
err,
numRetriesLeft,
url
});
dispatchRequest();
}, retryDelayMilliseconds);
}
if (this.preprocessRequestOptions) {
this.preprocessRequestOptions(requestOptions, options, passError(eventEmitter.error, dispatchRequest));
} else {
setImmediate(dispatchRequest);
function handleRequestError(err) {
disposeRequestOrResponse(currentRequest);
if (eventEmitter.done) {
return;
}
// Non-HTTP error (ECONNRESET, ETIMEDOUT, etc.)
// Try again (up to numRetriesLeft times). Warning: This doesn't work when piping into the returned request,
// so please specify numRetriesLeft:0 if you intend to do that.
if (numRetriesLeft > 0) {
return retryUponError(err);
} else {
eventEmitter.error(err);
}
}
function dispatchRequest() {
if (currentRequest) {
disposeRequestOrResponse(currentRequest);
}
currentRequest = (requestOptions.protocol === 'https' ? https : http).request(omit(requestOptions, 'protocol'));
that.emit('request', { requestOptions: requestOptions, url: url });
if (currentResponse) {
disposeRequestOrResponse(currentResponse);
}
currentResponse = null;
responseError = undefined;
if (eventEmitter.listeners('request').length > 0) {
numRetriesLeft = 0;
eventEmitter.emit('request', currentRequest, requestOptions, url);
}
var requestBody = body;
if (typeof requestBody === 'function') {
requestBody = requestBody();
}
if (requestBody && typeof requestBody.pipe === 'function') {
if (typeof body !== 'function') {
numRetriesLeft = 0;
}
requestBody.pipe(currentRequest);
} else {
currentRequest.end(requestBody);
}
currentRequest
.once('error', handleRequestError)
.once('response', function handleResponse(response) {
currentResponse = response;
let hasEnded = false;
if (typeof timeout === 'number') {
currentRequest.setTimeout(timeout, function () {
// This callback will be added as a one time listener for the 'timeout' event.
currentRequest.destroy();
cleanUp();
handleRequestError(new SocketError.ETIMEDOUT());
});
}
response.once('end', () => {
hasEnded = true;
});
function retryUponError(err) {
cleanUp();
numRetriesLeft -= 1;
setTimeout(function () {
that.emit('retriedRequest', { requestOptions: requestOptions, err: err, numRetriesLeft: numRetriesLeft, url: url });
dispatchRequest();
}, retryDelayMilliseconds);
if (eventEmitter.done) {
return;
}
function handleRequestError(err) {
disposeRequestOrResponse(currentRequest);
if (eventEmitter.done) {
return;
}
// Non-HTTP error (ECONNRESET, ETIMEDOUT, etc.)
// Try again (up to numRetriesLeft times). Warning: This doesn't work when piping into the returned request,
// so please specify numRetriesLeft:0 if you intend to do that.
if (numRetriesLeft > 0) {
return retryUponError(err);
function returnSuccessOrError(err) {
err = err || responseError;
if (err) {
eventEmitter.error(err, response);
} else {
if (hasEnded) {
eventEmitter.success(response);
} else {
eventEmitter.error(err);
response.once('end', () => {
eventEmitter.success(response);
});
// Avoid "Cannot switch to old mode now" error when a pipe has been added:
if (
(typeof response._readableState.pipesCount !== 'number' ||
response._readableState.pipesCount === 0) &&
!response._readableState.pipes
) {
response.resume();
}
}
}
}
currentRequest.once('error', handleRequestError).once('response', function handleResponse(response) {
currentResponse = response;
var hasEnded = false;
response.once('end', function () {
hasEnded = true;
});
if (eventEmitter.done) {
return;
function shouldRetryOnErrorStatusCode(statusCode) {
return retry.some(retryEntry => {
if (retryEntry === 'httpError' || retryEntry === statusCode) {
return true;
} else if (
typeof retryEntry === 'string' &&
retryEntry.length === 3 &&
/\d/.test(retryEntry.charAt(0))
) {
const statusCodeString = String(statusCode);
if (
retryEntry.replace(
/x/g,
($0, index) => statusCodeString[index]
) === statusCodeString
) {
return true;
}
}
});
}
function returnSuccessOrError(err) {
err = err || responseError;
if (err) {
eventEmitter.error(err, response);
} else {
if (hasEnded) {
eventEmitter.success(response);
} else {
response.once('end', function () {
eventEmitter.success(response);
});
// Avoid "Cannot switch to old mode now" error when a pipe has been added:
if ((typeof response._readableState.pipesCount !== 'number' || response._readableState.pipesCount === 0) && !response._readableState.pipes) {
response.resume();
}
}
}
}
response.requestOptions = requestOptions;
response.url = url;
response.cacheInfo = { headers: {} };
function shouldRetryOnErrorStatusCode(statusCode) {
return retry.some(function (retryEntry) {
if (retryEntry === 'httpError' || retryEntry === statusCode) {
return true;
} else if (typeof retryEntry === 'string' && retryEntry.length === 3 && /\d/.test(retryEntry.charAt(0))) {
var statusCodeString = String(statusCode);
if (retryEntry.replace(/x/g, function ($0, index) { return statusCodeString[index]; }) === statusCodeString) {
return true;
}
}
});
}
let responseBodyMustBeDisposedUnlessPiped = false;
response.requestOptions = requestOptions;
response.url = url;
response.cacheInfo = { headers: {} };
var responseBodyMustBeDisposedUnlessPiped = false;
if (response.statusCode === 301 || response.statusCode === 302) {
if (numRetriesLeft > 0 && retry.indexOf('selfRedirect') !== -1) {
var redirectTargetUrl = urlModule.resolve(url, response.headers.location);
if (redirectTargetUrl.replace(/#.*$/, '') === url.replace(/#.*$/, '')) {
response.once('error', function () {});
response.resume();
return retryUponError(new SelfRedirectError({ data: { location: response.headers.location }}));
} else {
responseBodyMustBeDisposedUnlessPiped = true;
}
}
} else if (response.statusCode >= 400) {
responseError = new HttpError(response.statusCode);
if (numRetriesLeft > 0 && shouldRetryOnErrorStatusCode(response.statusCode)) {
response.once('error', function () {});
response.resume();
return retryUponError(responseError);
}
} else if (response.statusCode === 304) {
response.cacheInfo.notModified = true;
body = null;
responseBodyMustBeDisposedUnlessPiped = true;
if (response.statusCode === 301 || response.statusCode === 302) {
if (numRetriesLeft > 0 && retry.indexOf('selfRedirect') !== -1) {
const redirectTargetUrl = new urlModule.URL(
response.headers.location,
url
).href;
if (
redirectTargetUrl.replace(/#.*$/, '') === url.replace(/#.*$/, '')
) {
response.once('error', () => {});
response.resume();
return retryUponError(
new SelfRedirectError({
data: { location: response.headers.location }
})
);
} else {
responseBodyMustBeDisposedUnlessPiped = true;
}
['last-modified', 'etag', 'expires', 'cache-control', 'content-type'].forEach(function (headerName) {
if (headerName in response.headers) {
response.cacheInfo.headers[headerName] = response.headers[headerName];
}
});
}
} else if (response.statusCode >= 400) {
responseError = new HttpError(response.statusCode);
if (
numRetriesLeft > 0 &&
shouldRetryOnErrorStatusCode(response.statusCode)
) {
response.once('error', () => {});
response.resume();
return retryUponError(responseError);
}
} else if (response.statusCode === 304) {
response.cacheInfo.notModified = true;
body = null;
responseBodyMustBeDisposedUnlessPiped = true;
}
[
'last-modified',
'etag',
'expires',
'cache-control',
'content-type'
].forEach(headerName => {
if (headerName in response.headers) {
response.cacheInfo.headers[headerName] =
response.headers[headerName];
}
});
eventEmitter.emit('response', response, responseError);
eventEmitter.emit('response', response, responseError);
if (responseError) {
if (!cb) {
eventEmitter.error(responseError);
}
} else {
eventEmitter.emit('success', response);
}
if (responseError) {
if (!cb) {
eventEmitter.error(responseError);
}
} else {
eventEmitter.emit('success', response);
}
var responseBodyMustBeBuffered = eventEmitter.listeners('responseBody').length > 0 || responseError;
let responseBodyMustBeBuffered =
eventEmitter.listeners('responseBody').length > 0 || responseError;
if (cb) {
responseBodyMustBeBuffered = true;
eventEmitter.once('responseBody', function () {
returnSuccessOrError();
});
if (cb) {
responseBodyMustBeBuffered = true;
eventEmitter.once('responseBody', () => {
returnSuccessOrError();
});
// Under these specific circumstances we can retry when the request times out while we're streaming the response:
if (typeof timeout === 'number' && numRetriesLeft > 0) {
currentRequest.removeAllListeners('timeout');
currentRequest.once('timeout', function () {
// Emitted if the socket times out from inactivity. This is only to notify that the socket has been idle. The user must manually close the connection.
eventEmitter.removeAllListeners('responseBody');
currentRequest.destroy();
numRetriesLeft -= 1;
retryUponError(new SocketError.ETIMEDOUT());
});
}
} else {
numRetriesLeft = 0;
if (responseError) {
if (responseBodyMustBeBuffered) {
eventEmitter.once('responseBody', function () {
setImmediate(function () {
returnSuccessOrError();
});
});
} else {
response.once('end', returnSuccessOrError);
// Avoid "Cannot switch to old mode now" error when a pipe has been added:
if ((typeof response._readableState.pipesCount !== 'number' || response._readableState.pipesCount === 0) && !response._readableState.pipes) {
response.resume();
}
}
} else if (!responseBodyMustBeBuffered) {
response.once('end', returnSuccessOrError);
}
}
// Under these specific circumstances we can retry when the request times out while we're streaming the response:
if (typeof timeout === 'number' && numRetriesLeft > 0) {
currentRequest.removeAllListeners('timeout');
currentRequest.once('timeout', () => {
// Emitted if the socket times out from inactivity. This is only to notify that the socket has been idle. The user must manually close the connection.
eventEmitter.removeAllListeners('responseBody');
currentRequest.destroy();
numRetriesLeft -= 1;
retryUponError(new SocketError.ETIMEDOUT());
});
}
} else {
numRetriesLeft = 0;
if (responseError) {
if (responseBodyMustBeBuffered) {
responseBodyChunks = [];
var responseBodyStream = response;
var contentEncoding = response.headers['content-encoding'];
if (contentEncoding === 'gzip' || contentEncoding === 'deflate') {
var decoder = new zlib[contentEncoding === 'gzip' ? 'Gunzip' : 'Inflate']();
decoder.once('error', returnSuccessOrError);
responseBodyStream = responseBodyStream.pipe(decoder);
}
responseBodyStream.on('data', function handleBodyChunk(responseBodyChunk) {
responseBodyChunks.push(responseBodyChunk);
}).once('error', returnSuccessOrError).once('end', function handleEnd() {
disposeRequestOrResponse(currentRequest);
currentRequest = null;
response.body = Buffer.concat(responseBodyChunks);
if (isContentTypeJson(response.headers['content-type']) && response.req.method !== 'HEAD' && autoDecodeJson) {
// 'HEAD' requests have blank response
try {
response.body = JSON.parse(response.body.toString('utf-8'));
} catch (e) {
return eventEmitter.error(new HttpError.BadGateway('Error parsing JSON response body'), response);
}
}
if (responseError) {
responseError.data = response.body;
}
eventEmitter.emit('responseBody', response);
returnSuccessOrError();
responseBodyChunks = null;
response = null;
eventEmitter.once('responseBody', () => {
setImmediate(() => {
returnSuccessOrError();
});
} else if (!response._readableState || (!response._teepeePipeDue && ((typeof response._readableState.pipesCount !== 'number' || response._readableState.pipesCount === 0) && !response._readableState.pipes))) {
});
} else {
response.once('end', returnSuccessOrError);
// Avoid "Cannot switch to old mode now" error when a pipe has been added:
if (
(typeof response._readableState.pipesCount !== 'number' ||
response._readableState.pipesCount === 0) &&
!response._readableState.pipes
) {
response.resume();
if (responseBodyMustBeDisposedUnlessPiped) {
response.once('error', function () {});
}
}
}
});
}
} else if (!responseBodyMustBeBuffered) {
response.once('end', returnSuccessOrError);
}
}
return eventEmitter;
if (responseBodyMustBeBuffered) {
responseBodyChunks = [];
let responseBodyStream = response;
const contentEncoding = response.headers['content-encoding'];
if (contentEncoding === 'gzip' || contentEncoding === 'deflate') {
const decoder = new zlib[
contentEncoding === 'gzip' ? 'Gunzip' : 'Inflate'
]();
decoder.once('error', returnSuccessOrError);
responseBodyStream = responseBodyStream.pipe(decoder);
}
responseBodyStream
.on('data', function handleBodyChunk(responseBodyChunk) {
responseBodyChunks.push(responseBodyChunk);
})
.once('error', returnSuccessOrError)
.once('end', function handleEnd() {
disposeRequestOrResponse(currentRequest);
currentRequest = null;
response.body = Buffer.concat(responseBodyChunks);
if (
isContentTypeJson(response.headers['content-type']) &&
response.req.method !== 'HEAD' &&
autoDecodeJson
) {
// 'HEAD' requests have blank response
try {
response.body = JSON.parse(response.body.toString('utf-8'));
} catch (e) {
return eventEmitter.error(
new HttpError.BadGateway(
'Error parsing JSON response body'
),
response
);
}
}
if (responseError) {
responseError.data = response.body;
}
eventEmitter.emit('responseBody', response);
returnSuccessOrError();
responseBodyChunks = null;
response = null;
});
} else if (
!response._readableState ||
(!response._teepeePipeDue &&
((typeof response._readableState.pipesCount !== 'number' ||
response._readableState.pipesCount === 0) &&
!response._readableState.pipes))
) {
response.resume();
if (responseBodyMustBeDisposedUnlessPiped) {
response.once('error', () => {});
}
}
});
}
return eventEmitter;
};
Teepee.prototype.quit = function () {
// agent.destroy became available in node.js 0.12:
if (this.agentByProtocol) {
Object.keys(this.agentByProtocol).forEach(function (protocol) {
var agent = this.agentByProtocol[protocol];
if (agent.destroy) {
agent.destroy();
}
}, this);
}
Teepee.prototype.quit = function() {
// agent.destroy became available in node.js 0.12:
if (this.agentByProtocol) {
Object.keys(this.agentByProtocol).forEach(function(protocol) {
const agent = this.agentByProtocol[protocol];
if (agent.destroy) {
agent.destroy();
}
}, this);
}
};

@@ -855,45 +1033,56 @@

// Add static + instance shorthand methods:
['get', 'put', 'post', 'delete', 'head'].forEach(function (methodName) {
Teepee[methodName] = function () {
var args = Array.prototype.slice.call(arguments);
if (args[0] && typeof args[0] === 'object') {
args[0] = defaults({
method: methodName
}, args[0]);
} else if (args[1] && typeof args[1] === 'object') {
args[1] = defaults({
method: methodName
}, args[1]);
} else if (typeof args[0] === 'string') {
args[0] = { method: methodName, url: args[0] };
} else {
throw new Error('Teepee.' + methodName + ': First argument must be either an object or a string');
}
return Teepee.apply(this, args);
};
['get', 'put', 'post', 'delete', 'head'].forEach(methodName => {
Teepee[methodName] = function(...args) {
if (args[0] && typeof args[0] === 'object') {
args[0] = defaults(
{
method: methodName
},
args[0]
);
} else if (args[1] && typeof args[1] === 'object') {
args[1] = defaults(
{
method: methodName
},
args[1]
);
} else if (typeof args[0] === 'string') {
args[0] = { method: methodName, url: args[0] };
} else {
throw new Error(
`Teepee.${methodName}: First argument must be either an object or a string`
);
}
return Teepee.apply(this, args);
};
Teepee.prototype[methodName] = function () {
var args = Array.prototype.slice.call(arguments);
if (args.length === 1 && typeof args[0] === 'function') {
args = [
{ method: methodName },
args[0]
];
} else if (args[0] && typeof args[0] === 'object') {
args[0] = defaults({
method: methodName
}, args[0]);
} else if (args[1] && typeof args[1] === 'object') {
args[1] = defaults({
method: methodName
}, args[1]);
} else if (typeof args[0] === 'string') {
args[0] = { method: methodName, url: args[0] };
} else if (args.length === 0) {
args = [ { method: methodName } ];
} else {
throw new Error('Teepee.' + methodName + ': First argument must be either an object or a string');
}
return this.request.apply(this, args);
};
Teepee.prototype[methodName] = function(...args) {
if (args.length === 1 && typeof args[0] === 'function') {
args = [{ method: methodName }, args[0]];
} else if (args[0] && typeof args[0] === 'object') {
args[0] = defaults(
{
method: methodName
},
args[0]
);
} else if (args[1] && typeof args[1] === 'object') {
args[1] = defaults(
{
method: methodName
},
args[1]
);
} else if (typeof args[0] === 'string') {
args[0] = { method: methodName, url: args[0] };
} else if (args.length === 0) {
args = [{ method: methodName }];
} else {
throw new Error(
`Teepee.${methodName}: First argument must be either an object or a string`
);
}
return this.request.apply(this, args);
};
});

@@ -900,0 +1089,0 @@

{
"name": "teepee",
"version": "2.31.2",
"version": "3.0.0",
"description": "Generic HTTP client",

@@ -10,9 +10,8 @@ "main": "lib/Teepee.js",

"scripts": {
"lint": "eslint .",
"test": "mocha && npm run lint",
"travis": "npm test && npm run coverage && (<coverage/lcov.info coveralls || true)",
"coverage": "NODE_ENV=development istanbul cover _mocha -- --reporter dot && echo google-chrome coverage/lcov-report/index.html"
"lint": "eslint . && prettier --check '**/*.js'",
"test": "mocha",
"ci": "npm test && npm run coverage && npm run lint",
"coverage": "NODE_ENV=development nyc --reporter=lcov --reporter=text --all -- npm test && echo google-chrome coverage/lcov-report/index.html"
},
"dependencies": {
"bluebird": "2.9.34",
"createerror": "1.2.0",

@@ -32,12 +31,24 @@ "dnserrors": "2.1.2",

"devDependencies": {
"coveralls": "^2.11.9",
"eslint": "^2.13.1",
"eslint-config-onelint": "^1.1.0",
"httpception": "0.5.1",
"istanbul": "^0.4.3",
"coveralls": "^3.0.6",
"eslint": "^6.3.0",
"eslint-config-prettier": "^6.2.0",
"eslint-config-standard": "^14.1.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-mocha": "^6.1.0",
"eslint-plugin-node": "^10.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"httpception": "^3.0.0",
"mocha": "^3.0.2",
"sinon": "^1.17.5",
"unexpected": "^10.15.1",
"unexpected-sinon": "^10.4.0"
"nyc": "^14.1.1",
"prettier": "^1.18.2",
"sinon": "^7.4.2",
"unexpected": "^11.8.0",
"unexpected-sinon": "^10.11.2"
},
"nyc": {
"include": [
"lib/**"
]
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc