index.js 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.UnsupportedProtocolError = exports.ReadError = exports.TimeoutError = exports.UploadError = exports.CacheError = exports.HTTPError = exports.MaxRedirectsError = exports.RequestError = exports.setNonEnumerableProperties = exports.knownHookEvents = exports.withoutBody = exports.kIsNormalizedAlready = void 0;
  4. const util_1 = require("util");
  5. const stream_1 = require("stream");
  6. const fs_1 = require("fs");
  7. const url_1 = require("url");
  8. const http = require("http");
  9. const http_1 = require("http");
  10. const https = require("https");
  11. const http_timer_1 = require("@szmarczak/http-timer");
  12. const cacheable_lookup_1 = require("cacheable-lookup");
  13. const CacheableRequest = require("cacheable-request");
  14. const decompressResponse = require("decompress-response");
  15. // @ts-expect-error Missing types
  16. const http2wrapper = require("http2-wrapper");
  17. const lowercaseKeys = require("lowercase-keys");
  18. const is_1 = require("@sindresorhus/is");
  19. const get_body_size_1 = require("./utils/get-body-size");
  20. const is_form_data_1 = require("./utils/is-form-data");
  21. const proxy_events_1 = require("./utils/proxy-events");
  22. const timed_out_1 = require("./utils/timed-out");
  23. const url_to_options_1 = require("./utils/url-to-options");
  24. const options_to_url_1 = require("./utils/options-to-url");
  25. const weakable_map_1 = require("./utils/weakable-map");
  26. const get_buffer_1 = require("./utils/get-buffer");
  27. const dns_ip_version_1 = require("./utils/dns-ip-version");
  28. const is_response_ok_1 = require("./utils/is-response-ok");
  29. const deprecation_warning_1 = require("../utils/deprecation-warning");
  30. const normalize_arguments_1 = require("../as-promise/normalize-arguments");
  31. const calculate_retry_delay_1 = require("./calculate-retry-delay");
  32. let globalDnsCache;
  33. const kRequest = Symbol('request');
  34. const kResponse = Symbol('response');
  35. const kResponseSize = Symbol('responseSize');
  36. const kDownloadedSize = Symbol('downloadedSize');
  37. const kBodySize = Symbol('bodySize');
  38. const kUploadedSize = Symbol('uploadedSize');
  39. const kServerResponsesPiped = Symbol('serverResponsesPiped');
  40. const kUnproxyEvents = Symbol('unproxyEvents');
  41. const kIsFromCache = Symbol('isFromCache');
  42. const kCancelTimeouts = Symbol('cancelTimeouts');
  43. const kStartedReading = Symbol('startedReading');
  44. const kStopReading = Symbol('stopReading');
  45. const kTriggerRead = Symbol('triggerRead');
  46. const kBody = Symbol('body');
  47. const kJobs = Symbol('jobs');
  48. const kOriginalResponse = Symbol('originalResponse');
  49. const kRetryTimeout = Symbol('retryTimeout');
  50. exports.kIsNormalizedAlready = Symbol('isNormalizedAlready');
  51. const supportsBrotli = is_1.default.string(process.versions.brotli);
  52. exports.withoutBody = new Set(['GET', 'HEAD']);
  53. exports.knownHookEvents = [
  54. 'init',
  55. 'beforeRequest',
  56. 'beforeRedirect',
  57. 'beforeError',
  58. 'beforeRetry',
  59. // Promise-Only
  60. 'afterResponse'
  61. ];
  62. function validateSearchParameters(searchParameters) {
  63. // eslint-disable-next-line guard-for-in
  64. for (const key in searchParameters) {
  65. const value = searchParameters[key];
  66. if (!is_1.default.string(value) && !is_1.default.number(value) && !is_1.default.boolean(value) && !is_1.default.null_(value) && !is_1.default.undefined(value)) {
  67. throw new TypeError(`The \`searchParams\` value '${String(value)}' must be a string, number, boolean or null`);
  68. }
  69. }
  70. }
  71. function isClientRequest(clientRequest) {
  72. return is_1.default.object(clientRequest) && !('statusCode' in clientRequest);
  73. }
  74. const cacheableStore = new weakable_map_1.default();
  75. const waitForOpenFile = async (file) => new Promise((resolve, reject) => {
  76. const onError = (error) => {
  77. reject(error);
  78. };
  79. // Node.js 12 has incomplete types
  80. if (!file.pending) {
  81. resolve();
  82. }
  83. file.once('error', onError);
  84. file.once('ready', () => {
  85. file.off('error', onError);
  86. resolve();
  87. });
  88. });
  89. const redirectCodes = new Set([300, 301, 302, 303, 304, 307, 308]);
  90. const nonEnumerableProperties = [
  91. 'context',
  92. 'body',
  93. 'json',
  94. 'form'
  95. ];
  96. exports.setNonEnumerableProperties = (sources, to) => {
  97. // Non enumerable properties shall not be merged
  98. const properties = {};
  99. for (const source of sources) {
  100. if (!source) {
  101. continue;
  102. }
  103. for (const name of nonEnumerableProperties) {
  104. if (!(name in source)) {
  105. continue;
  106. }
  107. properties[name] = {
  108. writable: true,
  109. configurable: true,
  110. enumerable: false,
  111. // @ts-expect-error TS doesn't see the check above
  112. value: source[name]
  113. };
  114. }
  115. }
  116. Object.defineProperties(to, properties);
  117. };
  118. /**
  119. An error to be thrown when a request fails.
  120. Contains a `code` property with error class code, like `ECONNREFUSED`.
  121. */
  122. class RequestError extends Error {
  123. constructor(message, error, self) {
  124. var _a, _b;
  125. super(message);
  126. Error.captureStackTrace(this, this.constructor);
  127. this.name = 'RequestError';
  128. this.code = (_a = error.code) !== null && _a !== void 0 ? _a : 'ERR_GOT_REQUEST_ERROR';
  129. if (self instanceof Request) {
  130. Object.defineProperty(this, 'request', {
  131. enumerable: false,
  132. value: self
  133. });
  134. Object.defineProperty(this, 'response', {
  135. enumerable: false,
  136. value: self[kResponse]
  137. });
  138. Object.defineProperty(this, 'options', {
  139. // This fails because of TS 3.7.2 useDefineForClassFields
  140. // Ref: https://github.com/microsoft/TypeScript/issues/34972
  141. enumerable: false,
  142. value: self.options
  143. });
  144. }
  145. else {
  146. Object.defineProperty(this, 'options', {
  147. // This fails because of TS 3.7.2 useDefineForClassFields
  148. // Ref: https://github.com/microsoft/TypeScript/issues/34972
  149. enumerable: false,
  150. value: self
  151. });
  152. }
  153. this.timings = (_b = this.request) === null || _b === void 0 ? void 0 : _b.timings;
  154. // Recover the original stacktrace
  155. if (is_1.default.string(error.stack) && is_1.default.string(this.stack)) {
  156. const indexOfMessage = this.stack.indexOf(this.message) + this.message.length;
  157. const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse();
  158. const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').reverse();
  159. // Remove duplicated traces
  160. while (errorStackTrace.length !== 0 && errorStackTrace[0] === thisStackTrace[0]) {
  161. thisStackTrace.shift();
  162. }
  163. this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.reverse().join('\n')}${errorStackTrace.reverse().join('\n')}`;
  164. }
  165. }
  166. }
  167. exports.RequestError = RequestError;
  168. /**
  169. An error to be thrown when the server redirects you more than ten times.
  170. Includes a `response` property.
  171. */
  172. class MaxRedirectsError extends RequestError {
  173. constructor(request) {
  174. super(`Redirected ${request.options.maxRedirects} times. Aborting.`, {}, request);
  175. this.name = 'MaxRedirectsError';
  176. this.code = 'ERR_TOO_MANY_REDIRECTS';
  177. }
  178. }
  179. exports.MaxRedirectsError = MaxRedirectsError;
  180. /**
  181. An error to be thrown when the server response code is not 2xx nor 3xx if `options.followRedirect` is `true`, but always except for 304.
  182. Includes a `response` property.
  183. */
  184. class HTTPError extends RequestError {
  185. constructor(response) {
  186. super(`Response code ${response.statusCode} (${response.statusMessage})`, {}, response.request);
  187. this.name = 'HTTPError';
  188. this.code = 'ERR_NON_2XX_3XX_RESPONSE';
  189. }
  190. }
  191. exports.HTTPError = HTTPError;
  192. /**
  193. An error to be thrown when a cache method fails.
  194. For example, if the database goes down or there's a filesystem error.
  195. */
  196. class CacheError extends RequestError {
  197. constructor(error, request) {
  198. super(error.message, error, request);
  199. this.name = 'CacheError';
  200. this.code = this.code === 'ERR_GOT_REQUEST_ERROR' ? 'ERR_CACHE_ACCESS' : this.code;
  201. }
  202. }
  203. exports.CacheError = CacheError;
  204. /**
  205. An error to be thrown when the request body is a stream and an error occurs while reading from that stream.
  206. */
  207. class UploadError extends RequestError {
  208. constructor(error, request) {
  209. super(error.message, error, request);
  210. this.name = 'UploadError';
  211. this.code = this.code === 'ERR_GOT_REQUEST_ERROR' ? 'ERR_UPLOAD' : this.code;
  212. }
  213. }
  214. exports.UploadError = UploadError;
  215. /**
  216. An error to be thrown when the request is aborted due to a timeout.
  217. Includes an `event` and `timings` property.
  218. */
  219. class TimeoutError extends RequestError {
  220. constructor(error, timings, request) {
  221. super(error.message, error, request);
  222. this.name = 'TimeoutError';
  223. this.event = error.event;
  224. this.timings = timings;
  225. }
  226. }
  227. exports.TimeoutError = TimeoutError;
  228. /**
  229. An error to be thrown when reading from response stream fails.
  230. */
  231. class ReadError extends RequestError {
  232. constructor(error, request) {
  233. super(error.message, error, request);
  234. this.name = 'ReadError';
  235. this.code = this.code === 'ERR_GOT_REQUEST_ERROR' ? 'ERR_READING_RESPONSE_STREAM' : this.code;
  236. }
  237. }
  238. exports.ReadError = ReadError;
  239. /**
  240. An error to be thrown when given an unsupported protocol.
  241. */
  242. class UnsupportedProtocolError extends RequestError {
  243. constructor(options) {
  244. super(`Unsupported protocol "${options.url.protocol}"`, {}, options);
  245. this.name = 'UnsupportedProtocolError';
  246. this.code = 'ERR_UNSUPPORTED_PROTOCOL';
  247. }
  248. }
  249. exports.UnsupportedProtocolError = UnsupportedProtocolError;
  250. const proxiedRequestEvents = [
  251. 'socket',
  252. 'connect',
  253. 'continue',
  254. 'information',
  255. 'upgrade',
  256. 'timeout'
  257. ];
  258. class Request extends stream_1.Duplex {
  259. constructor(url, options = {}, defaults) {
  260. super({
  261. // This must be false, to enable throwing after destroy
  262. // It is used for retry logic in Promise API
  263. autoDestroy: false,
  264. // It needs to be zero because we're just proxying the data to another stream
  265. highWaterMark: 0
  266. });
  267. this[kDownloadedSize] = 0;
  268. this[kUploadedSize] = 0;
  269. this.requestInitialized = false;
  270. this[kServerResponsesPiped] = new Set();
  271. this.redirects = [];
  272. this[kStopReading] = false;
  273. this[kTriggerRead] = false;
  274. this[kJobs] = [];
  275. this.retryCount = 0;
  276. // TODO: Remove this when targeting Node.js >= 12
  277. this._progressCallbacks = [];
  278. const unlockWrite = () => this._unlockWrite();
  279. const lockWrite = () => this._lockWrite();
  280. this.on('pipe', (source) => {
  281. source.prependListener('data', unlockWrite);
  282. source.on('data', lockWrite);
  283. source.prependListener('end', unlockWrite);
  284. source.on('end', lockWrite);
  285. });
  286. this.on('unpipe', (source) => {
  287. source.off('data', unlockWrite);
  288. source.off('data', lockWrite);
  289. source.off('end', unlockWrite);
  290. source.off('end', lockWrite);
  291. });
  292. this.on('pipe', source => {
  293. if (source instanceof http_1.IncomingMessage) {
  294. this.options.headers = {
  295. ...source.headers,
  296. ...this.options.headers
  297. };
  298. }
  299. });
  300. const { json, body, form } = options;
  301. if (json || body || form) {
  302. this._lockWrite();
  303. }
  304. if (exports.kIsNormalizedAlready in options) {
  305. this.options = options;
  306. }
  307. else {
  308. try {
  309. // @ts-expect-error Common TypeScript bug saying that `this.constructor` is not accessible
  310. this.options = this.constructor.normalizeArguments(url, options, defaults);
  311. }
  312. catch (error) {
  313. // TODO: Move this to `_destroy()`
  314. if (is_1.default.nodeStream(options.body)) {
  315. options.body.destroy();
  316. }
  317. this.destroy(error);
  318. return;
  319. }
  320. }
  321. (async () => {
  322. var _a;
  323. try {
  324. if (this.options.body instanceof fs_1.ReadStream) {
  325. await waitForOpenFile(this.options.body);
  326. }
  327. const { url: normalizedURL } = this.options;
  328. if (!normalizedURL) {
  329. throw new TypeError('Missing `url` property');
  330. }
  331. this.requestUrl = normalizedURL.toString();
  332. decodeURI(this.requestUrl);
  333. await this._finalizeBody();
  334. await this._makeRequest();
  335. if (this.destroyed) {
  336. (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.destroy();
  337. return;
  338. }
  339. // Queued writes etc.
  340. for (const job of this[kJobs]) {
  341. job();
  342. }
  343. // Prevent memory leak
  344. this[kJobs].length = 0;
  345. this.requestInitialized = true;
  346. }
  347. catch (error) {
  348. if (error instanceof RequestError) {
  349. this._beforeError(error);
  350. return;
  351. }
  352. // This is a workaround for https://github.com/nodejs/node/issues/33335
  353. if (!this.destroyed) {
  354. this.destroy(error);
  355. }
  356. }
  357. })();
  358. }
  359. static normalizeArguments(url, options, defaults) {
  360. var _a, _b, _c, _d, _e;
  361. const rawOptions = options;
  362. if (is_1.default.object(url) && !is_1.default.urlInstance(url)) {
  363. options = { ...defaults, ...url, ...options };
  364. }
  365. else {
  366. if (url && options && options.url !== undefined) {
  367. throw new TypeError('The `url` option is mutually exclusive with the `input` argument');
  368. }
  369. options = { ...defaults, ...options };
  370. if (url !== undefined) {
  371. options.url = url;
  372. }
  373. if (is_1.default.urlInstance(options.url)) {
  374. options.url = new url_1.URL(options.url.toString());
  375. }
  376. }
  377. // TODO: Deprecate URL options in Got 12.
  378. // Support extend-specific options
  379. if (options.cache === false) {
  380. options.cache = undefined;
  381. }
  382. if (options.dnsCache === false) {
  383. options.dnsCache = undefined;
  384. }
  385. // Nice type assertions
  386. is_1.assert.any([is_1.default.string, is_1.default.undefined], options.method);
  387. is_1.assert.any([is_1.default.object, is_1.default.undefined], options.headers);
  388. is_1.assert.any([is_1.default.string, is_1.default.urlInstance, is_1.default.undefined], options.prefixUrl);
  389. is_1.assert.any([is_1.default.object, is_1.default.undefined], options.cookieJar);
  390. is_1.assert.any([is_1.default.object, is_1.default.string, is_1.default.undefined], options.searchParams);
  391. is_1.assert.any([is_1.default.object, is_1.default.string, is_1.default.undefined], options.cache);
  392. is_1.assert.any([is_1.default.object, is_1.default.number, is_1.default.undefined], options.timeout);
  393. is_1.assert.any([is_1.default.object, is_1.default.undefined], options.context);
  394. is_1.assert.any([is_1.default.object, is_1.default.undefined], options.hooks);
  395. is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.decompress);
  396. is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.ignoreInvalidCookies);
  397. is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.followRedirect);
  398. is_1.assert.any([is_1.default.number, is_1.default.undefined], options.maxRedirects);
  399. is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.throwHttpErrors);
  400. is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.http2);
  401. is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.allowGetBody);
  402. is_1.assert.any([is_1.default.string, is_1.default.undefined], options.localAddress);
  403. is_1.assert.any([dns_ip_version_1.isDnsLookupIpVersion, is_1.default.undefined], options.dnsLookupIpVersion);
  404. is_1.assert.any([is_1.default.object, is_1.default.undefined], options.https);
  405. is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.rejectUnauthorized);
  406. if (options.https) {
  407. is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.https.rejectUnauthorized);
  408. is_1.assert.any([is_1.default.function_, is_1.default.undefined], options.https.checkServerIdentity);
  409. is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.certificateAuthority);
  410. is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.key);
  411. is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.certificate);
  412. is_1.assert.any([is_1.default.string, is_1.default.undefined], options.https.passphrase);
  413. is_1.assert.any([is_1.default.string, is_1.default.buffer, is_1.default.array, is_1.default.undefined], options.https.pfx);
  414. }
  415. is_1.assert.any([is_1.default.object, is_1.default.undefined], options.cacheOptions);
  416. // `options.method`
  417. if (is_1.default.string(options.method)) {
  418. options.method = options.method.toUpperCase();
  419. }
  420. else {
  421. options.method = 'GET';
  422. }
  423. // `options.headers`
  424. if (options.headers === (defaults === null || defaults === void 0 ? void 0 : defaults.headers)) {
  425. options.headers = { ...options.headers };
  426. }
  427. else {
  428. options.headers = lowercaseKeys({ ...(defaults === null || defaults === void 0 ? void 0 : defaults.headers), ...options.headers });
  429. }
  430. // Disallow legacy `url.Url`
  431. if ('slashes' in options) {
  432. throw new TypeError('The legacy `url.Url` has been deprecated. Use `URL` instead.');
  433. }
  434. // `options.auth`
  435. if ('auth' in options) {
  436. throw new TypeError('Parameter `auth` is deprecated. Use `username` / `password` instead.');
  437. }
  438. // `options.searchParams`
  439. if ('searchParams' in options) {
  440. if (options.searchParams && options.searchParams !== (defaults === null || defaults === void 0 ? void 0 : defaults.searchParams)) {
  441. let searchParameters;
  442. if (is_1.default.string(options.searchParams) || (options.searchParams instanceof url_1.URLSearchParams)) {
  443. searchParameters = new url_1.URLSearchParams(options.searchParams);
  444. }
  445. else {
  446. validateSearchParameters(options.searchParams);
  447. searchParameters = new url_1.URLSearchParams();
  448. // eslint-disable-next-line guard-for-in
  449. for (const key in options.searchParams) {
  450. const value = options.searchParams[key];
  451. if (value === null) {
  452. searchParameters.append(key, '');
  453. }
  454. else if (value !== undefined) {
  455. searchParameters.append(key, value);
  456. }
  457. }
  458. }
  459. // `normalizeArguments()` is also used to merge options
  460. (_a = defaults === null || defaults === void 0 ? void 0 : defaults.searchParams) === null || _a === void 0 ? void 0 : _a.forEach((value, key) => {
  461. // Only use default if one isn't already defined
  462. if (!searchParameters.has(key)) {
  463. searchParameters.append(key, value);
  464. }
  465. });
  466. options.searchParams = searchParameters;
  467. }
  468. }
  469. // `options.username` & `options.password`
  470. options.username = (_b = options.username) !== null && _b !== void 0 ? _b : '';
  471. options.password = (_c = options.password) !== null && _c !== void 0 ? _c : '';
  472. // `options.prefixUrl` & `options.url`
  473. if (is_1.default.undefined(options.prefixUrl)) {
  474. options.prefixUrl = (_d = defaults === null || defaults === void 0 ? void 0 : defaults.prefixUrl) !== null && _d !== void 0 ? _d : '';
  475. }
  476. else {
  477. options.prefixUrl = options.prefixUrl.toString();
  478. if (options.prefixUrl !== '' && !options.prefixUrl.endsWith('/')) {
  479. options.prefixUrl += '/';
  480. }
  481. }
  482. if (is_1.default.string(options.url)) {
  483. if (options.url.startsWith('/')) {
  484. throw new Error('`input` must not start with a slash when using `prefixUrl`');
  485. }
  486. options.url = options_to_url_1.default(options.prefixUrl + options.url, options);
  487. }
  488. else if ((is_1.default.undefined(options.url) && options.prefixUrl !== '') || options.protocol) {
  489. options.url = options_to_url_1.default(options.prefixUrl, options);
  490. }
  491. if (options.url) {
  492. if ('port' in options) {
  493. delete options.port;
  494. }
  495. // Make it possible to change `options.prefixUrl`
  496. let { prefixUrl } = options;
  497. Object.defineProperty(options, 'prefixUrl', {
  498. set: (value) => {
  499. const url = options.url;
  500. if (!url.href.startsWith(value)) {
  501. throw new Error(`Cannot change \`prefixUrl\` from ${prefixUrl} to ${value}: ${url.href}`);
  502. }
  503. options.url = new url_1.URL(value + url.href.slice(prefixUrl.length));
  504. prefixUrl = value;
  505. },
  506. get: () => prefixUrl
  507. });
  508. // Support UNIX sockets
  509. let { protocol } = options.url;
  510. if (protocol === 'unix:') {
  511. protocol = 'http:';
  512. options.url = new url_1.URL(`http://unix${options.url.pathname}${options.url.search}`);
  513. }
  514. // Set search params
  515. if (options.searchParams) {
  516. // eslint-disable-next-line @typescript-eslint/no-base-to-string
  517. options.url.search = options.searchParams.toString();
  518. }
  519. // Protocol check
  520. if (protocol !== 'http:' && protocol !== 'https:') {
  521. throw new UnsupportedProtocolError(options);
  522. }
  523. // Update `username`
  524. if (options.username === '') {
  525. options.username = options.url.username;
  526. }
  527. else {
  528. options.url.username = options.username;
  529. }
  530. // Update `password`
  531. if (options.password === '') {
  532. options.password = options.url.password;
  533. }
  534. else {
  535. options.url.password = options.password;
  536. }
  537. }
  538. // `options.cookieJar`
  539. const { cookieJar } = options;
  540. if (cookieJar) {
  541. let { setCookie, getCookieString } = cookieJar;
  542. is_1.assert.function_(setCookie);
  543. is_1.assert.function_(getCookieString);
  544. /* istanbul ignore next: Horrible `tough-cookie` v3 check */
  545. if (setCookie.length === 4 && getCookieString.length === 0) {
  546. setCookie = util_1.promisify(setCookie.bind(options.cookieJar));
  547. getCookieString = util_1.promisify(getCookieString.bind(options.cookieJar));
  548. options.cookieJar = {
  549. setCookie,
  550. getCookieString: getCookieString
  551. };
  552. }
  553. }
  554. // `options.cache`
  555. const { cache } = options;
  556. if (cache) {
  557. if (!cacheableStore.has(cache)) {
  558. cacheableStore.set(cache, new CacheableRequest(((requestOptions, handler) => {
  559. const result = requestOptions[kRequest](requestOptions, handler);
  560. // TODO: remove this when `cacheable-request` supports async request functions.
  561. if (is_1.default.promise(result)) {
  562. // @ts-expect-error
  563. // We only need to implement the error handler in order to support HTTP2 caching.
  564. // The result will be a promise anyway.
  565. result.once = (event, handler) => {
  566. if (event === 'error') {
  567. result.catch(handler);
  568. }
  569. else if (event === 'abort') {
  570. // The empty catch is needed here in case when
  571. // it rejects before it's `await`ed in `_makeRequest`.
  572. (async () => {
  573. try {
  574. const request = (await result);
  575. request.once('abort', handler);
  576. }
  577. catch (_a) { }
  578. })();
  579. }
  580. else {
  581. /* istanbul ignore next: safety check */
  582. throw new Error(`Unknown HTTP2 promise event: ${event}`);
  583. }
  584. return result;
  585. };
  586. }
  587. return result;
  588. }), cache));
  589. }
  590. }
  591. // `options.cacheOptions`
  592. options.cacheOptions = { ...options.cacheOptions };
  593. // `options.dnsCache`
  594. if (options.dnsCache === true) {
  595. if (!globalDnsCache) {
  596. globalDnsCache = new cacheable_lookup_1.default();
  597. }
  598. options.dnsCache = globalDnsCache;
  599. }
  600. else if (!is_1.default.undefined(options.dnsCache) && !options.dnsCache.lookup) {
  601. throw new TypeError(`Parameter \`dnsCache\` must be a CacheableLookup instance or a boolean, got ${is_1.default(options.dnsCache)}`);
  602. }
  603. // `options.timeout`
  604. if (is_1.default.number(options.timeout)) {
  605. options.timeout = { request: options.timeout };
  606. }
  607. else if (defaults && options.timeout !== defaults.timeout) {
  608. options.timeout = {
  609. ...defaults.timeout,
  610. ...options.timeout
  611. };
  612. }
  613. else {
  614. options.timeout = { ...options.timeout };
  615. }
  616. // `options.context`
  617. if (!options.context) {
  618. options.context = {};
  619. }
  620. // `options.hooks`
  621. const areHooksDefault = options.hooks === (defaults === null || defaults === void 0 ? void 0 : defaults.hooks);
  622. options.hooks = { ...options.hooks };
  623. for (const event of exports.knownHookEvents) {
  624. if (event in options.hooks) {
  625. if (is_1.default.array(options.hooks[event])) {
  626. // See https://github.com/microsoft/TypeScript/issues/31445#issuecomment-576929044
  627. options.hooks[event] = [...options.hooks[event]];
  628. }
  629. else {
  630. throw new TypeError(`Parameter \`${event}\` must be an Array, got ${is_1.default(options.hooks[event])}`);
  631. }
  632. }
  633. else {
  634. options.hooks[event] = [];
  635. }
  636. }
  637. if (defaults && !areHooksDefault) {
  638. for (const event of exports.knownHookEvents) {
  639. const defaultHooks = defaults.hooks[event];
  640. if (defaultHooks.length > 0) {
  641. // See https://github.com/microsoft/TypeScript/issues/31445#issuecomment-576929044
  642. options.hooks[event] = [
  643. ...defaults.hooks[event],
  644. ...options.hooks[event]
  645. ];
  646. }
  647. }
  648. }
  649. // DNS options
  650. if ('family' in options) {
  651. deprecation_warning_1.default('"options.family" was never documented, please use "options.dnsLookupIpVersion"');
  652. }
  653. // HTTPS options
  654. if (defaults === null || defaults === void 0 ? void 0 : defaults.https) {
  655. options.https = { ...defaults.https, ...options.https };
  656. }
  657. if ('rejectUnauthorized' in options) {
  658. deprecation_warning_1.default('"options.rejectUnauthorized" is now deprecated, please use "options.https.rejectUnauthorized"');
  659. }
  660. if ('checkServerIdentity' in options) {
  661. deprecation_warning_1.default('"options.checkServerIdentity" was never documented, please use "options.https.checkServerIdentity"');
  662. }
  663. if ('ca' in options) {
  664. deprecation_warning_1.default('"options.ca" was never documented, please use "options.https.certificateAuthority"');
  665. }
  666. if ('key' in options) {
  667. deprecation_warning_1.default('"options.key" was never documented, please use "options.https.key"');
  668. }
  669. if ('cert' in options) {
  670. deprecation_warning_1.default('"options.cert" was never documented, please use "options.https.certificate"');
  671. }
  672. if ('passphrase' in options) {
  673. deprecation_warning_1.default('"options.passphrase" was never documented, please use "options.https.passphrase"');
  674. }
  675. if ('pfx' in options) {
  676. deprecation_warning_1.default('"options.pfx" was never documented, please use "options.https.pfx"');
  677. }
  678. // Other options
  679. if ('followRedirects' in options) {
  680. throw new TypeError('The `followRedirects` option does not exist. Use `followRedirect` instead.');
  681. }
  682. if (options.agent) {
  683. for (const key in options.agent) {
  684. if (key !== 'http' && key !== 'https' && key !== 'http2') {
  685. throw new TypeError(`Expected the \`options.agent\` properties to be \`http\`, \`https\` or \`http2\`, got \`${key}\``);
  686. }
  687. }
  688. }
  689. options.maxRedirects = (_e = options.maxRedirects) !== null && _e !== void 0 ? _e : 0;
  690. // Set non-enumerable properties
  691. exports.setNonEnumerableProperties([defaults, rawOptions], options);
  692. return normalize_arguments_1.default(options, defaults);
  693. }
  694. _lockWrite() {
  695. const onLockedWrite = () => {
  696. throw new TypeError('The payload has been already provided');
  697. };
  698. this.write = onLockedWrite;
  699. this.end = onLockedWrite;
  700. }
  701. _unlockWrite() {
  702. this.write = super.write;
  703. this.end = super.end;
  704. }
  705. async _finalizeBody() {
  706. const { options } = this;
  707. const { headers } = options;
  708. const isForm = !is_1.default.undefined(options.form);
  709. const isJSON = !is_1.default.undefined(options.json);
  710. const isBody = !is_1.default.undefined(options.body);
  711. const hasPayload = isForm || isJSON || isBody;
  712. const cannotHaveBody = exports.withoutBody.has(options.method) && !(options.method === 'GET' && options.allowGetBody);
  713. this._cannotHaveBody = cannotHaveBody;
  714. if (hasPayload) {
  715. if (cannotHaveBody) {
  716. throw new TypeError(`The \`${options.method}\` method cannot be used with a body`);
  717. }
  718. if ([isBody, isForm, isJSON].filter(isTrue => isTrue).length > 1) {
  719. throw new TypeError('The `body`, `json` and `form` options are mutually exclusive');
  720. }
  721. if (isBody &&
  722. !(options.body instanceof stream_1.Readable) &&
  723. !is_1.default.string(options.body) &&
  724. !is_1.default.buffer(options.body) &&
  725. !is_form_data_1.default(options.body)) {
  726. throw new TypeError('The `body` option must be a stream.Readable, string or Buffer');
  727. }
  728. if (isForm && !is_1.default.object(options.form)) {
  729. throw new TypeError('The `form` option must be an Object');
  730. }
  731. {
  732. // Serialize body
  733. const noContentType = !is_1.default.string(headers['content-type']);
  734. if (isBody) {
  735. // Special case for https://github.com/form-data/form-data
  736. if (is_form_data_1.default(options.body) && noContentType) {
  737. headers['content-type'] = `multipart/form-data; boundary=${options.body.getBoundary()}`;
  738. }
  739. this[kBody] = options.body;
  740. }
  741. else if (isForm) {
  742. if (noContentType) {
  743. headers['content-type'] = 'application/x-www-form-urlencoded';
  744. }
  745. this[kBody] = (new url_1.URLSearchParams(options.form)).toString();
  746. }
  747. else {
  748. if (noContentType) {
  749. headers['content-type'] = 'application/json';
  750. }
  751. this[kBody] = options.stringifyJson(options.json);
  752. }
  753. const uploadBodySize = await get_body_size_1.default(this[kBody], options.headers);
  754. // See https://tools.ietf.org/html/rfc7230#section-3.3.2
  755. // A user agent SHOULD send a Content-Length in a request message when
  756. // no Transfer-Encoding is sent and the request method defines a meaning
  757. // for an enclosed payload body. For example, a Content-Length header
  758. // field is normally sent in a POST request even when the value is 0
  759. // (indicating an empty payload body). A user agent SHOULD NOT send a
  760. // Content-Length header field when the request message does not contain
  761. // a payload body and the method semantics do not anticipate such a
  762. // body.
  763. if (is_1.default.undefined(headers['content-length']) && is_1.default.undefined(headers['transfer-encoding'])) {
  764. if (!cannotHaveBody && !is_1.default.undefined(uploadBodySize)) {
  765. headers['content-length'] = String(uploadBodySize);
  766. }
  767. }
  768. }
  769. }
  770. else if (cannotHaveBody) {
  771. this._lockWrite();
  772. }
  773. else {
  774. this._unlockWrite();
  775. }
  776. this[kBodySize] = Number(headers['content-length']) || undefined;
  777. }
  778. async _onResponseBase(response) {
  779. const { options } = this;
  780. const { url } = options;
  781. this[kOriginalResponse] = response;
  782. if (options.decompress) {
  783. response = decompressResponse(response);
  784. }
  785. const statusCode = response.statusCode;
  786. const typedResponse = response;
  787. typedResponse.statusMessage = typedResponse.statusMessage ? typedResponse.statusMessage : http.STATUS_CODES[statusCode];
  788. typedResponse.url = options.url.toString();
  789. typedResponse.requestUrl = this.requestUrl;
  790. typedResponse.redirectUrls = this.redirects;
  791. typedResponse.request = this;
  792. typedResponse.isFromCache = response.fromCache || false;
  793. typedResponse.ip = this.ip;
  794. typedResponse.retryCount = this.retryCount;
  795. this[kIsFromCache] = typedResponse.isFromCache;
  796. this[kResponseSize] = Number(response.headers['content-length']) || undefined;
  797. this[kResponse] = response;
  798. response.once('end', () => {
  799. this[kResponseSize] = this[kDownloadedSize];
  800. this.emit('downloadProgress', this.downloadProgress);
  801. });
  802. response.once('error', (error) => {
  803. // Force clean-up, because some packages don't do this.
  804. // TODO: Fix decompress-response
  805. response.destroy();
  806. this._beforeError(new ReadError(error, this));
  807. });
  808. response.once('aborted', () => {
  809. this._beforeError(new ReadError({
  810. name: 'Error',
  811. message: 'The server aborted pending request',
  812. code: 'ECONNRESET'
  813. }, this));
  814. });
  815. this.emit('downloadProgress', this.downloadProgress);
  816. const rawCookies = response.headers['set-cookie'];
  817. if (is_1.default.object(options.cookieJar) && rawCookies) {
  818. let promises = rawCookies.map(async (rawCookie) => options.cookieJar.setCookie(rawCookie, url.toString()));
  819. if (options.ignoreInvalidCookies) {
  820. promises = promises.map(async (p) => p.catch(() => { }));
  821. }
  822. try {
  823. await Promise.all(promises);
  824. }
  825. catch (error) {
  826. this._beforeError(error);
  827. return;
  828. }
  829. }
  830. if (options.followRedirect && response.headers.location && redirectCodes.has(statusCode)) {
  831. // We're being redirected, we don't care about the response.
  832. // It'd be best to abort the request, but we can't because
  833. // we would have to sacrifice the TCP connection. We don't want that.
  834. response.resume();
  835. if (this[kRequest]) {
  836. this[kCancelTimeouts]();
  837. // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
  838. delete this[kRequest];
  839. this[kUnproxyEvents]();
  840. }
  841. const shouldBeGet = statusCode === 303 && options.method !== 'GET' && options.method !== 'HEAD';
  842. if (shouldBeGet || !options.methodRewriting) {
  843. // Server responded with "see other", indicating that the resource exists at another location,
  844. // and the client should request it from that location via GET or HEAD.
  845. options.method = 'GET';
  846. if ('body' in options) {
  847. delete options.body;
  848. }
  849. if ('json' in options) {
  850. delete options.json;
  851. }
  852. if ('form' in options) {
  853. delete options.form;
  854. }
  855. this[kBody] = undefined;
  856. delete options.headers['content-length'];
  857. }
  858. if (this.redirects.length >= options.maxRedirects) {
  859. this._beforeError(new MaxRedirectsError(this));
  860. return;
  861. }
  862. try {
  863. // Do not remove. See https://github.com/sindresorhus/got/pull/214
  864. const redirectBuffer = Buffer.from(response.headers.location, 'binary').toString();
  865. // Handles invalid URLs. See https://github.com/sindresorhus/got/issues/604
  866. const redirectUrl = new url_1.URL(redirectBuffer, url);
  867. const redirectString = redirectUrl.toString();
  868. decodeURI(redirectString);
  869. // eslint-disable-next-line no-inner-declarations
  870. function isUnixSocketURL(url) {
  871. return url.protocol === 'unix:' || url.hostname === 'unix';
  872. }
  873. if (!isUnixSocketURL(url) && isUnixSocketURL(redirectUrl)) {
  874. this._beforeError(new RequestError('Cannot redirect to UNIX socket', {}, this));
  875. return;
  876. }
  877. // Redirecting to a different site, clear sensitive data.
  878. if (redirectUrl.hostname !== url.hostname || redirectUrl.port !== url.port) {
  879. if ('host' in options.headers) {
  880. delete options.headers.host;
  881. }
  882. if ('cookie' in options.headers) {
  883. delete options.headers.cookie;
  884. }
  885. if ('authorization' in options.headers) {
  886. delete options.headers.authorization;
  887. }
  888. if (options.username || options.password) {
  889. options.username = '';
  890. options.password = '';
  891. }
  892. }
  893. else {
  894. redirectUrl.username = options.username;
  895. redirectUrl.password = options.password;
  896. }
  897. this.redirects.push(redirectString);
  898. options.url = redirectUrl;
  899. for (const hook of options.hooks.beforeRedirect) {
  900. // eslint-disable-next-line no-await-in-loop
  901. await hook(options, typedResponse);
  902. }
  903. this.emit('redirect', typedResponse, options);
  904. await this._makeRequest();
  905. }
  906. catch (error) {
  907. this._beforeError(error);
  908. return;
  909. }
  910. return;
  911. }
  912. if (options.isStream && options.throwHttpErrors && !is_response_ok_1.isResponseOk(typedResponse)) {
  913. this._beforeError(new HTTPError(typedResponse));
  914. return;
  915. }
  916. response.on('readable', () => {
  917. if (this[kTriggerRead]) {
  918. this._read();
  919. }
  920. });
  921. this.on('resume', () => {
  922. response.resume();
  923. });
  924. this.on('pause', () => {
  925. response.pause();
  926. });
  927. response.once('end', () => {
  928. this.push(null);
  929. });
  930. this.emit('response', response);
  931. for (const destination of this[kServerResponsesPiped]) {
  932. if (destination.headersSent) {
  933. continue;
  934. }
  935. // eslint-disable-next-line guard-for-in
  936. for (const key in response.headers) {
  937. const isAllowed = options.decompress ? key !== 'content-encoding' : true;
  938. const value = response.headers[key];
  939. if (isAllowed) {
  940. destination.setHeader(key, value);
  941. }
  942. }
  943. destination.statusCode = statusCode;
  944. }
  945. }
  946. async _onResponse(response) {
  947. try {
  948. await this._onResponseBase(response);
  949. }
  950. catch (error) {
  951. /* istanbul ignore next: better safe than sorry */
  952. this._beforeError(error);
  953. }
  954. }
  955. _onRequest(request) {
  956. const { options } = this;
  957. const { timeout, url } = options;
  958. http_timer_1.default(request);
  959. this[kCancelTimeouts] = timed_out_1.default(request, timeout, url);
  960. const responseEventName = options.cache ? 'cacheableResponse' : 'response';
  961. request.once(responseEventName, (response) => {
  962. void this._onResponse(response);
  963. });
  964. request.once('error', (error) => {
  965. var _a;
  966. // Force clean-up, because some packages (e.g. nock) don't do this.
  967. request.destroy();
  968. // Node.js <= 12.18.2 mistakenly emits the response `end` first.
  969. (_a = request.res) === null || _a === void 0 ? void 0 : _a.removeAllListeners('end');
  970. error = error instanceof timed_out_1.TimeoutError ? new TimeoutError(error, this.timings, this) : new RequestError(error.message, error, this);
  971. this._beforeError(error);
  972. });
  973. this[kUnproxyEvents] = proxy_events_1.default(request, this, proxiedRequestEvents);
  974. this[kRequest] = request;
  975. this.emit('uploadProgress', this.uploadProgress);
  976. // Send body
  977. const body = this[kBody];
  978. const currentRequest = this.redirects.length === 0 ? this : request;
  979. if (is_1.default.nodeStream(body)) {
  980. body.pipe(currentRequest);
  981. body.once('error', (error) => {
  982. this._beforeError(new UploadError(error, this));
  983. });
  984. }
  985. else {
  986. this._unlockWrite();
  987. if (!is_1.default.undefined(body)) {
  988. this._writeRequest(body, undefined, () => { });
  989. currentRequest.end();
  990. this._lockWrite();
  991. }
  992. else if (this._cannotHaveBody || this._noPipe) {
  993. currentRequest.end();
  994. this._lockWrite();
  995. }
  996. }
  997. this.emit('request', request);
  998. }
  999. async _createCacheableRequest(url, options) {
  1000. return new Promise((resolve, reject) => {
  1001. // TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed
  1002. Object.assign(options, url_to_options_1.default(url));
  1003. // `http-cache-semantics` checks this
  1004. // TODO: Fix this ignore.
  1005. // @ts-expect-error
  1006. delete options.url;
  1007. let request;
  1008. // This is ugly
  1009. const cacheRequest = cacheableStore.get(options.cache)(options, async (response) => {
  1010. // TODO: Fix `cacheable-response`
  1011. response._readableState.autoDestroy = false;
  1012. if (request) {
  1013. (await request).emit('cacheableResponse', response);
  1014. }
  1015. resolve(response);
  1016. });
  1017. // Restore options
  1018. options.url = url;
  1019. cacheRequest.once('error', reject);
  1020. cacheRequest.once('request', async (requestOrPromise) => {
  1021. request = requestOrPromise;
  1022. resolve(request);
  1023. });
  1024. });
  1025. }
  1026. async _makeRequest() {
  1027. var _a, _b, _c, _d, _e;
  1028. const { options } = this;
  1029. const { headers } = options;
  1030. for (const key in headers) {
  1031. if (is_1.default.undefined(headers[key])) {
  1032. // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
  1033. delete headers[key];
  1034. }
  1035. else if (is_1.default.null_(headers[key])) {
  1036. throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`);
  1037. }
  1038. }
  1039. if (options.decompress && is_1.default.undefined(headers['accept-encoding'])) {
  1040. headers['accept-encoding'] = supportsBrotli ? 'gzip, deflate, br' : 'gzip, deflate';
  1041. }
  1042. // Set cookies
  1043. if (options.cookieJar) {
  1044. const cookieString = await options.cookieJar.getCookieString(options.url.toString());
  1045. if (is_1.default.nonEmptyString(cookieString)) {
  1046. options.headers.cookie = cookieString;
  1047. }
  1048. }
  1049. for (const hook of options.hooks.beforeRequest) {
  1050. // eslint-disable-next-line no-await-in-loop
  1051. const result = await hook(options);
  1052. if (!is_1.default.undefined(result)) {
  1053. // @ts-expect-error Skip the type mismatch to support abstract responses
  1054. options.request = () => result;
  1055. break;
  1056. }
  1057. }
  1058. if (options.body && this[kBody] !== options.body) {
  1059. this[kBody] = options.body;
  1060. }
  1061. const { agent, request, timeout, url } = options;
  1062. if (options.dnsCache && !('lookup' in options)) {
  1063. options.lookup = options.dnsCache.lookup;
  1064. }
  1065. // UNIX sockets
  1066. if (url.hostname === 'unix') {
  1067. const matches = /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`);
  1068. if (matches === null || matches === void 0 ? void 0 : matches.groups) {
  1069. const { socketPath, path } = matches.groups;
  1070. Object.assign(options, {
  1071. socketPath,
  1072. path,
  1073. host: ''
  1074. });
  1075. }
  1076. }
  1077. const isHttps = url.protocol === 'https:';
  1078. // Fallback function
  1079. let fallbackFn;
  1080. if (options.http2) {
  1081. fallbackFn = http2wrapper.auto;
  1082. }
  1083. else {
  1084. fallbackFn = isHttps ? https.request : http.request;
  1085. }
  1086. const realFn = (_a = options.request) !== null && _a !== void 0 ? _a : fallbackFn;
  1087. // Cache support
  1088. const fn = options.cache ? this._createCacheableRequest : realFn;
  1089. // Pass an agent directly when HTTP2 is disabled
  1090. if (agent && !options.http2) {
  1091. options.agent = agent[isHttps ? 'https' : 'http'];
  1092. }
  1093. // Prepare plain HTTP request options
  1094. options[kRequest] = realFn;
  1095. delete options.request;
  1096. // TODO: Fix this ignore.
  1097. // @ts-expect-error
  1098. delete options.timeout;
  1099. const requestOptions = options;
  1100. requestOptions.shared = (_b = options.cacheOptions) === null || _b === void 0 ? void 0 : _b.shared;
  1101. requestOptions.cacheHeuristic = (_c = options.cacheOptions) === null || _c === void 0 ? void 0 : _c.cacheHeuristic;
  1102. requestOptions.immutableMinTimeToLive = (_d = options.cacheOptions) === null || _d === void 0 ? void 0 : _d.immutableMinTimeToLive;
  1103. requestOptions.ignoreCargoCult = (_e = options.cacheOptions) === null || _e === void 0 ? void 0 : _e.ignoreCargoCult;
  1104. // If `dnsLookupIpVersion` is not present do not override `family`
  1105. if (options.dnsLookupIpVersion !== undefined) {
  1106. try {
  1107. requestOptions.family = dns_ip_version_1.dnsLookupIpVersionToFamily(options.dnsLookupIpVersion);
  1108. }
  1109. catch (_f) {
  1110. throw new Error('Invalid `dnsLookupIpVersion` option value');
  1111. }
  1112. }
  1113. // HTTPS options remapping
  1114. if (options.https) {
  1115. if ('rejectUnauthorized' in options.https) {
  1116. requestOptions.rejectUnauthorized = options.https.rejectUnauthorized;
  1117. }
  1118. if (options.https.checkServerIdentity) {
  1119. requestOptions.checkServerIdentity = options.https.checkServerIdentity;
  1120. }
  1121. if (options.https.certificateAuthority) {
  1122. requestOptions.ca = options.https.certificateAuthority;
  1123. }
  1124. if (options.https.certificate) {
  1125. requestOptions.cert = options.https.certificate;
  1126. }
  1127. if (options.https.key) {
  1128. requestOptions.key = options.https.key;
  1129. }
  1130. if (options.https.passphrase) {
  1131. requestOptions.passphrase = options.https.passphrase;
  1132. }
  1133. if (options.https.pfx) {
  1134. requestOptions.pfx = options.https.pfx;
  1135. }
  1136. }
  1137. try {
  1138. let requestOrResponse = await fn(url, requestOptions);
  1139. if (is_1.default.undefined(requestOrResponse)) {
  1140. requestOrResponse = fallbackFn(url, requestOptions);
  1141. }
  1142. // Restore options
  1143. options.request = request;
  1144. options.timeout = timeout;
  1145. options.agent = agent;
  1146. // HTTPS options restore
  1147. if (options.https) {
  1148. if ('rejectUnauthorized' in options.https) {
  1149. delete requestOptions.rejectUnauthorized;
  1150. }
  1151. if (options.https.checkServerIdentity) {
  1152. // @ts-expect-error - This one will be removed when we remove the alias.
  1153. delete requestOptions.checkServerIdentity;
  1154. }
  1155. if (options.https.certificateAuthority) {
  1156. delete requestOptions.ca;
  1157. }
  1158. if (options.https.certificate) {
  1159. delete requestOptions.cert;
  1160. }
  1161. if (options.https.key) {
  1162. delete requestOptions.key;
  1163. }
  1164. if (options.https.passphrase) {
  1165. delete requestOptions.passphrase;
  1166. }
  1167. if (options.https.pfx) {
  1168. delete requestOptions.pfx;
  1169. }
  1170. }
  1171. if (isClientRequest(requestOrResponse)) {
  1172. this._onRequest(requestOrResponse);
  1173. // Emit the response after the stream has been ended
  1174. }
  1175. else if (this.writable) {
  1176. this.once('finish', () => {
  1177. void this._onResponse(requestOrResponse);
  1178. });
  1179. this._unlockWrite();
  1180. this.end();
  1181. this._lockWrite();
  1182. }
  1183. else {
  1184. void this._onResponse(requestOrResponse);
  1185. }
  1186. }
  1187. catch (error) {
  1188. if (error instanceof CacheableRequest.CacheError) {
  1189. throw new CacheError(error, this);
  1190. }
  1191. throw new RequestError(error.message, error, this);
  1192. }
  1193. }
  1194. async _error(error) {
  1195. try {
  1196. for (const hook of this.options.hooks.beforeError) {
  1197. // eslint-disable-next-line no-await-in-loop
  1198. error = await hook(error);
  1199. }
  1200. }
  1201. catch (error_) {
  1202. error = new RequestError(error_.message, error_, this);
  1203. }
  1204. this.destroy(error);
  1205. }
  1206. _beforeError(error) {
  1207. if (this[kStopReading]) {
  1208. return;
  1209. }
  1210. const { options } = this;
  1211. const retryCount = this.retryCount + 1;
  1212. this[kStopReading] = true;
  1213. if (!(error instanceof RequestError)) {
  1214. error = new RequestError(error.message, error, this);
  1215. }
  1216. const typedError = error;
  1217. const { response } = typedError;
  1218. void (async () => {
  1219. if (response && !response.body) {
  1220. response.setEncoding(this._readableState.encoding);
  1221. try {
  1222. response.rawBody = await get_buffer_1.default(response);
  1223. response.body = response.rawBody.toString();
  1224. }
  1225. catch (_a) { }
  1226. }
  1227. if (this.listenerCount('retry') !== 0) {
  1228. let backoff;
  1229. try {
  1230. let retryAfter;
  1231. if (response && 'retry-after' in response.headers) {
  1232. retryAfter = Number(response.headers['retry-after']);
  1233. if (Number.isNaN(retryAfter)) {
  1234. retryAfter = Date.parse(response.headers['retry-after']) - Date.now();
  1235. if (retryAfter <= 0) {
  1236. retryAfter = 1;
  1237. }
  1238. }
  1239. else {
  1240. retryAfter *= 1000;
  1241. }
  1242. }
  1243. backoff = await options.retry.calculateDelay({
  1244. attemptCount: retryCount,
  1245. retryOptions: options.retry,
  1246. error: typedError,
  1247. retryAfter,
  1248. computedValue: calculate_retry_delay_1.default({
  1249. attemptCount: retryCount,
  1250. retryOptions: options.retry,
  1251. error: typedError,
  1252. retryAfter,
  1253. computedValue: 0
  1254. })
  1255. });
  1256. }
  1257. catch (error_) {
  1258. void this._error(new RequestError(error_.message, error_, this));
  1259. return;
  1260. }
  1261. if (backoff) {
  1262. const retry = async () => {
  1263. try {
  1264. for (const hook of this.options.hooks.beforeRetry) {
  1265. // eslint-disable-next-line no-await-in-loop
  1266. await hook(this.options, typedError, retryCount);
  1267. }
  1268. }
  1269. catch (error_) {
  1270. void this._error(new RequestError(error_.message, error, this));
  1271. return;
  1272. }
  1273. // Something forced us to abort the retry
  1274. if (this.destroyed) {
  1275. return;
  1276. }
  1277. this.destroy();
  1278. this.emit('retry', retryCount, error);
  1279. };
  1280. this[kRetryTimeout] = setTimeout(retry, backoff);
  1281. return;
  1282. }
  1283. }
  1284. void this._error(typedError);
  1285. })();
  1286. }
  1287. _read() {
  1288. this[kTriggerRead] = true;
  1289. const response = this[kResponse];
  1290. if (response && !this[kStopReading]) {
  1291. // We cannot put this in the `if` above
  1292. // because `.read()` also triggers the `end` event
  1293. if (response.readableLength) {
  1294. this[kTriggerRead] = false;
  1295. }
  1296. let data;
  1297. while ((data = response.read()) !== null) {
  1298. this[kDownloadedSize] += data.length;
  1299. this[kStartedReading] = true;
  1300. const progress = this.downloadProgress;
  1301. if (progress.percent < 1) {
  1302. this.emit('downloadProgress', progress);
  1303. }
  1304. this.push(data);
  1305. }
  1306. }
  1307. }
  1308. // Node.js 12 has incorrect types, so the encoding must be a string
  1309. _write(chunk, encoding, callback) {
  1310. const write = () => {
  1311. this._writeRequest(chunk, encoding, callback);
  1312. };
  1313. if (this.requestInitialized) {
  1314. write();
  1315. }
  1316. else {
  1317. this[kJobs].push(write);
  1318. }
  1319. }
  1320. _writeRequest(chunk, encoding, callback) {
  1321. if (this[kRequest].destroyed) {
  1322. // Probably the `ClientRequest` instance will throw
  1323. return;
  1324. }
  1325. this._progressCallbacks.push(() => {
  1326. this[kUploadedSize] += Buffer.byteLength(chunk, encoding);
  1327. const progress = this.uploadProgress;
  1328. if (progress.percent < 1) {
  1329. this.emit('uploadProgress', progress);
  1330. }
  1331. });
  1332. // TODO: What happens if it's from cache? Then this[kRequest] won't be defined.
  1333. this[kRequest].write(chunk, encoding, (error) => {
  1334. if (!error && this._progressCallbacks.length > 0) {
  1335. this._progressCallbacks.shift()();
  1336. }
  1337. callback(error);
  1338. });
  1339. }
  1340. _final(callback) {
  1341. const endRequest = () => {
  1342. // FIX: Node.js 10 calls the write callback AFTER the end callback!
  1343. while (this._progressCallbacks.length !== 0) {
  1344. this._progressCallbacks.shift()();
  1345. }
  1346. // We need to check if `this[kRequest]` is present,
  1347. // because it isn't when we use cache.
  1348. if (!(kRequest in this)) {
  1349. callback();
  1350. return;
  1351. }
  1352. if (this[kRequest].destroyed) {
  1353. callback();
  1354. return;
  1355. }
  1356. this[kRequest].end((error) => {
  1357. if (!error) {
  1358. this[kBodySize] = this[kUploadedSize];
  1359. this.emit('uploadProgress', this.uploadProgress);
  1360. this[kRequest].emit('upload-complete');
  1361. }
  1362. callback(error);
  1363. });
  1364. };
  1365. if (this.requestInitialized) {
  1366. endRequest();
  1367. }
  1368. else {
  1369. this[kJobs].push(endRequest);
  1370. }
  1371. }
  1372. _destroy(error, callback) {
  1373. var _a;
  1374. this[kStopReading] = true;
  1375. // Prevent further retries
  1376. clearTimeout(this[kRetryTimeout]);
  1377. if (kRequest in this) {
  1378. this[kCancelTimeouts]();
  1379. // TODO: Remove the next `if` when these get fixed:
  1380. // - https://github.com/nodejs/node/issues/32851
  1381. if (!((_a = this[kResponse]) === null || _a === void 0 ? void 0 : _a.complete)) {
  1382. this[kRequest].destroy();
  1383. }
  1384. }
  1385. if (error !== null && !is_1.default.undefined(error) && !(error instanceof RequestError)) {
  1386. error = new RequestError(error.message, error, this);
  1387. }
  1388. callback(error);
  1389. }
  1390. get _isAboutToError() {
  1391. return this[kStopReading];
  1392. }
  1393. /**
  1394. The remote IP address.
  1395. */
  1396. get ip() {
  1397. var _a;
  1398. return (_a = this.socket) === null || _a === void 0 ? void 0 : _a.remoteAddress;
  1399. }
  1400. /**
  1401. Indicates whether the request has been aborted or not.
  1402. */
  1403. get aborted() {
  1404. var _a, _b, _c;
  1405. return ((_b = (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.destroyed) !== null && _b !== void 0 ? _b : this.destroyed) && !((_c = this[kOriginalResponse]) === null || _c === void 0 ? void 0 : _c.complete);
  1406. }
  1407. get socket() {
  1408. var _a, _b;
  1409. return (_b = (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket) !== null && _b !== void 0 ? _b : undefined;
  1410. }
  1411. /**
  1412. Progress event for downloading (receiving a response).
  1413. */
  1414. get downloadProgress() {
  1415. let percent;
  1416. if (this[kResponseSize]) {
  1417. percent = this[kDownloadedSize] / this[kResponseSize];
  1418. }
  1419. else if (this[kResponseSize] === this[kDownloadedSize]) {
  1420. percent = 1;
  1421. }
  1422. else {
  1423. percent = 0;
  1424. }
  1425. return {
  1426. percent,
  1427. transferred: this[kDownloadedSize],
  1428. total: this[kResponseSize]
  1429. };
  1430. }
  1431. /**
  1432. Progress event for uploading (sending a request).
  1433. */
  1434. get uploadProgress() {
  1435. let percent;
  1436. if (this[kBodySize]) {
  1437. percent = this[kUploadedSize] / this[kBodySize];
  1438. }
  1439. else if (this[kBodySize] === this[kUploadedSize]) {
  1440. percent = 1;
  1441. }
  1442. else {
  1443. percent = 0;
  1444. }
  1445. return {
  1446. percent,
  1447. transferred: this[kUploadedSize],
  1448. total: this[kBodySize]
  1449. };
  1450. }
  1451. /**
  1452. The object contains the following properties:
  1453. - `start` - Time when the request started.
  1454. - `socket` - Time when a socket was assigned to the request.
  1455. - `lookup` - Time when the DNS lookup finished.
  1456. - `connect` - Time when the socket successfully connected.
  1457. - `secureConnect` - Time when the socket securely connected.
  1458. - `upload` - Time when the request finished uploading.
  1459. - `response` - Time when the request fired `response` event.
  1460. - `end` - Time when the response fired `end` event.
  1461. - `error` - Time when the request fired `error` event.
  1462. - `abort` - Time when the request fired `abort` event.
  1463. - `phases`
  1464. - `wait` - `timings.socket - timings.start`
  1465. - `dns` - `timings.lookup - timings.socket`
  1466. - `tcp` - `timings.connect - timings.lookup`
  1467. - `tls` - `timings.secureConnect - timings.connect`
  1468. - `request` - `timings.upload - (timings.secureConnect || timings.connect)`
  1469. - `firstByte` - `timings.response - timings.upload`
  1470. - `download` - `timings.end - timings.response`
  1471. - `total` - `(timings.end || timings.error || timings.abort) - timings.start`
  1472. If something has not been measured yet, it will be `undefined`.
  1473. __Note__: The time is a `number` representing the milliseconds elapsed since the UNIX epoch.
  1474. */
  1475. get timings() {
  1476. var _a;
  1477. return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.timings;
  1478. }
  1479. /**
  1480. Whether the response was retrieved from the cache.
  1481. */
  1482. get isFromCache() {
  1483. return this[kIsFromCache];
  1484. }
  1485. pipe(destination, options) {
  1486. if (this[kStartedReading]) {
  1487. throw new Error('Failed to pipe. The response has been emitted already.');
  1488. }
  1489. if (destination instanceof http_1.ServerResponse) {
  1490. this[kServerResponsesPiped].add(destination);
  1491. }
  1492. return super.pipe(destination, options);
  1493. }
  1494. unpipe(destination) {
  1495. if (destination instanceof http_1.ServerResponse) {
  1496. this[kServerResponsesPiped].delete(destination);
  1497. }
  1498. super.unpipe(destination);
  1499. return this;
  1500. }
  1501. }
  1502. exports.default = Request;