@e-mc/request 0.9.9 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
2
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
3
3
  const path = require("path");
4
4
  const fs = require("fs");
5
+ const crypto = require("crypto");
5
6
  const child_process = require("child_process");
6
7
  const http = require("http");
7
8
  const https = require("https");
@@ -15,16 +16,17 @@ const combined = require("combined-stream");
15
16
  const pm = require("picomatch");
16
17
  const yaml = require("js-yaml");
17
18
  const which = require("which");
18
- const types_1 = require("@e-mc/types");
19
19
  const module_1 = require("@e-mc/module");
20
- const host_1 = require("@e-mc/request/http/host");
20
+ const types_1 = require("@e-mc/types");
21
21
  const util_1 = require("@e-mc/request/util");
22
+ const host_1 = require("@e-mc/request/http/host");
22
23
  const kSession = Symbol('session');
23
24
  const kHttpVersion = Symbol('httpVersion');
24
25
  const kIpVersion = Symbol('ipVersion');
25
26
  const kAgentTimeout = Symbol('agentTimeout');
26
27
  const kHeaders = Symbol('headers');
27
28
  const kCerts = Symbol('certs');
29
+ const kBaseURL = Symbol('baseURL');
28
30
  const kDownloading = Symbol('downloading');
29
31
  const kSingleton = Symbol('singleton');
30
32
  const kHostInfo = Symbol('hostInfo');
@@ -33,8 +35,9 @@ const kPendingDns = Symbol('pendingDns');
33
35
  const kConnectHttp = Symbol('connectHttp');
34
36
  const kStatusOn = Symbol('statusOn');
35
37
  const kHeadersOn = Symbol('headersOn');
36
- const PLATFORM_WIN32 = process.platform === 'win32';
37
- const SUPPORT_NODEJS20 = module_1.supported(20);
38
+ const SUPPORTED_NODE20 = (0, types_1.supported)(20);
39
+ const REGEXP_PEMCERT = /^-{3,}[ \t]*BEGIN[ \t].+\n-{3,}[ \t]*END[ \t][^-]+-{3,}$/s;
40
+ const REGEXP_GLOBWITHIN = /\\\?|(?:(?<!\\)(?:\*|\[!?[^!\]]+\]|\{(?:[^,]+,)+[^}]+\}|[!?+*@]\((?:[^|]+\|)*[^)]+\)|\?.*\?|\?$))/;
38
41
  const HTTP = {
39
42
  HOST: {},
40
43
  HEADERS: {},
@@ -52,13 +55,14 @@ const DNS = {
52
55
  FAMILY: 0
53
56
  };
54
57
  const ARIA2 = {
55
- BIN: which.sync(PLATFORM_WIN32 ? 'aria2c.exe' : 'aria2c', { nothrow: true }) || '',
58
+ BIN: which.sync(module_1.PLATFORM_WIN32 ? 'aria2c.exe' : 'aria2c', { nothrow: true }) || '',
56
59
  EXEC_UID: undefined,
57
60
  EXEC_GID: undefined,
58
61
  PID_TIMER: null,
59
62
  PID_QUEUE: [],
60
63
  UPDATE_STATUS: 0,
61
64
  UPDATE_BROADCAST_ONLY: false,
65
+ CHECK_INTEGRITY: false,
62
66
  BT_STOP_TIMEOUT: 60,
63
67
  BT_TRACKER_CONNECT_TIMEOUT: 30,
64
68
  BT_TRACKER_TIMEOUT: 60,
@@ -118,15 +122,6 @@ function setDnsCache(hostname, value, expires) {
118
122
  }
119
123
  }
120
124
  }
