@e-mc/request 0.9.7 → 0.10.0

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