121
- function isConnectionTimeout(err) {
122
- switch (err instanceof Error && err.code) {
123
- case 'ETIMEDOUT':
124
- case 'ECONNRESET':
125
- return true;
126
- default:
127
- return false;
128
- }
129
- }
130
125
  function setOutgoingHeaders(output, headers) {
131
126
  for (const href in headers) {
132
127
  output[href] = (0, util_1.normalizeHeaders)(headers[href]);
@@ -134,18 +129,17 @@ function setOutgoingHeaders(output, headers) {
134
129
  }
135
130
  function getProxySettings(request, agentTimeout) {
136
131
  const proxy = request.proxy;
137
- if (proxy?.address && proxy.port) {
138
- const port = (0, util_1.asInt)(proxy.port);
139
- const address = (!module_1.isURL(proxy.address) ? port === 80 ? 'http://' : 'https://' : '') + proxy.address;
132
+ if (proxy && (proxy.origin || proxy.address && proxy.port)) {
133
+ const origin = proxy.origin || ((!module_1.isURL(proxy.address) ? (0, util_1.asInt)(proxy.port) === 80 ? 'http://' : 'https://' : '') + proxy.address + ':' + proxy.port);
140
134
  try {
141
- let host = new URL(address + ':' + port), include, exclude;
135
+ let host = new URL(origin), include, exclude;
142
136
  if (proxy.username) {
143
137
  host = new URL(host.protocol + '//' + (0, util_1.getBasicAuth)(proxy.username, proxy.password) + host.host);
144
138
  }
145
139
  if ((0, types_1.isArray)(proxy.include)) {
146
140
  include = proxy.include;
147
141
  }
148
- else if ((0, types_1.isArray)(proxy.exclude)) {
142
+ if ((0, types_1.isArray)(proxy.exclude)) {
149
143
  exclude = proxy.exclude;
150
144
  }
151
145
  return { host, include, exclude, keepAlive: proxy.keep_alive, agentTimeout };
@@ -156,14 +150,18 @@ function getProxySettings(request, agentTimeout) {
156
150
  return null;
157
151
  }
158
152
  function closeTorrent(pid) {
159
- const index = ARIA2.PID_QUEUE.findIndex(value => pid === value[0]);
160
- if (index !== -1) {
161
- ARIA2.PID_QUEUE.splice(index, 1);
153
+ if (typeof pid === 'number') {
154
+ const index = ARIA2.PID_QUEUE.findIndex(value => pid === value[0]);
155
+ if (index !== -1) {
156
+ ARIA2.PID_QUEUE.splice(index, 1);
157
+ }
162
158
  }
163
159
  }
164
160
  function clearDnsLookup() {
165
161
  DNS.CACHE = Object.create(null);
166
- DNS.TIMEOUT.forEach(value => clearTimeout(value));
162
+ for (const value of DNS.TIMEOUT) {
163
+ clearTimeout(value);
164
+ }
167
165
  DNS.TIMEOUT.length = 0;
168
166
  }
169
167
  function resetHttpHost(version) {
@@ -194,15 +192,8 @@ function resetHttpHost(version) {
194
192
  function validateCerts(certs) {
195
193
  const text = {};
196
194
  const file = {};
197
- const checkFile = (values) => {
198
- for (let pathname of values) {
199
- if (module_1.isPath(pathname = path.resolve(pathname))) {
200
- return pathname;
201
- }
202
- }
203
- };
204
195
  for (let origin in certs) {
205
- let { ca, cert, key, passphrase, version: minVersion } = certs[origin], file_ca, file_cert, file_key, keyObject;
196
+ let { ca, cert, key, passphrase, ciphers, version: minVersion } = certs[origin], file_ca, file_cert, file_key, keyObject;
206
197
  try {
207
198
  origin = new URL(origin).origin;
208
199
  }
@@ -241,16 +232,16 @@ function validateCerts(certs) {
241
232
  }
242
233
  file_key = checkFile(key);
243
234
  key = key.map(value => Request.readTLSKey(value)).filter(value => value);
244
- if (key.length) {
235
+ if (key.length > 0) {
245
236
  if (!Array.isArray(passphrase)) {
246
237
  passphrase = passphrase ? [passphrase] : [];
247
238
  }
248
- keyObject = key.length > 1 || passphrase.length ? key.map((pem, index) => ({ pem, passphrase: passphrase[index] })) : key[0];
239
+ keyObject = key.length > 1 || passphrase.length > 0 ? key.map((pem, index) => ({ pem, passphrase: passphrase[index] })) : key[0];
249
240
  }
250
241
  }
251
242
  }
252
243
  if (ca || cert) {
253
- text[origin] = { ca, cert, key: keyObject, version: minVersion };
244
+ text[origin] = { ca, cert, key: keyObject, ciphers, version: minVersion };
254
245
  }
255
246
  if (file_ca || file_cert) {
256
247
  file[origin] = { ca: file_ca, cert: file_cert, key: file_key };
@@ -258,32 +249,42 @@ function validateCerts(certs) {
258
249
  }
259
250
  return [text, file];
260
251
  }
261
- function abortHeaders(href, request, options) {
262
- const reason = (0, types_1.errorValue)("Aborted by client", href);
263
- const outAbort = options.outAbort;
264
- if (outAbort) {
265
- outAbort.abort(reason);
266
- this[kDownloading].delete(outAbort);
252
+ function checkFile(values) {
253
+ for (let pathname of values) {
254
+ if (module_1.isPath(pathname = path.resolve(pathname))) {
255
+ return pathname;
256
+ }
267
257
  }
268
- request.destroy(reason);
269
258
  }
270
- function checkEncoding(request, response, statusCode, outStream, contentEncoding = '') {
259
+ function parseSize(value, zero) {
260
+ if (zero && (value === '0' || value === 0)) {
261
+ return 0;
262
+ }
263
+ if ((0, types_1.isString)(value) && /^\d+[KM]$/.test(value = value.trim().toUpperCase())) {
264
+ return value;
265
+ }
266
+ }
267
+ function copySearchParams(url, base) {
268
+ base.searchParams.forEach((value, key) => {
269
+ if (!url.searchParams.has(key)) {
270
+ url.searchParams.append(key, value);
271
+ }
272
+ });
273
+ }
274
+ function checkEncoding(request, response, statusCode, outStream, contentEncoding) {
271
275
  switch (statusCode) {
272
276
  case 206:
273
277
  request.emit('error', (0, types_1.errorValue)("Aborted", 'Partial content'));
274
278
  case 204:
275
279
  return;
276
- default:
277
- contentEncoding = contentEncoding.trim();
278
- if (!contentEncoding) {
279
- return;
280
- }
281
- contentEncoding = contentEncoding.toLowerCase();
282
- break;
283
280
  }
281
+ if (!contentEncoding) {
282
+ return;
283
+ }
284
+ contentEncoding = contentEncoding.trim().toLowerCase();
284
285
  const chunkSize = outStream?.writableHighWaterMark;
285
286
  let pipeTo;
286
- if (contentEncoding.indexOf(',') === -1) {
287
+ if (!contentEncoding.includes(',')) {
287
288
  pipeTo = decompressEncoding(contentEncoding, chunkSize);
288
289
  }
289
290
  else {
@@ -297,10 +298,18 @@ function checkEncoding(request, response, statusCode, outStream, contentEncoding
297
298
  }
298
299
  if (pipeTo) {
299
300
  if (outStream) {
300
- stream.pipeline(response, pipeTo, outStream, err => err && response.emit('error', err));
301
+ stream.pipeline(response, pipeTo, outStream, err => {
302
+ if (err) {
303
+ response.emit('error', err);
304
+ }
305
+ });
301
306
  }
302
307
  else {
303
- stream.pipeline(response, pipeTo, err => err && response.emit('error', err));
308
+ stream.pipeline(response, pipeTo, err => {
309
+ if (err) {
310
+ response.emit('error', err);
311
+ }
312
+ });
304
313
  }
305
314
  return pipeTo;
306
315
  }
@@ -322,10 +331,577 @@ function decompressEncoding(value, chunkSize) {
322
331
  break;
323
332
  }
324
333
  }
334
+ function abortHeaders(href, request, options) {
335
+ const reason = (0, types_1.errorValue)("Aborted by client", href);
336
+ const outAbort = options.outAbort;
337
+ if (outAbort) {
338
+ outAbort.abort(reason);
339
+ this[kDownloading].delete(outAbort);
340
+ }
341
+ request.destroy(reason);
342
+ }
343
+ function resetAria2() {
344
+ clearInterval(ARIA2.PID_TIMER);
345
+ ARIA2.PID_TIMER = null;
346
+ }
347
+ function escapeShellQuote(value) {
348
+ value = value.replaceAll('"', '\\"');
349
+ return module_1.PLATFORM_WIN32 ? value : value.replace(/[ $`]/g, capture => (capture !== ' ' ? '\\' : '') + '\\' + capture);
350
+ }
351
+ function failedDns(err, pending) {
352
+ for (const cb of pending) {
353
+ if (SUPPORTED_NODE20) {
354
+ cb(err, []);
355
+ }
356
+ else {
357
+ cb(err, '', 0);
358
+ }
359
+ }
360
+ pending.length = 0;
361
+ }
362
+ function successDns(instance, value, pending, connected) {
363
+ instance[kConnectDns][value] = connected;
364
+ setDnsCache(value, connected, null);
365
+ if (SUPPORTED_NODE20) {
366
+ for (const cb of pending) {
367
+ cb(null, connected);
368
+ }
369
+ }
370
+ else {
371
+ const { address, family } = connected[0];
372
+ for (const cb of pending) {
373
+ cb(null, address, family);
374
+ }
375
+ }
376
+ pending.length = 0;
377
+ }
378
+ const configureDns = (family, options) => family === 0 ? options : { family, hints: family === 6 ? dns.V4MAPPED : 0 };
379
+ const ignoreOpt = (opts, ...values) => !opts?.some(item => values.includes(item));
380
+ const escapeQuote = (value) => value.replace(/[\\"]/g, capture => '\\' + capture);
381
+ class Fetch {
382
+ static isUnsupported(value) {
383
+ return value === 421 || value === 505;
384
+ }
385
+ static isDowngrade(err) {
386
+ return err instanceof Error && (err.code === 'ERR_HTTP2_ERROR' || this.isUnsupported(Math.abs(err.errno)));
387
+ }
388
+ static wasAborted(err) {
389
+ return err instanceof Error && err.message.startsWith("Aborted");
390
+ }
391
+ static isConnectionTimeout(err) {
392
+ switch (err instanceof Error && err.code) {
393
+ case 'ETIMEDOUT':
394
+ case 'ECONNRESET':
395
+ return true;
396
+ default:
397
+ return false;
398
+ }
399
+ }
400
+ constructor(instance, uri, opts) {
401
+ this.instance = instance;
402
+ this.opts = opts;
403
+ this.retries = 0;
404
+ this.redirects = 0;
405
+ this.closed = false;
406
+ this.aborted = false;
407
+ this.timeout = null;
408
+ this.outStream = null;
409
+ this.status = opts.silent === false || !opts.silent && !instance[kSingleton];
410
+ this.log = this.status && LOG_HTTP && LOG_TIMEPROCESS;
411
+ this.startTime = this.log ? process.hrtime() : 0;
412
+ this.setConfig(uri);
413
+ }
414
+ async start() {
415
+ return new Promise((resolve, reject) => {
416
+ this.promise = [resolve, reject];
417
+ this.init();
418
+ });
419
+ }
420
+ init() {
421
+ if (this.retries > 0) {
422
+ this.cleanup();
423
+ this.aborted = false;
424
+ }
425
+ this.setWriteStream();
426
+ const config = this.config;
427
+ const client = this.instance.open(this.uri, config);
428
+ this.client = client;
429
+ if (config.httpVersion === 2) {
430
+ client
431
+ .on('response', (headers, flags) => {
432
+ if (this.destroyed) {
433
+ return;
434
+ }
435
+ const statusCode = headers[':status'];
436
+ if (statusCode < 300) {
437
+ this.acceptResponse(headers);
438
+ }
439
+ else if (statusCode < 400) {
440
+ this.redirectResponse(statusCode, headers.location);
441
+ }
442
+ else if (statusCode === 401 ||
443
+ statusCode === 402 ||
444
+ statusCode === 403 ||
445
+ statusCode === 404 ||
446
+ statusCode === 407 ||
447
+ statusCode === 410) {
448
+ this.rejectError(this.formatStatus(statusCode));
449
+ }
450
+ else if (this.isRetry(statusCode)) {
451
+ this.retryResponse(statusCode, headers['retry-after']);
452
+ }
453
+ else if (Fetch.isUnsupported(statusCode)) {
454
+ this.retryDownload(true, this.formatNgFlags(http2.constants.NGHTTP2_PROTOCOL_ERROR, statusCode));
455
+ }
456
+ else {
457
+ switch (flags) {
458
+ case http2.constants.NGHTTP2_PROTOCOL_ERROR:
459
+ case http2.constants.NGHTTP2_INADEQUATE_SECURITY:
460
+ case http2.constants.NGHTTP2_HTTP_1_1_REQUIRED:
461
+ this.retryDownload(true, this.formatNgFlags(flags, statusCode, headers.location));
462
+ break;
463
+ default:
464
+ this.retryDownload(false, this.formatStatus(statusCode));
465
+ break;
466
+ }
467
+ }
468
+ })
469
+ .on('unknownProtocol', () => {
470
+ if (!this.aborted) {
471
+ this.retryDownload(true, 'Unknown protocol (HTTP/2)');
472
+ }
473
+ })
474
+ .on('aborted', () => {
475
+ this.aborted = true;
476
+ this.rejectError((0, types_1.createAbortError)());
477
+ })
478
+ .on('error', async (err) => {
479
+ if (this.aborted) {
480
+ return;
481
+ }
482
+ if (Fetch.wasAborted(err)) {
483
+ this.errorResponse(err);
484
+ }
485
+ else {
486
+ switch (!Fetch.isDowngrade(err) && await config.host.hasProtocol(2)) {
487
+ case 1:
488
+ this.errorResponse(err);
489
+ break;
490
+ case 2:
491
+ this.retryDownload(false, err);
492
+ break;
493
+ default:
494
+ this.retryDownload(true, err);
495
+ break;
496
+ }
497
+ }
498
+ });
499
+ }
500
+ else {
501
+ client
502
+ .on('response', res => {
503
+ if (this.destroyed) {
504
+ return;
505
+ }
506
+ const statusCode = res.statusCode;
507
+ if (statusCode < 300) {
508
+ this.acceptResponse(res.headers);
509
+ }
510
+ else if (statusCode < 400) {
511
+ this.redirectResponse(statusCode, res.headers.location);
512
+ }
513
+ else if (this.isRetry(statusCode)) {
514
+ this.retryResponse(statusCode, res.headers['retry-after']);
515
+ }
516
+ else {
517
+ this.abortResponse();
518
+ this.rejectError(this.formatStatus(statusCode));
519
+ }
520
+ })
521
+ .on('abort', () => {
522
+ this.aborted = true;
523
+ this.rejectError((0, types_1.createAbortError)());
524
+ })
525
+ .on('error', err => {
526
+ if (!this.aborted) {
527
+ this.errorResponse(err);
528
+ }
529
+ });
530
+ }
531
+ client.on('timeout', () => {
532
+ if (this.aborted) {
533
+ return;
534
+ }
535
+ this.abortResponse();
536
+ if (++this.retries <= this.retryLimit) {
537
+ this.retryTimeout();
538
+ }
539
+ else {
540
+ this.rejectError(this.formatStatus(408));
541
+ }
542
+ });
543
+ }
544
+ setConfig(uri) {
545
+ this.uri = uri;
546
+ this.config = this.instance.opts(uri, this.opts);
547
+ }
548
+ setWriteStream() {
549
+ const pipeTo = this.pipeTo;
550
+ if (typeof pipeTo === 'string') {
551
+ try {
552
+ this.outStream = fs.createWriteStream(pipeTo, { emitClose: false, highWaterMark: this.config.host.streamSize });
553
+ this.config.outStream = this.outStream;
554
+ }
555
+ catch (err) {
556
+ this.rejectError(err);
557
+ }
558
+ }
559
+ else {
560
+ this.config.outStream = pipeTo;
561
+ }
562
+ }
563
+ abortResponse() {
564
+ if (this.closed) {
565
+ return;
566
+ }
567
+ if (this.timeout) {
568
+ clearTimeout(this.timeout);
569
+ }
570
+ this.aborted = true;
571
+ if (this.outAbort) {
572
+ if (!this.client.aborted) {
573
+ this.outAbort.abort();
574
+ }
575
+ this.downloading.delete(this.outAbort);
576
+ }
577
+ this.client.destroy();
578
+ }
579
+ retryDownload(downgrade, message) {
580
+ if (this.aborted) {
581
+ return;
582
+ }
583
+ this.abortResponse();
584
+ if (downgrade) {
585
+ const host = this.config.host;
586
+ host.failed(2);
587
+ if (host.version > 1) {
588
+ if (this.status) {
589
+ this.instance.formatMessage(1024, 'HTTP2', ["Unsupported protocol", host.origin], message, { failed: true });
590
+ }
591
+ host.version = 1;
592
+ }
593
+ }
594
+ this.opts.httpVersion = 1;
595
+ this.init();
596
+ }
597
+ acceptResponse(headers) {
598
+ const { instance, config, client, opts, pipeTo } = this;
599
+ const parent = this.instance.host;
600
+ const progressId = config.progressId;
601
+ if ('outHeaders' in opts) {
602
+ opts.outHeaders = headers;
603
+ }
604
+ if ('outFilename' in opts) {
605
+ opts.outFilename = (0, util_1.parseHeader)(headers, 'content-disposition');
606
+ }
607
+ const pipeline = pipeTo ? !(0, types_1.isString)(pipeTo) : false;
608
+ const enabled = config.connected?.call(client, headers) !== false && !pipeline;
609
+ const maxBufferSize = config.maxBufferSize ? (0, types_1.alignSize)(config.maxBufferSize) : 0;
610
+ const contentLength = parent && progressId !== undefined ? parseInt(headers['content-length'] || '0') : 0;
611
+ let log = this.log, buffer = null, dataLength = 0, mibsTime, delayTime;
612
+ if (log || contentLength > 0 || instance.readTimeout > 0) {
613
+ client.once('readable', () => {
614
+ if (instance.readTimeout > 0) {
615
+ this.timeout = setTimeout(() => {
616
+ this.abortResponse();
617
+ this.rejectError((0, types_1.errorValue)("Timeout was exceeded", this.uri.toString()));
618
+ }, instance.readTimeout);
619
+ }
620
+ if (log) {
621
+ switch (instance.settings?.time_format || LOG_TIMEFORMAT) {
622
+ case 'readable':
623
+ delayTime = process.hrtime(this.startTime);
624
+ break;
625
+ case 'relative':
626
+ delayTime = Date.now() - instance.startTime;
627
+ break;
628
+ case 'none':
629
+ if (opts.silent !== false) {
630
+ log = false;
631
+ }
632
+ break;
633
+ }
634
+ }
635
+ mibsTime = process.hrtime();
636
+ if (contentLength > 0) {
637
+ parent.updateProgress("request", progressId, 0, 0, mibsTime);
638
+ }
639
+ });
640
+ }
641
+ if (enabled) {
642
+ const encoding = opts.encoding;
643
+ client.on('data', (chunk) => {
644
+ if (buffer) {
645
+ if (typeof buffer === 'string') {
646
+ buffer += typeof chunk === 'string' ? chunk : chunk.toString(encoding);
647
+ }
648
+ else if (Array.isArray(buffer)) {
649
+ buffer.push(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk);
650
+ }
651
+ else {
652
+ buffer = Buffer.concat([buffer, typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk]);
653
+ }
654
+ }
655
+ else {
656
+ buffer = typeof chunk === 'string' ? chunk : [chunk];
657
+ }
658
+ if (contentLength > 0) {
659
+ dataLength += Buffer.byteLength(chunk, encoding);
660
+ parent.updateProgress("request", progressId, dataLength, contentLength);
661
+ }
662
+ if (maxBufferSize > 0) {
663
+ if (contentLength === 0) {
664
+ dataLength += Buffer.byteLength(chunk, encoding);
665
+ }
666
+ if (dataLength > maxBufferSize) {
667
+ this.abortResponse();
668
+ this.rejectError((0, types_1.errorValue)("Size limit was exceeded", this.uri.toString()));
669
+ }
670
+ }
671
+ });
672
+ }
673
+ client.once('end', () => {
674
+ if (this.closed || this.aborted) {
675
+ return;
676
+ }
677
+ if (this.timeout) {
678
+ clearTimeout(this.timeout);
679
+ }
680
+ if (this.outAbort) {
681
+ this.downloading.delete(this.outAbort);
682
+ }
683
+ this.closed = true;
684
+ const encoding = opts.encoding;
685
+ let result, messageUnit, titleBgColor;
686
+ if (buffer) {
687
+ if (Array.isArray(buffer)) {
688
+ buffer = Buffer.concat(buffer);
689
+ if (encoding) {
690
+ buffer = buffer.toString(encoding);
691
+ }
692
+ }
693
+ dataLength = Buffer.byteLength(buffer, encoding);
694
+ if (mibsTime) {
695
+ messageUnit = (0, util_1.getTransferRate)(dataLength, (0, types_1.convertTime)(process.hrtime(mibsTime), false) * 1000);
696
+ }
697
+ if (contentLength > 0) {
698
+ parent.updateProgress("request", progressId, dataLength, dataLength);
699
+ }
700
+ if (typeof buffer === 'string') {
701
+ if (buffer.startsWith('\uFEFF') && encoding !== 'utf16le' && encoding !== 'utf-16le') {
702
+ buffer = buffer.substring(1);
703
+ }
704
+ if (config.outFormat) {
705
+ const { out: format, parser } = config.outFormat;
706
+ let packageName;
707
+ try {
708
+ switch (format) {
709
+ case 'yaml':
710
+ result = yaml.load(buffer, parser);
711
+ break;
712
+ case 'json5':
713
+ result = require(packageName = 'json5').parse(buffer);
714
+ break;
715
+ case 'xml':
716
+ result = new (require(packageName = 'fast-xml-parser').XMLParser)(parser).parse(buffer);
717
+ break;
718
+ case 'toml':
719
+ result = require(packageName = 'toml').parse(buffer);
720
+ break;
721
+ default:
722
+ result = JSON.parse(buffer);
723
+ break;
724
+ }
725
+ if (!(0, types_1.isObject)(result)) {
726
+ result = null;
727
+ }
728
+ }
729
+ catch (err) {
730
+ if (this.status && !(packageName && instance.checkPackage(err, packageName))) {
731
+ instance.writeFail(["Unable to parse URI response", format], err, 1024);
732
+ }
733
+ result = null;
734
+ }
735
+ }
736
+ }
737
+ if (result === undefined) {
738
+ result = buffer;
739
+ }
740
+ }
741
+ else {
742
+ if (contentLength > 0) {
743
+ parent.updateProgress("request", progressId, 0, contentLength);
744
+ }
745
+ if (enabled && instance.readExpect === 'always') {
746
+ this.rejectError("No data received");
747
+ return;
748
+ }
749
+ result = encoding && !pipeline ? '' : null;
750
+ titleBgColor = 'bgBlue';
751
+ }
752
+ if (log) {
753
+ instance.writeTimeProcess('HTTP' + config.httpVersion, config.statusMessage || this.uri.toString(), this.startTime, { type: 1024, queue: !!parent, titleBgColor, messageUnit, messageUnitMinWidth: 9, delayTime, bypassLog: LOG_STDOUT });
754
+ }
755
+ this.promise[0](result);
756
+ });
757
+ config.host.success(this.httpVersion);
758
+ }
759
+ redirectResponse(statusCode, location) {
760
+ this.abortResponse();
761
+ if (location) {
762
+ if (this.config.follow_redirect === false) {
763
+ this.rejectError(this.formatStatus(statusCode, "Follow redirect was disabled"));
764
+ }
765
+ else if (++this.redirects <= this.redirectLimit) {
766
+ this.setConfig(Request.fromURL(this.config.url, location));
767
+ this.init();
768
+ }
769
+ else {
770
+ this.rejectError(this.formatStatus(statusCode, "Exceeded redirect limit"));
771
+ }
772
+ }
773
+ else {
774
+ this.rejectError(this.formatStatus(statusCode, "Missing redirect location"));
775
+ }
776
+ }
777
+ errorResponse(err) {
778
+ this.abortResponse();
779
+ if (Fetch.wasAborted(err)) {
780
+ this.rejectError(err);
781
+ }
782
+ else if ((0, util_1.checkRetryable)(err) && ++this.retries <= this.retryLimit) {
783
+ if (Fetch.isConnectionTimeout(err)) {
784
+ this.retryTimeout();
785
+ }
786
+ else {
787
+ setTimeout(() => {
788
+ this.init();
789
+ }, this.retryWait);
790
+ }
791
+ }
792
+ else {
793
+ this.config.host.error(this.httpVersion);
794
+ this.rejectError(err);
795
+ }
796
+ }
797
+ retryResponse(statusCode, retryAfter) {
798
+ this.abortResponse();
799
+ if (retryAfter && this.retryAfter > 0) {
800
+ let offset = +retryAfter || new Date(retryAfter);
801
+ if (offset instanceof Date) {
802
+ offset = Math.max(0, offset.getTime() - Date.now());
803
+ }
804
+ else {
805
+ offset *= 1000;
806
+ }
807
+ if (offset > 0) {
808
+ if (offset <= this.retryAfter) {
809
+ this.sendWarning(`Retry After (${retryAfter})`);
810
+ setTimeout(() => {
811
+ this.init();
812
+ }, offset);
813
+ }
814
+ else {
815
+ this.rejectError(this.formatStatus(statusCode));
816
+ }
817
+ return;
818
+ }
819
+ }
820
+ this.sendWarning(this.formatRetry(Request.fromStatusCode(statusCode)));
821
+ if ((0, util_1.isRetryable)(statusCode, true)) {
822
+ process.nextTick(this.init.bind(this));
823
+ }
824
+ else {
825
+ setTimeout(() => {
826
+ this.init();
827
+ }, this.retryWait);
828
+ }
829
+ }
830
+ isRetry(value) {
831
+ return (0, util_1.isRetryable)(value) && ++this.retries <= this.retryLimit;
832
+ }
833
+ retryTimeout() {
834
+ this.sendWarning(this.formatRetry("HTTP connection timeout"));
835
+ this.init();
836
+ }
837
+ rejectError(err) {
838
+ if (this.timeout) {
839
+ clearTimeout(this.timeout);
840
+ }
841
+ if (!this.closed) {
842
+ this.closed = true;
843
+ this.cleanup();
844
+ this.promise[1](typeof err === 'string' ? new Error(err) : err);
845
+ }
846
+ if (this.outAbort) {
847
+ this.downloading.delete(this.outAbort);
848
+ }
849
+ }
850
+ sendWarning(message) {
851
+ if (this.status) {
852
+ const { host, url } = this.config;
853
+ this.instance.formatMessage(1024, 'HTTP' + this.httpVersion, [message, host.origin], url.toString(), { ...module_1.LOG_STYLE_WARN });
854
+ }
855
+ }
856
+ formatStatus(value, hint) {
857
+ return value + ': ' + (hint || Request.fromStatusCode(value)) + ` (${this.uri.toString()})`;
858
+ }
859
+ formatNgFlags(value, statusCode, location) {
860
+ return location ? `Using HTTP 1.1 for URL redirect (${location})` : this.formatStatus(statusCode, value ? 'NGHTTP2 Error ' + value : '');
861
+ }
862
+ formatRetry(message) {
863
+ return message + ` (${this.retries} / ${this.retryLimit})`;
864
+ }
865
+ cleanup() {
866
+ if ((0, types_1.isString)(this.pipeTo) && this.outStream) {
867
+ (0, util_1.cleanupStream)(this.outStream, this.pipeTo);
868
+ }
869
+ }
870
+ get destroyed() {
871
+ return this.client.destroyed || this.httpVersion === 2 && this.client.aborted;
872
+ }
873
+ get downloading() {
874
+ return this.instance[kDownloading];
875
+ }
876
+ get httpVersion() {
877
+ return this.config.httpVersion;
878
+ }
879
+ get outAbort() {
880
+ return this.config.outAbort;
881
+ }
882
+ get pipeTo() {
883
+ return this.opts.pipeTo;
884
+ }
885
+ get retryLimit() {
886
+ return this.settings.retryLimit;
887
+ }
888
+ get retryWait() {
889
+ return this.settings.retryWait;
890
+ }
891
+ get retryAfter() {
892
+ return this.settings.retryAfter;
893
+ }
894
+ get redirectLimit() {
895
+ return this.settings.redirectLimit;
896
+ }
897
+ get settings() {
898
+ return this.instance['_config'];
899
+ }
900
+ }
325
901
  class Request extends module_1 {
326
902
  static async purgeMemory(percent = 1, limit = 0, parent) {
327
903
  if (percent >= 1) {
328
- resetHttpHost();
904
+ resetHttpHost(0);
329
905
  clearDnsLookup();
330
906
  }
331
907
  else if (percent === 0) {
@@ -341,16 +917,8 @@ class Request extends module_1 {
341
917
  return false;
342
918
  }
343
919
  const { request, download } = settings;
344
- if (download && (0, types_1.isPlainObject)(download.aria2)) {
345
- let { bin, exec, update_status, max_concurrent_downloads, max_connection_per_server, bt_stop_timeout, bt_tracker_connect_timeout, bt_tracker_timeout, min_split_size, disk_cache, lowest_speed_limit, always_resume, file_allocation, conf_path } = download.aria2;
346
- const parseSize = (value, zero) => {
347
- if (zero && (value === '0' || value === 0)) {
348
- return 0;
349
- }
350
- if ((0, types_1.isString)(value) && /^\d+[KM]$/.test(value = value.trim().toUpperCase())) {
351
- return value;
352
- }
353
- };
920
+ if (download?.aria2) {
921
+ let { bin, exec, update_status, max_concurrent_downloads, max_connection_per_server, check_integrity, bt_stop_timeout, bt_tracker_connect_timeout, bt_tracker_timeout, min_split_size, disk_cache, lowest_speed_limit, always_resume, file_allocation, conf_path } = download.aria2;
354
922
  if (bin === false) {
355
923
  ARIA2.BIN = '';
356
924
  }
@@ -375,6 +943,9 @@ class Request extends module_1 {
375
943
  if ((max_concurrent_downloads = (0, util_1.asInt)(max_concurrent_downloads)) > 0) {
376
944
  ARIA2.MAX_CONCURRENT_DOWNLOADS = max_concurrent_downloads;
377
945
  }
946
+ if (typeof check_integrity === 'boolean') {
947
+ ARIA2.CHECK_INTEGRITY = check_integrity;
948
+ }
378
949
  if ((max_connection_per_server = (0, util_1.asInt)(max_connection_per_server)) > 0) {
379
950
  ARIA2.MAX_CONNECTION_PER_SERVER = max_connection_per_server;
380
951
  }
@@ -387,7 +958,7 @@ class Request extends module_1 {
387
958
  if ((bt_tracker_timeout = (0, util_1.asInt)(bt_tracker_timeout)) > 0) {
388
959
  ARIA2.BT_TRACKER_TIMEOUT = bt_tracker_timeout;
389
960
  }
390
- if (min_split_size = parseSize(min_split_size)) {
961
+ if (min_split_size = parseSize(min_split_size, false)) {
391
962
  ARIA2.MIN_SPLIT_SIZE = min_split_size;
392
963
  }
393
964
  if ((disk_cache = parseSize(disk_cache, true)) !== undefined) {
@@ -414,7 +985,7 @@ class Request extends module_1 {
414
985
  ARIA2.CONF_PATH = conf_path;
415
986
  }
416
987
  }
417
- if ((0, types_1.isPlainObject)(request)) {
988
+ if (request) {
418
989
  let { read_timeout, agent, use, headers, certs } = request, agent_timeout;
419
990
  if ((read_timeout = (0, util_1.fromSeconds)(read_timeout)) >= 0) {
420
991
  READ_TIMEOUT = read_timeout;
@@ -436,7 +1007,7 @@ class Request extends module_1 {
436
1007
  }
437
1008
  this.defineHttpAgent({ keepAlive: keep_alive, timeout: agent_timeout });
438
1009
  }
439
- if ((0, types_1.isObject)(use)) {
1010
+ if (use) {
440
1011
  let { http_version, accept_encoding } = use;
441
1012
  if (typeof accept_encoding === 'boolean') {
442
1013
  ACCEPT_ENCODING = accept_encoding;
@@ -448,10 +1019,10 @@ class Request extends module_1 {
448
1019
  break;
449
1020
  }
450
1021
  }
451
- if ((0, types_1.isObject)(headers)) {
1022
+ if ((0, types_1.isPlainObject)(headers)) {
452
1023
  setOutgoingHeaders(HTTP.HEADERS, headers);
453
1024
  }
454
- if ((0, types_1.isObject)(certs)) {
1025
+ if ((0, types_1.isPlainObject)(certs)) {
455
1026
  [TLS.TEXT, TLS.FILE] = validateCerts(certs);
456
1027
  }
457
1028
  HTTP.PROXY = getProxySettings(request, agent_timeout);
@@ -463,6 +1034,7 @@ class Request extends module_1 {
463
1034
  LOG_TIMEFORMAT = time_format;
464
1035
  break;
465
1036
  }
1037
+ host_1.defineHostConfig(request);
466
1038
  }
467
1039
  LOG_HTTP = this.hasLogType(1024);
468
1040
  LOG_TIMEPROCESS = this.hasLogType(256);
@@ -470,7 +1042,7 @@ class Request extends module_1 {
470
1042
  return true;
471
1043
  }
472
1044
  static readCACert(value, cache) {
473
- return (0, types_1.isString)(value) ? (this.isCert(value) ? value : this.readText(value, cache)).trim() : '';
1045
+ return (this.isCert(value) ? value : this.readText(value, cache)).trim();
474
1046
  }
475
1047
  static readTLSCert(value, cache) {
476
1048
  return this.readCACert(value, cache);
@@ -479,7 +1051,7 @@ class Request extends module_1 {
479
1051
  return this.readCACert(value, cache);
480
1052
  }
481
1053
  static isCert(value) {
482
- return (0, types_1.isString)(value) && (value = value.trim()) ? value.includes('\n') && value.startsWith('---') && value.endsWith('---') : false;
1054
+ return typeof value === 'string' && (value = value.trim()).length > 0 && REGEXP_PEMCERT.test(value);
483
1055
  }
484
1056
  static fromURL(url, value) {
485
1057
  if (this.isURL(value)) {
@@ -489,7 +1061,8 @@ class Request extends module_1 {
489
1061
  return url.protocol + '//' + (auth && (auth + '@')) + url.hostname + (url.port ? ':' + url.port : '') + (value.startsWith('/') ? '' : '/') + value;
490
1062
  }
491
1063
  static fromStatusCode(value) {
492
- if ((value = +value) < 200) {
1064
+ value = +value;
1065
+ if (value < 200) {
493
1066
  switch (value) {
494
1067
  case 100:
495
1068
  return 'Continue';
@@ -698,14 +1271,15 @@ class Request extends module_1 {
698
1271
  this[_b] = null;
699
1272
  this[_c] = null;
700
1273
  this[_d] = null;
701
- this[_e] = Object.create(null);
1274
+ this[_e] = null;
702
1275
  this[_f] = Object.create(null);
703
- this[_g] = [{}, {}];
704
- this[_h] = null;
1276
+ this[_g] = Object.create(null);
1277
+ this[_h] = [{}, {}];
705
1278
  this[_j] = null;
706
- this[_k] = new Set();
707
- this[_l] = {};
708
- this[_m] = [Object.create(null)];
1279
+ this[_k] = null;
1280
+ this[_l] = new Set();
1281
+ this[_m] = {};
1282
+ this[_o] = [Object.create(null)];
709
1283
  if ((0, types_1.isPlainObject)(data)) {
710
1284
  const { headers, read_timeout, agent, use, connect, certs } = data;
711
1285
  const timeout = (0, util_1.fromSeconds)(data.timeout);
@@ -764,11 +1338,11 @@ class Request extends module_1 {
764
1338
  log.length = 0;
765
1339
  }
766
1340
  else {
767
- if (log.length && !this.host?.aborted) {
1341
+ if (log.length > 0 && !this.host?.aborted) {
768
1342
  const output = [];
769
1343
  let count = 0;
770
1344
  this[kConnectHttp].forEach((protocol, index) => {
771
- var _o;
1345
+ var _p;
772
1346
  const title = 'HTTP' + (index + 1);
773
1347
  for (const origin in protocol) {
774
1348
  const value = protocol[origin];
@@ -778,7 +1352,7 @@ class Request extends module_1 {
778
1352
  if (item[1] === title && Array.isArray(item[2]) && item[2][0].startsWith(origin)) {
779
1353
  item[1] = '';
780
1354
  item[2][0] = item[2][0].substring(origin.length);
781
- (_o = item[4]).titleBgColor && (_o.titleBgColor = undefined);
1355
+ (_p = item[4]).titleBgColor && (_p.titleBgColor = undefined);
782
1356
  item[4].titleJustify = 'right';
783
1357
  args.push(item);
784
1358
  log.splice(i--, 1);
@@ -796,8 +1370,7 @@ class Request extends module_1 {
796
1370
  return b[2] - a[2];
797
1371
  });
798
1372
  const width = count.toString().length;
799
- output.forEach(item => {
800
- const [title, origin, downloads, messages] = item;
1373
+ for (const [title, origin, downloads, messages] of output) {
801
1374
  const options = { ...title === 'HTTP1' ? module_1.LOG_STYLE_NOTICE : module_1.LOG_STYLE_INFO };
802
1375
  if (messages.length === 1) {
803
1376
  const message = messages[0];
@@ -808,12 +1381,12 @@ class Request extends module_1 {
808
1381
  }
809
1382
  else {
810
1383
  this.formatMessage(1024, title, [origin, 'downloads: ' + downloads.toString().padStart(width)], '', options);
811
- messages.forEach(args => {
1384
+ for (const args of messages) {
812
1385
  args[4].titleIndent = true;
813
1386
  this.formatMessage(...args);
814
- });
1387
+ }
815
1388
  }
816
- });
1389
+ }
817
1390
  }
818
1391
  }
819
1392
  super.flushLog();
@@ -829,7 +1402,9 @@ class Request extends module_1 {
829
1402
  }
830
1403
  }
831
1404
  abort(reason) {
832
- this[kDownloading].forEach(item => item.abort(reason));
1405
+ for (const item of this[kDownloading]) {
1406
+ item.abort(reason);
1407
+ }
833
1408
  this.close();
834
1409
  if (!this[kSingleton]) {
835
1410
  super.abort(reason);
@@ -929,11 +1504,11 @@ class Request extends module_1 {
929
1504
  setDnsCache(hostname, this[kConnectDns][hostname] = [{ address, family }], timeout);
930
1505
  }
931
1506
  lookupDns(hostname) {
932
- var _o;
1507
+ var _p;
933
1508
  const resolved = this[kConnectDns][hostname] || DNS.CACHE[hostname];
934
1509
  if (resolved) {
935
1510
  return (...args) => {
936
- if (SUPPORT_NODEJS20) {
1511
+ if (SUPPORTED_NODE20) {
937
1512
  args[2](null, resolved);
938
1513
  }
939
1514
  else {
@@ -941,36 +1516,20 @@ class Request extends module_1 {
941
1516
  }
942
1517
  };
943
1518
  }
944
- const pending = (_o = this[kPendingDns])[hostname] || (_o[hostname] = []);
1519
+ const pending = (_p = this[kPendingDns])[hostname] || (_p[hostname] = []);
945
1520
  return (value, options, callback) => {
946
1521
  if (pending.push(callback) === 1) {
947
- const configure = (family) => family === 0 ? options : { family, hints: family === 6 ? dns.V4MAPPED : 0 };
948
- const success = (connected) => {
949
- setDnsCache(value, this[kConnectDns][value] = connected);
950
- if (SUPPORT_NODEJS20) {
951
- pending.forEach(cb => cb(null, connected));
952
- }
953
- else {
954
- const { address, family } = connected[0];
955
- pending.forEach(cb => cb(null, address, family));
956
- }
957
- pending.length = 0;
958
- };
959
- const failed = (err) => {
960
- pending.forEach(cb => SUPPORT_NODEJS20 ? cb(err, []) : cb(err, '', 0));
961
- pending.length = 0;
962
- };
963
1522
  let ipVersion = this.ipVersion;
964
- dns.lookup(value, configure(ipVersion), (err, address, family) => {
1523
+ dns.lookup(value, configureDns(ipVersion, options), (err, address, family) => {
965
1524
  if (!err) {
966
- success(typeof address === 'string' ? [{ address, family }] : address);
1525
+ successDns(this, value, pending, typeof address === 'string' ? [{ address, family }] : address);
967
1526
  return;
968
1527
  }
969
1528
  switch (err.code) {
970
1529
  case 'ENOTFOUND':
971
1530
  case 'EBADNAME':
972
1531
  case 'ENODATA':
973
- failed(err);
1532
+ failedDns(err, pending);
974
1533
  return;
975
1534
  case 'ETIMEOUT':
976
1535
  case 'ECONNREFUSED':
@@ -980,18 +1539,18 @@ class Request extends module_1 {
980
1539
  break;
981
1540
  default:
982
1541
  if (ipVersion === 0) {
983
- failed(err);
1542
+ failedDns(err, pending);
984
1543
  return;
985
1544
  }
986
1545
  ipVersion = ipVersion === 4 ? 6 : 4;
987
1546
  break;
988
1547
  }
989
- dns.lookup(value, configure(ipVersion), (err, address, family) => {
1548
+ dns.lookup(value, configureDns(ipVersion, options), (err, address, family) => {
990
1549
  if (!err) {
991
- success(typeof address === 'string' ? [{ address, family }] : address);
1550
+ successDns(this, value, pending, typeof address === 'string' ? [{ address, family }] : address);
992
1551
  }
993
1552
  else {
994
- failed(err);
1553
+ failedDns(err, pending);
995
1554
  }
996
1555
  });
997
1556
  });
@@ -1005,12 +1564,10 @@ class Request extends module_1 {
1005
1564
  if (!include && !exclude && !localhost) {
1006
1565
  return proxy;
1007
1566
  }
1008
- if ((0, types_1.isArray)(include)) {
1009
- return include.some(value => uri.startsWith(value)) ? proxy : undefined;
1010
- }
1011
- if (Array.isArray(exclude) && !exclude.some(value => uri.startsWith(value))) {
1012
- return proxy;
1567
+ if ((0, types_1.isArray)(include) && !include.some(value => REGEXP_GLOBWITHIN.test(value) ? pm.isMatch(uri, value) : uri.startsWith(value)) || (0, types_1.isArray)(exclude) && exclude.some(value => REGEXP_GLOBWITHIN.test(value) ? pm.isMatch(uri, value) : uri.startsWith(value))) {
1568
+ return;
1013
1569
  }
1570
+ return proxy;
1014
1571
  }
1015
1572
  }
1016
1573
  statusOn(code, globUrl = '*', callback) {
@@ -1054,12 +1611,7 @@ class Request extends module_1 {
1054
1611
  return Promise.reject((0, types_1.errorMessage)("aria2", "Binary not found"));
1055
1612
  }
1056
1613
  if (typeof uri === 'string' && module_1.isURL(uri)) {
1057
- try {
1058
- uri = new URL(uri);
1059
- }
1060
- catch (err) {
1061
- return Promise.reject(err);
1062
- }
1614
+ uri = new URL(uri);
1063
1615
  }
1064
1616
  let pathname, headers, binOpts, silent;
1065
1617
  if (options) {
@@ -1070,7 +1622,7 @@ class Request extends module_1 {
1070
1622
  ({ pathname, headers, binOpts, silent } = options);
1071
1623
  if ((0, types_1.isArray)(binOpts)) {
1072
1624
  let next = false;
1073
- binOpts = binOpts.filter(opt => !((0, types_1.isString)(opt) && /^-[a-z][\S\s]*$/i.test(opt.trim()))).map((opt) => {
1625
+ binOpts = binOpts.filter(opt => !((0, types_1.isString)(opt) && /^-[a-z].*$/i.test(opt.trim()))).map((opt) => {
1074
1626
  if (next) {
1075
1627
  if (!module_1.asString(opt).startsWith('--')) {
1076
1628
  return [];
@@ -1108,7 +1660,7 @@ class Request extends module_1 {
1108
1660
  return [opt.toString()];
1109
1661
  default:
1110
1662
  if ((0, types_1.isArray)(opt)) {
1111
- return opt.filter(item => (0, types_1.isString)(item)).map((item) => module_1.sanitizeArgs(item));
1663
+ return opt.filter(item => (0, types_1.isString)(item)).map(item => module_1.sanitizeArgs(item));
1112
1664
  }
1113
1665
  break;
1114
1666
  }
@@ -1135,12 +1687,8 @@ class Request extends module_1 {
1135
1687
  if (uri instanceof URL) {
1136
1688
  ({ protocol, origin, username, password, href: uri } = uri);
1137
1689
  }
1138
- const escapeQuote = (value) => {
1139
- value = value.replace(/"/g, '\\"');
1140
- return PLATFORM_WIN32 ? value : value.replace(/[ $`]/g, capture => (capture !== ' ' ? '\\' : '') + '\\' + capture);
1141
- };
1142
1690
  const init = [
1143
- `--dir="${escapeQuote(pathname)}"`,
1691
+ `--dir="${escapeShellQuote(pathname)}"`,
1144
1692
  '--download-result=full',
1145
1693
  '--follow-torrent=mem',
1146
1694
  '--follow-metalink=mem',
@@ -1188,13 +1736,15 @@ class Request extends module_1 {
1188
1736
  '--file-allocation=' + ARIA2.FILE_ALLOCATION,
1189
1737
  '--max-tries=' + (retryLimit + 1)
1190
1738
  ];
1191
- const ignoreOpt = (...values) => !binOpts?.some(item => values.includes(item));
1192
1739
  if (ARIA2.MAX_CONCURRENT_DOWNLOADS) {
1193
1740
  opts.push('--max-concurrent-downloads=' + ARIA2.MAX_CONCURRENT_DOWNLOADS);
1194
1741
  }
1195
1742
  if (ARIA2.MAX_CONNECTION_PER_SERVER) {
1196
1743
  opts.push('--max-connection-per-server=' + ARIA2.MAX_CONNECTION_PER_SERVER);
1197
1744
  }
1745
+ if (ARIA2.CHECK_INTEGRITY) {
1746
+ opts.push('--check-integrity=true');
1747
+ }
1198
1748
  if (ARIA2.MIN_SPLIT_SIZE) {
1199
1749
  opts.push('--min-split-size=' + ARIA2.MIN_SPLIT_SIZE);
1200
1750
  }
@@ -1205,7 +1755,7 @@ class Request extends module_1 {
1205
1755
  opts.push('--lowest-speed-limit=' + ARIA2.LOWEST_SPEED_LIMIT);
1206
1756
  }
1207
1757
  if (ARIA2.CONF_PATH) {
1208
- opts.push(`--conf-path="${escapeQuote(ARIA2.CONF_PATH)}"`);
1758
+ opts.push(`--conf-path="${escapeShellQuote(ARIA2.CONF_PATH)}"`);
1209
1759
  }
1210
1760
  if (!ARIA2.ALWAYS_RESUME) {
1211
1761
  opts.push('--always-resume=false', '--keep-unfinished-download-result=false');
@@ -1223,7 +1773,7 @@ class Request extends module_1 {
1223
1773
  if (this.agentTimeout === 0) {
1224
1774
  opts.push('--enable-http-keep-alive=false');
1225
1775
  }
1226
- const baseHeaders = ignoreOpt('--header') && this.headersOf(uri);
1776
+ const baseHeaders = ignoreOpt(binOpts, '--header') && this.headersOf(uri);
1227
1777
  if (headers || baseHeaders) {
1228
1778
  if (baseHeaders) {
1229
1779
  headers = headers ? { ...baseHeaders, ...headers } : baseHeaders;
@@ -1233,47 +1783,50 @@ class Request extends module_1 {
1233
1783
  if (!Array.isArray(items)) {
1234
1784
  items = [items.toString()];
1235
1785
  }
1236
- args.push(...items.map(value => `--header="${name}: ${escapeQuote(value)}"`));
1786
+ args.push(...items.map(value => `--header="${name}: ${escapeShellQuote(value)}"`));
1237
1787
  }
1238
1788
  }
1239
1789
  if (origin) {
1240
1790
  const secure = this[kCerts]?.[1][origin] || this.host && TLS.FILE[origin];
1241
1791
  if (secure) {
1242
- if (secure.ca && ignoreOpt('--ca-certificate')) {
1243
- args.push(`--ca-certificate="${escapeQuote(secure.ca)}"`);
1792
+ if (secure.ca && ignoreOpt(binOpts, '--ca-certificate')) {
1793
+ args.push(`--ca-certificate="${escapeShellQuote(secure.ca)}"`);
1244
1794
  }
1245
- if (secure.cert && ignoreOpt('--certificate', '--private-key')) {
1246
- args.push(`--certificate="${escapeQuote(secure.cert)}"`);
1795
+ if (secure.cert && ignoreOpt(binOpts, '--certificate', '--private-key')) {
1796
+ args.push(`--certificate="${escapeShellQuote(secure.cert)}"`);
1247
1797
  if (secure.key) {
1248
- args.push(`--private-key="${escapeQuote(secure.key)}"`);
1798
+ args.push(`--private-key="${escapeShellQuote(secure.key)}"`);
1249
1799
  }
1250
1800
  }
1251
1801
  }
1252
1802
  }
1253
1803
  switch (protocol = protocol.substring(0, protocol.length - 1)) {
1254
- case 'ftp':
1255
1804
  case 'http':
1256
- case 'https': {
1805
+ case 'https':
1806
+ if (ignoreOpt(binOpts, '--http-no-cache')) {
1807
+ args.push('--http-no-cache=true');
1808
+ }
1809
+ case 'ftp': {
1257
1810
  const prefix = protocol === 'https' ? 'http' : protocol;
1258
- if (ignoreOpt(`--${prefix}-user`, `--${prefix}-passwd`)) {
1811
+ if (ignoreOpt(binOpts, `--${prefix}-user`, `--${prefix}-passwd`)) {
1259
1812
  if (username) {
1260
- args.push(`--${prefix}-user="${escapeQuote(decodeURIComponent(username))}"`);
1813
+ args.push(`--${prefix}-user="${escapeShellQuote(decodeURIComponent(username))}"`);
1261
1814
  }
1262
1815
  if (password) {
1263
- args.push(`--${prefix}-passwd="${escapeQuote(decodeURIComponent(password))}"`);
1816
+ args.push(`--${prefix}-passwd="${escapeShellQuote(decodeURIComponent(password))}"`);
1264
1817
  }
1265
1818
  }
1266
1819
  const proxy = this.proxyOf(uri);
1267
- if (proxy && ignoreOpt(`--${protocol}-proxy-user`, `--${protocol}-proxy-passwd`)) {
1820
+ if (proxy && ignoreOpt(binOpts, `--${protocol}-proxy-user`, `--${protocol}-proxy-passwd`)) {
1268
1821
  ({ origin, username, password } = proxy.host);
1269
- if (ignoreOpt(`--${protocol}-proxy`)) {
1822
+ if (ignoreOpt(binOpts, `--${protocol}-proxy`)) {
1270
1823
  args.push(`--${protocol}-proxy="${origin}"`);
1271
1824
  }
1272
1825
  if (username) {
1273
- args.push(`--${protocol}-proxy-user="${escapeQuote(decodeURIComponent(username))}"`);
1826
+ args.push(`--${protocol}-proxy-user="${escapeShellQuote(decodeURIComponent(username))}"`);
1274
1827
  }
1275
1828
  if (password) {
1276
- args.push(`--${protocol}-proxy-passwd="${escapeQuote(decodeURIComponent(password))}"`);
1829
+ args.push(`--${protocol}-proxy-passwd="${escapeShellQuote(decodeURIComponent(password))}"`);
1277
1830
  }
1278
1831
  }
1279
1832
  break;
@@ -1291,7 +1844,7 @@ class Request extends module_1 {
1291
1844
  }
1292
1845
  args = binOpts.concat(args);
1293
1846
  }
1294
- if (args.length) {
1847
+ if (args.length > 0) {
1295
1848
  if (module_1.hasLogType(32768)) {
1296
1849
  this.formatMessage(32768, 'ARIA2', ARIA2.BIN, args.join(' '), { ...module_1.LOG_STYLE_WARN });
1297
1850
  }
@@ -1299,7 +1852,7 @@ class Request extends module_1 {
1299
1852
  this.addLog(types_1.STATUS_TYPE.INFO, path.basename(ARIA2.BIN) + ' ' + args.join(' '), "aria2");
1300
1853
  }
1301
1854
  }
1302
- opts.push(`"${escapeQuote(uri)}"`);
1855
+ opts.push(`"${escapeShellQuote(uri)}"`);
1303
1856
  args = args.concat(init, opts);
1304
1857
  const startTime = Date.now();
1305
1858
  let out = '', message = '', aborted;
@@ -1340,29 +1893,31 @@ class Request extends module_1 {
1340
1893
  break;
1341
1894
  }
1342
1895
  case 'ERR':
1343
- fs.unlink(file, err => err && !silent && !this[kSingleton] && this.writeFail(["Unable to delete file", path.basename(file)], err, { type: 32, fatal: false }));
1896
+ fs.unlink(file, err => {
1897
+ if (err && !silent && !this[kSingleton]) {
1898
+ this.writeFail(["Unable to delete file", path.basename(file)], err, { type: 32, fatal: false });
1899
+ }
1900
+ });
1344
1901
  break;
1345
1902
  }
1346
1903
  }
1347
1904
  }
1348
- if (result.length && !silent && LOG_HTTP && LOG_TIMEPROCESS) {
1905
+ if (result.length > 0 && !silent && LOG_HTTP && LOG_TIMEPROCESS) {
1349
1906
  this.writeTimeProcess("aria2", uri, startTime, { type: 1024, queue: true, messageUnit, messageUnitMinWidth: 9, bypassLog: true });
1350
1907
  }
1351
- this.addLog(result.length ? types_1.STATUS_TYPE.INFO : types_1.STATUS_TYPE.ERROR, out, currentTime, currentTime - startTime, "aria2", uri);
1908
+ this.addLog(result.length > 0 ? types_1.STATUS_TYPE.INFO : types_1.STATUS_TYPE.ERROR, out, currentTime, currentTime - startTime, "aria2", uri);
1352
1909
  resolve(result);
1353
1910
  })
1354
- .on('error', err => errorResponse(pid, err));
1911
+ .on('error', err => {
1912
+ errorResponse(pid, err);
1913
+ });
1355
1914
  stdout.setEncoding('utf-8').on('data', (value) => out += value);
1356
1915
  stderr.setEncoding('utf-8').on('data', (value) => message += value);
1357
1916
  if (pid !== undefined && module_1.isFile(uri, 'torrent')) {
1358
1917
  if (!ARIA2.PID_TIMER) {
1359
- const clearTimer = () => {
1360
- clearInterval(ARIA2.PID_TIMER);
1361
- ARIA2.PID_TIMER = null;
1362
- };
1363
1918
  ARIA2.PID_TIMER = setInterval(() => {
1364
1919
  if (ARIA2.PID_QUEUE.length === 0) {
1365
- clearTimer();
1920
+ resetAria2();
1366
1921
  return;
1367
1922
  }
1368
1923
  for (const item of ARIA2.PID_QUEUE) {
@@ -1376,7 +1931,7 @@ class Request extends module_1 {
1376
1931
  if (ARIA2.UPDATE_STATUS && !silent) {
1377
1932
  const item = ARIA2.PID_QUEUE.shift();
1378
1933
  if (!item) {
1379
- clearTimer();
1934
+ resetAria2();
1380
1935
  return;
1381
1936
  }
1382
1937
  if ((!ARIA2.UPDATE_BROADCAST_ONLY || item[2]) && this.host?.logState !== 0) {
@@ -1388,7 +1943,7 @@ class Request extends module_1 {
1388
1943
  const current = (0, types_1.getLogCurrent)();
1389
1944
  progressBar = current?.type === 128 && current.title === "aria2";
1390
1945
  }
1391
- this.formatMessage(128, "aria2", ['Downloading...', (0, types_1.formatTime)(startTime, true)], (PLATFORM_WIN32 ? 'taskkill /f /pid' : 'kill') + ` ${item[0]} -> ` + item[1], { ...module_1.LOG_STYLE_INFO, progressBar, broadcastId: item[2] });
1946
+ this.formatMessage(128, "aria2", ['Downloading...', (0, types_1.formatTime)(startTime, true)], (module_1.PLATFORM_WIN32 ? 'taskkill /f /pid' : 'kill') + ` ${item[0]} -> ` + item[1], { ...module_1.LOG_STYLE_INFO, progressBar, broadcastId: item[2] });
1392
1947
  }
1393
1948
  ARIA2.PID_QUEUE.push(item);
1394
1949
  }
@@ -1407,21 +1962,30 @@ class Request extends module_1 {
1407
1962
  return this.get(uri, options);
1408
1963
  }
1409
1964
  opts(url, options) {
1410
- var _o, _p, _q, _r;
1411
- if (typeof url === 'string') {
1965
+ var _p, _q, _r, _s;
1966
+ const base = this[kBaseURL];
1967
+ if (base) {
1968
+ if (typeof url === 'string') {
1969
+ url = new URL(url, base[0]);
1970
+ }
1971
+ if (!options?.base) {
1972
+ copySearchParams(url, base[0]);
1973
+ }
1974
+ }
1975
+ else if (typeof url === 'string') {
1412
1976
  url = new URL(url);
1413
1977
  }
1414
1978
  let host;
1415
1979
  if (this.host) {
1416
- host = (_o = HTTP.HOST)[_p = url.origin] || (_o[_p] = new host_1(url, HTTP.VERSION));
1980
+ host = (_p = HTTP.HOST)[_q = url.origin] || (_p[_q] = new host_1(url, HTTP.VERSION));
1417
1981
  }
1418
1982
  else {
1419
- host = (_q = this[kHostInfo])[_r = url.origin] || (_q[_r] = new host_1(url, this.httpVersion || 1));
1983
+ host = (_r = this[kHostInfo])[_s = url.origin] || (_r[_s] = new host_1(url, this.httpVersion || 1));
1420
1984
  }
1421
1985
  return { ...options, host, url };
1422
1986
  }
1423
1987
  open(uri, options) {
1424
- var _o, _p;
1988
+ var _p, _q;
1425
1989
  let { host, url, httpVersion, method = 'GET', search, encoding, format, headers, postData, keepAlive, agentTimeout, socketPath, timeout = this._config.connectTimeout, outStream } = options;
1426
1990
  const getting = method === 'GET';
1427
1991
  const posting = method === 'POST';
@@ -1460,15 +2024,33 @@ class Request extends module_1 {
1460
2024
  url = uri;
1461
2025
  uri = url.toString();
1462
2026
  }
2027
+ const base = this[kBaseURL];
1463
2028
  if (!host) {
1464
- ({ host, url } = this.opts(url || uri));
2029
+ ({ host, url } = this.opts(url || uri, { base: options.base }));
1465
2030
  options.host = host;
1466
2031
  options.url = url;
1467
2032
  }
1468
2033
  else if (!url) {
1469
- url = new URL(uri);
2034
+ if (base) {
2035
+ url = new URL(uri, base[0]);
2036
+ if (!options.base) {
2037
+ copySearchParams(url, base[0]);
2038
+ }
2039
+ }
2040
+ else {
2041
+ url = new URL(uri);
2042
+ }
1470
2043
  options.url = url;
1471
2044
  }
2045
+ if (options.base) {
2046
+ this[kBaseURL] = [url, httpVersion, headers];
2047
+ }
2048
+ else if (base) {
2049
+ httpVersion ?? (httpVersion = base[1]);
2050
+ if (base[2]) {
2051
+ headers = { ...base[2], ...headers };
2052
+ }
2053
+ }
1472
2054
  if (search) {
1473
2055
  for (const param in search) {
1474
2056
  url.searchParams.append(param, search[param]);
@@ -1479,18 +2061,18 @@ class Request extends module_1 {
1479
2061
  const pathname = url.pathname + (socketPath ? '' : url.search);
1480
2062
  const proxy = this.proxyOf(uri, localhost);
1481
2063
  const version = this.httpVersion;
1482
- let request, ca, cert, key, minVersion, baseHeaders = this.headersOf(uri);
2064
+ let request, ca, cert, key, ciphers, minVersion, baseHeaders = this.headersOf(uri);
1483
2065
  if (getting && this.acceptEncoding && !localhost && !baseHeaders?.['accept-encoding']) {
1484
- (_o = (headers || (headers = {})))['accept-encoding'] || (_o['accept-encoding'] = 'gzip, deflate, br' + (LIB_ZSTD ? ', zstd' : ''));
2066
+ (_p = (headers || (headers = {})))['accept-encoding'] || (_p['accept-encoding'] = 'gzip, deflate, br' + (LIB_ZSTD ? ', zstd' : ''));
1485
2067
  }
1486
2068
  if (secure) {
1487
2069
  const certs = this[kCerts]?.[0][origin] || this.host && TLS.TEXT[origin];
1488
2070
  if (certs) {
1489
- ({ ca, cert, key, version: minVersion } = certs);
2071
+ ({ ca, cert, key, ciphers, version: minVersion } = certs);
1490
2072
  }
1491
2073
  }
1492
2074
  if (!proxy && httpVersion !== 1 && ((httpVersion || host.version) === 2 && version !== 1 || secure && version === 2 && host.failed(2, true) === 0)) {
1493
- request = ((_p = this[kSession][0])[origin] || (_p[origin] = http2.connect(origin, { lookup: this.lookupDns(hostname), ca, cert, key, minVersion, settings: localhost ? { maxFrameSize: 16777215, enablePush: false } : { enablePush: false } }))).request({ ...baseHeaders, ...host_1.getBasicAuth(url), ...headers, ':path': pathname, ':method': method });
2075
+ request = ((_q = this[kSession][0])[origin] || (_q[origin] = http2.connect(origin, { lookup: this.lookupDns(hostname), ca, cert, key, ciphers, minVersion, settings: localhost ? { maxFrameSize: 16777215, enablePush: false } : { enablePush: false } }))).request({ ...baseHeaders, ...host_1.getBasicAuth(url), ...headers, ':path': pathname, ':method': method });
1494
2076
  if (getting) {
1495
2077
  const listenerMap = {};
1496
2078
  const onEvent = request.on.bind(request);
@@ -1500,21 +2082,24 @@ class Request extends module_1 {
1500
2082
  connected = true;
1501
2083
  const statusCode = response[':status'];
1502
2084
  if (this.matchStatus(statusCode, url, response, request, options) && statusCode >= 200 && statusCode < 300) {
1503
- emitter = checkEncoding(request, request, statusCode, outStream, response['content-encoding']);
1504
- if (emitter) {
2085
+ if (emitter = checkEncoding(request, request, statusCode, outStream, response['content-encoding'])) {
1505
2086
  for (const event in listenerMap) {
1506
- listenerMap[event].forEach(listener => {
1507
- const [name, type] = event.split('-');
2087
+ const [name, type] = event.split('-');
2088
+ for (const listener of listenerMap[event]) {
1508
2089
  if (name !== 'error') {
1509
2090
  request.removeListener(name, listener);
1510
2091
  }
1511
2092
  emitter[type](name === 'end' ? 'finish' : name, listener);
1512
- });
2093
+ }
1513
2094
  }
1514
2095
  }
1515
2096
  else {
1516
2097
  if (outStream) {
1517
- stream.pipeline(request, outStream, err => err && request.emit('error', err));
2098
+ stream.pipeline(request, outStream, err => {
2099
+ if (err) {
2100
+ request.emit('error', err);
2101
+ }
2102
+ });
1518
2103
  }
1519
2104
  if (encoding) {
1520
2105
  request.setEncoding((0, types_1.getEncoding)(encoding));
@@ -1528,7 +2113,7 @@ class Request extends module_1 {
1528
2113
  this.matchHeaders(url, response, request, options);
1529
2114
  });
1530
2115
  request.on = function (event, listener) {
1531
- var _o;
2116
+ var _p;
1532
2117
  switch (event) {
1533
2118
  case 'data':
1534
2119
  case 'error':
@@ -1538,7 +2123,7 @@ class Request extends module_1 {
1538
2123
  break;
1539
2124
  }
1540
2125
  if (!connected) {
1541
- (listenerMap[_o = event + '-on'] || (listenerMap[_o] = [])).push(listener);
2126
+ (listenerMap[_p = event + '-on'] || (listenerMap[_p] = [])).push(listener);
1542
2127
  }
1543
2128
  default:
1544
2129
  onEvent(event, listener);
@@ -1547,7 +2132,7 @@ class Request extends module_1 {
1547
2132
  return this;
1548
2133
  };
1549
2134
  request.once = function (event, listener) {
1550
- var _o;
2135
+ var _p;
1551
2136
  switch (event) {
1552
2137
  case 'data':
1553
2138
  case 'error':
@@ -1557,7 +2142,7 @@ class Request extends module_1 {
1557
2142
  break;
1558
2143
  }
1559
2144
  if (!connected) {
1560
- (listenerMap[_o = event + '-once'] || (listenerMap[_o] = [])).push(listener);
2145
+ (listenerMap[_p = event + '-once'] || (listenerMap[_p] = [])).push(listener);
1561
2146
  }
1562
2147
  default:
1563
2148
  onceEvent(event, listener);
@@ -1593,10 +2178,9 @@ class Request extends module_1 {
1593
2178
  agent = new (secure ? https.Agent : http.Agent)({ keepAlive: true, timeout: agentTimeout });
1594
2179
  }
1595
2180
  else if (agentTimeout !== 0) {
1596
- keepAlive = this.keepAlive || false;
1597
2181
  agentTimeout ?? (agentTimeout = this.agentTimeout);
1598
- if (keepAlive || agentTimeout > 0) {
1599
- agent = new (secure ? https.Agent : http.Agent)({ keepAlive, timeout: agentTimeout });
2182
+ if (this.keepAlive !== null || agentTimeout > 0) {
2183
+ agent = new (secure ? https.Agent : http.Agent)({ keepAlive: this.keepAlive ?? true, timeout: agentTimeout });
1600
2184
  }
1601
2185
  }
1602
2186
  }
@@ -1613,6 +2197,7 @@ class Request extends module_1 {
1613
2197
  ca,
1614
2198
  cert,
1615
2199
  key,
2200
+ ciphers,
1616
2201
  minVersion,
1617
2202
  headers,
1618
2203
  lookup: this.lookupDns(hostname),
@@ -1645,12 +2230,22 @@ class Request extends module_1 {
1645
2230
  source = response;
1646
2231
  }
1647
2232
  response
1648
- .on('close', () => request.emit('close'))
1649
- .on('error', err => request.emit('error', err))
1650
- .once('readable', () => request.emit('readable'));
1651
- source.on('data', chunk => request.emit('data', chunk));
2233
+ .on('close', () => {
2234
+ request.emit('close');
2235
+ })
2236
+ .on('error', err => {
2237
+ request.emit('error', err);
2238
+ })
2239
+ .once('readable', () => {
2240
+ request.emit('readable');
2241
+ });
2242
+ source.on('data', chunk => {
2243
+ request.emit('data', chunk);
2244
+ });
1652
2245
  if (response !== source) {
1653
- source.on('error', err => request.emit('error', err));
2246
+ source.on('error', err => {
2247
+ request.emit('error', err);
2248
+ });
1654
2249
  }
1655
2250
  if (!posting) {
1656
2251
  if (version === 2 && incoming.upgrade?.includes('h2')) {
@@ -1666,9 +2261,15 @@ class Request extends module_1 {
1666
2261
  }
1667
2262
  else {
1668
2263
  response
1669
- .on('close', () => request.emit('close'))
1670
- .on('error', err => request.emit('error', err))
1671
- .once('end', () => request.emit('end'));
2264
+ .on('close', () => {
2265
+ request.emit('close');
2266
+ })
2267
+ .on('error', err => {
2268
+ request.emit('error', err);
2269
+ })
2270
+ .once('end', () => {
2271
+ request.emit('end');
2272
+ });
1672
2273
  }
1673
2274
  if (this._config.timeout) {
1674
2275
  response.setTimeout(this._config.timeout, () => request.emit('timeout'));
@@ -1684,7 +2285,9 @@ class Request extends module_1 {
1684
2285
  const ac = new AbortController();
1685
2286
  this[kDownloading].add(options.outAbort = ac);
1686
2287
  stream.addAbortSignal(ac.signal, request);
1687
- this.signal.addEventListener('abort', () => ac.abort(new Error("Aborted by process")), { once: true });
2288
+ this.signal.addEventListener('abort', () => {
2289
+ ac.abort(new Error("Aborted by process"));
2290
+ }, { once: true });
1688
2291
  }
1689
2292
  if (posting) {
1690
2293
  if ((0, types_1.isString)(postData) || Buffer.isBuffer(postData)) {
@@ -1744,7 +2347,7 @@ class Request extends module_1 {
1744
2347
  let valid;
1745
2348
  if ((0, types_1.isArray)(parts)) {
1746
2349
  const write = combined.create();
1747
- const boundary = (0, types_1.generateUUID)().replace(/-/g, '');
2350
+ const boundary = crypto.randomUUID().replaceAll('-', '');
1748
2351
  contentType = "multipart/form-data" + `; boundary="${boundary}"`;
1749
2352
  let contentLength = 0;
1750
2353
  const createPart = (name, filename, type) => {
@@ -1761,7 +2364,6 @@ class Request extends module_1 {
1761
2364
  contentLength += Buffer.byteLength(disposition);
1762
2365
  }
1763
2366
  };
1764
- const escapeQuote = (value) => value.replace(/[\\"]/g, capture => '\\' + capture);
1765
2367
  if ((0, types_1.isPlainObject)(data)) {
1766
2368
  for (const name in data) {
1767
2369
  addValue(name, data[name]);
@@ -1772,46 +2374,41 @@ class Request extends module_1 {
1772
2374
  continue;
1773
2375
  }
1774
2376
  if (target) {
1775
- try {
1776
- if (typeof target === 'string') {
1777
- filename || (filename = path.basename(target));
1778
- type || (type = module_1.lookupMime(filename));
1779
- target = fs.readFileSync(target);
2377
+ if (typeof target === 'string') {
2378
+ filename || (filename = path.basename(target));
2379
+ type || (type = module_1.lookupMime(filename));
2380
+ target = fs.readFileSync(target);
2381
+ }
2382
+ else if (target instanceof stream.Readable) {
2383
+ const chunks = [];
2384
+ for await (const chunk of target) {
2385
+ chunks.push(chunk);
1780
2386
  }
1781
- else if (target instanceof stream.Readable) {
1782
- const chunks = [];
1783
- for await (const chunk of target) {
1784
- chunks.push(chunk);
1785
- }
1786
- target = Buffer.concat(chunks);
2387
+ target = Buffer.concat(chunks);
2388
+ }
2389
+ if (!Buffer.isBuffer(target)) {
2390
+ throw (0, types_1.errorMessage)('File', "Unknown", "multipart/form-data");
2391
+ }
2392
+ if (!type || !filename) {
2393
+ const result = await module_1.resolveMime(target);
2394
+ let ext;
2395
+ if (result) {
2396
+ type || (type = result.mime);
2397
+ ext = result.ext;
1787
2398
  }
1788
- if (!Buffer.isBuffer(target)) {
1789
- throw (0, types_1.errorMessage)('File', "Unknown", "multipart/form-data");
2399
+ else if (type) {
2400
+ ext = module_1.lookupMime(type, true);
1790
2401
  }
1791
- if (!type || !filename) {
1792
- const result = await module_1.resolveMime(target);
1793
- let ext;
1794
- if (result) {
1795
- type || (type = result.mime);
1796
- ext = result.ext;
1797
- }
1798
- else if (type) {
1799
- ext = module_1.lookupMime(type, true);
1800
- }
1801
- if (ext && !filename) {
1802
- filename = (0, types_1.generateUUID)() + '.' + ext;
1803
- }
2402
+ if (ext && !filename) {
2403
+ filename = crypto.randomUUID() + '.' + ext;
1804
2404
  }
1805
- const disposition = createPart(name, filename, type || "application/octet-stream");
1806
- write.append(disposition);
1807
- write.append(target);
1808
- write.append("\r\n");
1809
- contentLength += Buffer.byteLength(disposition) + target.length + 2;
1810
- valid = true;
1811
- }
1812
- catch (err) {
1813
- return Promise.reject(err);
1814
2405
  }
2406
+ const disposition = createPart(name, filename, type || "application/octet-stream");
2407
+ write.append(disposition);
2408
+ write.append(target);
2409
+ write.append("\r\n");
2410
+ contentLength += Buffer.byteLength(disposition) + target.length + 2;
2411
+ valid = true;
1815
2412
  }
1816
2413
  else {
1817
2414
  addValue(name, value);
@@ -1854,437 +2451,7 @@ class Request extends module_1 {
1854
2451
  if (this.readExpect === 'string') {
1855
2452
  opts.encoding = (0, types_1.getEncoding)(opts.encoding);
1856
2453
  }
1857
- return new Promise((resolve, reject) => {
1858
- const pipeTo = opts.pipeTo;
1859
- const status = opts.silent === false || !opts.silent && !this[kSingleton];
1860
- let log = status && LOG_HTTP && LOG_TIMEPROCESS, retries = 0, redirects = 0, closed, timeout, outStream;
1861
- const startTime = log ? process.hrtime() : 0;
1862
- const throwError = (err, outAbort) => {
1863
- if (timeout) {
1864
- clearTimeout(timeout);
1865
- }
1866
- if (!closed) {
1867
- closed = true;
1868
- if (outStream && (0, types_1.isString)(pipeTo)) {
1869
- (0, util_1.cleanupStream)(outStream, pipeTo);
1870
- }
1871
- reject(typeof err === 'string' ? new Error(err) : err);
1872
- }
1873
- if (outAbort) {
1874
- this[kDownloading].delete(outAbort);
1875
- }
1876
- };
1877
- const formatStatus = (value, hint) => value + ': ' + (hint || Request.fromStatusCode(value)) + ` (${uri.toString()})`;
1878
- (function downloadUri(href, httpVersion) {
1879
- let outAbort;
1880
- try {
1881
- const request = this.opts(href, opts);
1882
- if (outStream && (0, types_1.isString)(pipeTo)) {
1883
- (0, util_1.cleanupStream)(outStream, pipeTo);
1884
- }
1885
- if (pipeTo) {
1886
- if (typeof pipeTo === 'string') {
1887
- outStream = fs.createWriteStream(pipeTo, { emitClose: false, highWaterMark: request.host.localhost ? 65536 : 4096 });
1888
- request.outStream = outStream;
1889
- }
1890
- else {
1891
- request.outStream = pipeTo;
1892
- }
1893
- }
1894
- if (httpVersion) {
1895
- request.httpVersion = httpVersion;
1896
- }
1897
- const client = this.open(href, request);
1898
- const { host, url, encoding, progressId, outFormat } = request;
1899
- let buffer, aborted;
1900
- ({ httpVersion, outAbort } = request);
1901
- const isAborted = () => client.destroyed || httpVersion === 2 && client.aborted;
1902
- const isRetry = (value) => (0, util_1.isRetryable)(value) && ++retries <= this._config.retryLimit;
1903
- const isUnsupported = (value) => value === 421 || value === 505;
1904
- const isDowngrade = (err) => err instanceof Error && (err.code === 'ERR_HTTP2_ERROR' || isUnsupported(Math.abs(err.errno)));
1905
- const wasAborted = (err) => err instanceof Error && err.message.startsWith("Aborted");
1906
- const sendWarning = (message) => status && LOG_HTTP && this.formatMessage(1024, 'HTTP' + httpVersion, [message, host.origin], url.toString(), { ...module_1.LOG_STYLE_WARN });
1907
- const formatRetry = (message) => message + ` (${retries} / ${this._config.retryLimit})`;
1908
- const formatNgFlags = (value, statusCode, location) => location ? `Using HTTP 1.1 for URL redirect (${location})` : formatStatus(statusCode, value ? 'NGHTTP2 Error ' + value : '');
1909
- const abortResponse = () => {
1910
- if (closed) {
1911
- return;
1912
- }
1913
- if (timeout) {
1914
- clearTimeout(timeout);
1915
- }
1916
- buffer = null;
1917
- aborted = true;
1918
- if (outAbort) {
1919
- if (!client.aborted) {
1920
- outAbort.abort();
1921
- }
1922
- this[kDownloading].delete(outAbort);
1923
- }
1924
- client.destroy();
1925
- };
1926
- const retryTimeout = () => {
1927
- sendWarning(formatRetry('Connection timeout'));
1928
- downloadUri.call(this, href);
1929
- };
1930
- const acceptResponse = (headers) => {
1931
- if ('outHeaders' in opts) {
1932
- opts.outHeaders = headers;
1933
- }
1934
- if ('outFilename' in opts) {
1935
- opts.outFilename = (0, util_1.parseHeader)(headers, 'content-disposition');
1936
- }
1937
- const pipeline = pipeTo ? !(0, types_1.isString)(pipeTo) : false;
1938
- const enabled = request.connected?.call(client, headers) !== false && !pipeline;
1939
- const maxBufferSize = request.maxBufferSize ? (0, types_1.alignSize)(request.maxBufferSize) : 0;
1940
- const { host: parent, readTimeout } = this;
1941
- const contentLength = parent && progressId !== undefined ? parseInt(headers['content-length'] || '0') : 0;
1942
- let dataLength = 0, mibsTime, delayTime;
1943
- if (log || readTimeout > 0 || contentLength > 0) {
1944
- client.once('readable', () => {
1945
- if (readTimeout > 0) {
1946
- timeout = setTimeout(() => {
1947
- abortResponse();
1948
- throwError((0, types_1.errorValue)("Timeout was exceeded", href.toString()));
1949
- }, readTimeout);
1950
- }
1951
- if (log) {
1952
- switch (this.settings.time_format || LOG_TIMEFORMAT) {
1953
- case 'readable':
1954
- delayTime = process.hrtime(startTime);
1955
- break;
1956
- case 'relative':
1957
- delayTime = Date.now() - this.startTime;
1958
- break;
1959
- case 'none':
1960
- if (opts.silent !== false) {
1961
- log = false;
1962
- }
1963
- break;
1964
- }
1965
- }
1966
- mibsTime = process.hrtime();
1967
- if (contentLength > 0) {
1968
- parent.updateProgress("request", progressId, 0, 0, mibsTime);
1969
- }
1970
- });
1971
- }
1972
- if (enabled) {
1973
- client.on('data', (chunk) => {
1974
- if (buffer) {
1975
- if (typeof buffer === 'string') {
1976
- buffer += typeof chunk === 'string' ? chunk : chunk.toString(encoding);
1977
- }
1978
- else if (Array.isArray(buffer)) {
1979
- buffer.push(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk);
1980
- }
1981
- else {
1982
- buffer = Buffer.concat([buffer, typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk]);
1983
- }
1984
- }
1985
- else {
1986
- buffer = typeof chunk === 'string' ? chunk : [chunk];
1987
- }
1988
- if (contentLength > 0) {
1989
- dataLength += Buffer.byteLength(chunk, encoding);
1990
- parent.updateProgress("request", progressId, dataLength, contentLength);
1991
- }
1992
- if (maxBufferSize > 0) {
1993
- if (contentLength === 0) {
1994
- dataLength += Buffer.byteLength(chunk, encoding);
1995
- }
1996
- if (dataLength > maxBufferSize) {
1997
- abortResponse();
1998
- throwError((0, types_1.errorValue)("Size limit was exceeded", href.toString()));
1999
- }
2000
- }
2001
- });
2002
- }
2003
- client.once('end', () => {
2004
- if (closed || aborted) {
2005
- return;
2006
- }
2007
- if (timeout) {
2008
- clearTimeout(timeout);
2009
- }
2010
- if (outAbort) {
2011
- this[kDownloading].delete(outAbort);
2012
- }
2013
- closed = true;
2014
- let result, messageUnit, titleBgColor;
2015
- if (buffer) {
2016
- if (Array.isArray(buffer)) {
2017
- buffer = Buffer.concat(buffer);
2018
- if (encoding) {
2019
- buffer = buffer.toString(encoding);
2020
- }
2021
- }
2022
- dataLength = Buffer.byteLength(buffer, encoding);
2023
- if (mibsTime) {
2024
- messageUnit = (0, util_1.getTransferRate)(dataLength, (0, types_1.convertTime)(process.hrtime(mibsTime), false) * 1000);
2025
- }
2026
- if (contentLength > 0) {
2027
- parent.updateProgress("request", progressId, dataLength, dataLength);
2028
- }
2029
- if (typeof buffer === 'string') {
2030
- if (buffer.startsWith('\uFEFF') && encoding !== 'utf16le' && encoding !== 'utf-16le') {
2031
- buffer = buffer.substring(1);
2032
- }
2033
- if (outFormat) {
2034
- const { out: format, parser } = outFormat;
2035
- let packageName;
2036
- try {
2037
- switch (format) {
2038
- case 'yaml':
2039
- result = yaml.load(buffer, parser);
2040
- break;
2041
- case 'json5':
2042
- result = require(packageName = 'json5').parse(buffer);
2043
- break;
2044
- case 'xml':
2045
- result = new (require(packageName = 'fast-xml-parser').XMLParser)(parser).parse(buffer);
2046
- break;
2047
- case 'toml':
2048
- result = require(packageName = 'toml').parse(buffer);
2049
- break;
2050
- default:
2051
- result = JSON.parse(buffer);
2052
- break;
2053
- }
2054
- if (!(0, types_1.isObject)(result)) {
2055
- result = null;
2056
- }
2057
- }
2058
- catch (err) {
2059
- if (status && !(packageName && this.checkPackage(err, packageName))) {
2060
- this.writeFail(['Unable to parse URI response', format], err, 1024);
2061
- }
2062
- result = null;
2063
- }
2064
- }
2065
- }
2066
- if (result === undefined) {
2067
- result = buffer;
2068
- }
2069
- }
2070
- else {
2071
- if (contentLength > 0) {
2072
- parent.updateProgress("request", progressId, 0, contentLength);
2073
- }
2074
- if (enabled && this.readExpect === 'always') {
2075
- throwError('No data received');
2076
- return;
2077
- }
2078
- result = encoding && !pipeline ? '' : null;
2079
- titleBgColor = 'bgBlue';
2080
- }
2081
- if (log) {
2082
- this.writeTimeProcess('HTTP' + httpVersion, request.statusMessage || url.toString(), startTime, { type: 1024, queue: !!this.host, titleBgColor, messageUnit, messageUnitMinWidth: 9, delayTime, bypassLog: LOG_STDOUT });
2083
- }
2084
- resolve(result);
2085
- });
2086
- host.success(httpVersion);
2087
- };
2088
- const redirectResponse = (statusCode, location) => {
2089
- abortResponse();
2090
- if (location) {
2091
- if (request.follow_redirect === false) {
2092
- throwError(formatStatus(statusCode, 'Follow redirect was disabled'));
2093
- }
2094
- else if (++redirects <= this._config.redirectLimit) {
2095
- downloadUri.call(this, Request.fromURL(url, location));
2096
- }
2097
- else {
2098
- throwError(formatStatus(statusCode, 'Exceeded redirect limit'));
2099
- }
2100
- }
2101
- else {
2102
- throwError(formatStatus(statusCode, 'Missing redirect location'));
2103
- }
2104
- };
2105
- const errorResponse = (err) => {
2106
- abortResponse();
2107
- if (wasAborted(err)) {
2108
- throwError(err);
2109
- }
2110
- else if ((0, util_1.checkRetryable)(err) && ++retries <= this._config.retryLimit) {
2111
- if (isConnectionTimeout(err)) {
2112
- retryTimeout();
2113
- }
2114
- else {
2115
- setTimeout(() => downloadUri.call(this, href), this._config.retryWait);
2116
- }
2117
- }
2118
- else {
2119
- host.error(httpVersion);
2120
- throwError(err);
2121
- }
2122
- };
2123
- const retryResponse = (statusCode, retryAfter) => {
2124
- abortResponse();
2125
- if (retryAfter && this._config.retryAfter > 0) {
2126
- let offset = +retryAfter || new Date(retryAfter);
2127
- if (offset instanceof Date) {
2128
- offset = Math.max(0, offset.getTime() - Date.now());
2129
- }
2130
- else {
2131
- offset *= 1000;
2132
- }
2133
- if (offset > 0) {
2134
- if (offset <= this._config.retryAfter) {
2135
- sendWarning(`Retry After (${retryAfter})`);
2136
- setTimeout(() => downloadUri.call(this, href), offset);
2137
- }
2138
- else {
2139
- throwError(formatStatus(statusCode));
2140
- }
2141
- return;
2142
- }
2143
- }
2144
- sendWarning(formatRetry(Request.fromStatusCode(statusCode)));
2145
- if ((0, util_1.isRetryable)(statusCode, true)) {
2146
- process.nextTick(downloadUri.bind(this), href);
2147
- }
2148
- else {
2149
- setTimeout(() => downloadUri.call(this, href), this._config.retryWait);
2150
- }
2151
- };
2152
- if (httpVersion === 2) {
2153
- const retryDownload = (downgrade, message) => {
2154
- if (aborted) {
2155
- return;
2156
- }
2157
- abortResponse();
2158
- if (downgrade) {
2159
- host.failed(2);
2160
- if (host.version > 1) {
2161
- if (status && LOG_HTTP) {
2162
- this.formatMessage(1024, 'HTTP2', ['Unsupported protocol', host.origin], message, { failed: true });
2163
- }
2164
- host.version = 1;
2165
- }
2166
- }
2167
- downloadUri.call(this, href, 1);
2168
- };
2169
- client
2170
- .on('response', (headers, flags) => {
2171
- if (isAborted()) {
2172
- return;
2173
- }
2174
- const statusCode = headers[':status'];
2175
- if (statusCode < 300) {
2176
- acceptResponse(headers);
2177
- }
2178
- else if (statusCode < 400) {
2179
- redirectResponse(statusCode, headers.location);
2180
- }
2181
- else if (statusCode === 401 ||
2182
- statusCode === 402 ||
2183
- statusCode === 403 ||
2184
- statusCode === 404 ||
2185
- statusCode === 407 ||
2186
- statusCode === 410) {
2187
- throwError(formatStatus(statusCode), outAbort);
2188
- }
2189
- else if (isRetry(statusCode)) {
2190
- retryResponse(statusCode, headers['retry-after']);
2191
- }
2192
- else if (isUnsupported(statusCode)) {
2193
- retryDownload(true, formatNgFlags(http2.constants.NGHTTP2_PROTOCOL_ERROR, statusCode));
2194
- }
2195
- else {
2196
- switch (flags) {
2197
- case http2.constants.NGHTTP2_PROTOCOL_ERROR:
2198
- case http2.constants.NGHTTP2_INADEQUATE_SECURITY:
2199
- case http2.constants.NGHTTP2_HTTP_1_1_REQUIRED:
2200
- retryDownload(true, formatNgFlags(flags, statusCode, headers.location));
2201
- break;
2202
- default:
2203
- retryDownload(false, formatStatus(statusCode));
2204
- break;
2205
- }
2206
- }
2207
- })
2208
- .on('unknownProtocol', () => {
2209
- if (!aborted) {
2210
- retryDownload(true, 'Unknown protocol (HTTP/2)');
2211
- }
2212
- })
2213
- .on('aborted', () => {
2214
- aborted = true;
2215
- throwError((0, types_1.createAbortError)(), outAbort);
2216
- })
2217
- .on('error', async (err) => {
2218
- if (aborted) {
2219
- return;
2220
- }
2221
- if (wasAborted(err)) {
2222
- errorResponse(err);
2223
- }
2224
- else {
2225
- switch (!isDowngrade(err) && await host.hasProtocol(2)) {
2226
- case 1:
2227
- errorResponse(err);
2228
- break;
2229
- case 2:
2230
- retryDownload(false, err);
2231
- break;
2232
- default:
2233
- retryDownload(true, err);
2234
- break;
2235
- }
2236
- }
2237
- });
2238
- }
2239
- else {
2240
- client
2241
- .on('response', res => {
2242
- if (isAborted()) {
2243
- return;
2244
- }
2245
- const statusCode = res.statusCode;
2246
- if (statusCode < 300) {
2247
- acceptResponse(res.headers);
2248
- }
2249
- else if (statusCode < 400) {
2250
- redirectResponse(statusCode, res.headers.location);
2251
- }
2252
- else if (isRetry(statusCode)) {
2253
- retryResponse(statusCode, res.headers['retry-after']);
2254
- }
2255
- else {
2256
- abortResponse();
2257
- throwError(formatStatus(statusCode));
2258
- }
2259
- })
2260
- .on('abort', () => {
2261
- aborted = true;
2262
- throwError((0, types_1.createAbortError)(), outAbort);
2263
- })
2264
- .on('error', err => {
2265
- if (!aborted) {
2266
- errorResponse(err);
2267
- }
2268
- });
2269
- }
2270
- client.on('timeout', () => {
2271
- if (aborted) {
2272
- return;
2273
- }
2274
- abortResponse();
2275
- if (++retries <= this._config.retryLimit) {
2276
- retryTimeout();
2277
- }
2278
- else {
2279
- throwError(formatStatus(408));
2280
- }
2281
- });
2282
- }
2283
- catch (err) {
2284
- throwError(err, outAbort);
2285
- }
2286
- }).bind(this)(uri);
2287
- });
2454
+ return new Fetch(this, uri, opts).start();
2288
2455
  }
2289
2456
  reset() {
2290
2457
  this[kPendingDns] = Object.create(null);
@@ -2393,10 +2560,9 @@ class Request extends module_1 {
2393
2560
  return this[kIpVersion];
2394
2561
  }
2395
2562
  get settings() {
2396
- var _o;
2397
- return (_o = this.module).settings || (_o.settings = {});
2563
+ var _p;
2564
+ return (_p = this.module).settings || (_p.settings = {});
2398
2565
  }
2399
2566
  }
2400
- _a = kSingleton, _b = kHttpVersion, _c = kHeaders, _d = kCerts, _e = kConnectDns, _f = kPendingDns, _g = kConnectHttp, _h = kStatusOn, _j = kHeadersOn, _k = kDownloading, _l = kHostInfo, _m = kSession;
2401
-
2567
+ _a = kSingleton, _b = kHttpVersion, _c = kHeaders, _d = kCerts, _e = kBaseURL, _f = kConnectDns, _g = kPendingDns, _h = kConnectHttp, _j = kStatusOn, _k = kHeadersOn, _l = kDownloading, _m = kHostInfo, _o = kSession;
2402
2568
  module.exports = Request;