@e-mc/request 0.10.5 → 0.11.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,25 +1,25 @@
1
1
  "use strict";
2
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
3
- const path = require("path");
4
- const fs = require("fs");
5
- const crypto = require("crypto");
6
- const child_process = require("child_process");
7
- const http = require("http");
8
- const https = require("https");
9
- const http2 = require("http2");
10
- const dns = require("dns");
11
- const net = require("net");
12
- const stream = require("stream");
13
- const zlib = require("zlib");
2
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
3
+ const path = require("node:path");
4
+ const fs = require("node:fs");
5
+ const crypto = require("node:crypto");
6
+ const child_process = require("node:child_process");
7
+ const http = require("node:http");
8
+ const https = require("node:https");
9
+ const http2 = require("node:http2");
10
+ const dns = require("node:dns");
11
+ const net = require("node:net");
12
+ const stream = require("node:stream");
13
+ const zlib = require("node:zlib");
14
14
  const qs = require("node:querystring");
15
15
  const combined = require("combined-stream");
16
16
  const pm = require("picomatch");
17
- const yaml = require("js-yaml");
18
17
  const which = require("which");
19
18
  const types_1 = require("@e-mc/types");
20
19
  const module_1 = require("@e-mc/module");
21
20
  const util_1 = require("@e-mc/request/util");
22
21
  const host_1 = require("@e-mc/request/http/host");
22
+ const adapter_1 = require("@e-mc/request/http/adapter");
23
23
  const kSession = Symbol('session');
24
24
  const kHttpVersion = Symbol('httpVersion');
25
25
  const kIpVersion = Symbol('ipVersion');
@@ -35,6 +35,7 @@ const kPendingDns = Symbol('pendingDns');
35
35
  const kConnectHttp = Symbol('connectHttp');
36
36
  const kStatusOn = Symbol('statusOn');
37
37
  const kHeadersOn = Symbol('headersOn');
38
+ const kAdapter = Symbol('adapter');
38
39
  const SUPPORTED_NODE20 = (0, types_1.supported)(20);
39
40
  const REGEXP_PEMCERT = /^-{3,}[ \t]*BEGIN[ \t].+\n-{3,}[ \t]*END[ \t][^-]+-{3,}$/s;
40
41
  const REGEXP_GLOBWITHIN = /\\\?|(?:(?<!\\)(?:\*|\[!?[^!\]]+\]|\{(?:[^,]+,)+[^}]+\}|[!?+*@]\((?:[^|]+\|)*[^)]+\)|\?.*\?|\?$))/;
@@ -75,14 +76,13 @@ const ARIA2 = {
75
76
  FILE_ALLOCATION: 'none',
76
77
  CONF_PATH: ''
77
78
  };
79
+ let HTTP_ADAPTER = adapter_1;
78
80
  let KEEP_ALIVE = null;
79
81
  let ACCEPT_ENCODING = false;
80
82
  let READ_TIMEOUT = 0;
81
83
  let AGENT_TIMEOUT = 0;
82
84
  let LOG_HTTP = false;
83
85
  let LOG_TIMEPROCESS = true;
84
- let LOG_STDOUT = true;
85
- let LOG_TIMEFORMAT = 'readable';
86
86
  let LIB_ZSTD = null;
87
87
  try {
88
88
  require('zstd-codec/lib/zstd-stream').run(codec => {
@@ -92,8 +92,8 @@ try {
92
92
  catch {
93
93
  }
94
94
  function getBaseHeaders(uri, headers) {
95
- uri = (0, util_1.trimPath)(uri);
96
95
  let result;
96
+ uri = (0, util_1.trimPath)(uri);
97
97
  for (const pathname in headers) {
98
98
  if (pathname === uri || uri.startsWith(pathname + '/')) {
99
99
  (result ||= []).push([pathname, headers[pathname]]);
@@ -331,8 +331,8 @@ function decompressEncoding(value, chunkSize) {
331
331
  break;
332
332
  }
333
333
  }
334
- function abortHeaders(href, request, options, statusCode = '') {
335
- const reason = (0, types_1.errorMessage)(statusCode, "Aborted by client", href);
334
+ function abortHeaders(href, request, options, statusCode = '', message) {
335
+ const reason = (0, types_1.errorMessage)(statusCode, message || "Aborted by client", href);
336
336
  const outAbort = options.outAbort;
337
337
  if (outAbort) {
338
338
  outAbort.abort(reason);
@@ -346,7 +346,7 @@ function resetAria2() {
346
346
  }
347
347
  function escapeShellQuote(value) {
348
348
  value = value.replaceAll('"', '\\"');
349
- return module_1.PLATFORM_WIN32 ? value : value.replace(/[ $`]/g, capture => (capture !== ' ' ? '\\' : '') + '\\' + capture);
349
+ return module_1.PLATFORM_WIN32 ? value : value.replace(/[ $`;]/g, capture => (capture !== ' ' ? '\\' : '') + '\\' + capture);
350
350
  }
351
351
  function failedDns(err, pending) {
352
352
  for (const cb of pending) {
@@ -375,523 +375,10 @@ function successDns(instance, value, pending, connected) {
375
375
  }
376
376
  pending.length = 0;
377
377
  }
378
+ const isFunction = (value) => typeof value === 'function';
378
379
  const configureDns = (family, options) => family === 0 ? options : { family, hints: family === 6 ? dns.V4MAPPED : 0 };
379
380
  const ignoreOpt = (opts, ...values) => !opts?.some(item => values.includes(item));
380
381
  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.resolve = resolve;
417
- this.reject = reject;
418
- this.init();
419
- });
420
- }
421
- init() {
422
- this.aborted = false;
423
- this.setWriteStream();
424
- const config = this.config;
425
- const client = this.instance.open(this.uri, config);
426
- this.client = client;
427
- if (config.httpVersion === 2) {
428
- client
429
- .on('response', (headers, flags) => {
430
- if (this.destroyed) {
431
- return;
432
- }
433
- const statusCode = headers[':status'];
434
- if (statusCode < 300) {
435
- this.acceptResponse(headers);
436
- }
437
- else if (statusCode < 400) {
438
- this.redirectResponse(statusCode, headers.location);
439
- }
440
- else if (statusCode === 401 ||
441
- statusCode === 402 ||
442
- statusCode === 403 ||
443
- statusCode === 404 ||
444
- statusCode === 407 ||
445
- statusCode === 410) {
446
- this.terminate(this.formatStatus(statusCode));
447
- }
448
- else if (this.isRetry(statusCode)) {
449
- this.retryResponse(statusCode, headers['retry-after']);
450
- }
451
- else if (Fetch.isUnsupported(statusCode)) {
452
- this.retryDownload(true, this.formatNgFlags(http2.constants.NGHTTP2_PROTOCOL_ERROR, statusCode));
453
- }
454
- else {
455
- switch (flags) {
456
- case http2.constants.NGHTTP2_PROTOCOL_ERROR:
457
- case http2.constants.NGHTTP2_INADEQUATE_SECURITY:
458
- case http2.constants.NGHTTP2_HTTP_1_1_REQUIRED:
459
- this.retryDownload(true, this.formatNgFlags(flags, statusCode, headers.location));
460
- break;
461
- default:
462
- this.retryDownload(false, this.formatStatus(statusCode));
463
- break;
464
- }
465
- }
466
- })
467
- .on('unknownProtocol', () => {
468
- if (!this.aborted) {
469
- this.retryDownload(true, 'Unknown protocol (HTTP/2)');
470
- }
471
- })
472
- .on('aborted', () => {
473
- this.aborted = true;
474
- this.terminate((0, types_1.createAbortError)());
475
- })
476
- .on('error', async (err) => {
477
- if (this.aborted) {
478
- return;
479
- }
480
- if (Fetch.wasAborted(err)) {
481
- this.errorResponse(err);
482
- }
483
- else {
484
- switch (!Fetch.isDowngrade(err) && await config.host.hasProtocol(2)) {
485
- case 1:
486
- this.errorResponse(err);
487
- break;
488
- case 2:
489
- this.retryDownload(false, err);
490
- break;
491
- default:
492
- this.retryDownload(true, err);
493
- break;
494
- }
495
- }
496
- });
497
- }
498
- else {
499
- client
500
- .on('response', res => {
501
- if (this.destroyed) {
502
- return;
503
- }
504
- const statusCode = res.statusCode;
505
- if (statusCode < 300) {
506
- this.acceptResponse(res.headers);
507
- }
508
- else if (statusCode < 400) {
509
- this.redirectResponse(statusCode, res.headers.location);
510
- }
511
- else if (this.isRetry(statusCode)) {
512
- this.retryResponse(statusCode, res.headers['retry-after']);
513
- }
514
- else {
515
- this.terminate(this.formatStatus(statusCode));
516
- }
517
- })
518
- .on('abort', () => {
519
- this.aborted = true;
520
- this.terminate((0, types_1.createAbortError)());
521
- })
522
- .on('error', err => {
523
- if (!this.aborted) {
524
- this.errorResponse(err);
525
- }
526
- });
527
- }
528
- client.on('timeout', () => {
529
- if (this.aborted) {
530
- return;
531
- }
532
- if (++this.retries <= this.retryLimit) {
533
- this.abortResponse();
534
- this.retryTimeout();
535
- }
536
- else {
537
- this.terminate(this.formatStatus(408));
538
- }
539
- });
540
- }
541
- setConfig(uri) {
542
- this.uri = uri;
543
- this.config = this.instance.opts(uri, this.opts);
544
- }
545
- setWriteStream() {
546
- const pipeTo = this.pipeTo;
547
- if (typeof pipeTo === 'string') {
548
- try {
549
- this.outStream = fs.createWriteStream(pipeTo, { emitClose: false, highWaterMark: this.config.host.streamSize });
550
- this.config.outStream = this.outStream;
551
- }
552
- catch (err) {
553
- this.terminate(err);
554
- }
555
- }
556
- else {
557
- this.config.outStream = pipeTo;
558
- }
559
- }
560
- abortResponse() {
561
- if (this.closed) {
562
- return;
563
- }
564
- if (this.timeout) {
565
- clearTimeout(this.timeout);
566
- }
567
- this.aborted = true;
568
- this.client.destroy();
569
- this.cleanup();
570
- }
571
- retryDownload(downgrade, message) {
572
- if (this.aborted) {
573
- return;
574
- }
575
- this.abortResponse();
576
- if (downgrade) {
577
- const host = this.config.host;
578
- host.failed(2);
579
- if (host.version > 1) {
580
- if (this.status) {
581
- this.instance.formatMessage(1024, 'HTTP2', ["Unsupported protocol", host.origin], message, { failed: true });
582
- }
583
- host.version = 1;
584
- }
585
- }
586
- this.opts.httpVersion = 1;
587
- this.init();
588
- }
589
- acceptResponse(headers) {
590
- const { instance, config, client, opts, pipeTo } = this;
591
- const parent = this.instance.host;
592
- const progressId = config.progressId;
593
- if ('outHeaders' in opts) {
594
- opts.outHeaders = headers;
595
- }
596
- if ('outFilename' in opts) {
597
- opts.outFilename = (0, util_1.parseHeader)(headers, 'content-disposition');
598
- }
599
- const pipeline = pipeTo ? !(0, types_1.isString)(pipeTo) : false;
600
- const enabled = config.connected?.call(client, headers) !== false && !pipeline;
601
- const maxBufferSize = config.maxBufferSize ? (0, types_1.alignSize)(config.maxBufferSize) : 0;
602
- const contentLength = parent && progressId !== undefined ? parseInt(headers['content-length'] || '0') : 0;
603
- let log = this.log, buffer = null, dataLength = 0, mibsTime, delayTime;
604
- if (log || contentLength > 0 || instance.readTimeout > 0) {
605
- client.once('readable', () => {
606
- if (instance.readTimeout > 0) {
607
- this.timeout = setTimeout(() => {
608
- this.terminate((0, types_1.errorValue)("Timeout was exceeded", this.uri.toString()));
609
- }, instance.readTimeout);
610
- }
611
- if (log) {
612
- switch (instance.settings?.time_format || LOG_TIMEFORMAT) {
613
- case 'readable':
614
- delayTime = process.hrtime(this.startTime);
615
- break;
616
- case 'relative':
617
- delayTime = Date.now() - instance.startTime;
618
- break;
619
- case 'none':
620
- if (opts.silent !== false) {
621
- log = false;
622
- }
623
- break;
624
- }
625
- }
626
- mibsTime = process.hrtime();
627
- if (contentLength > 0) {
628
- parent.updateProgress("request", progressId, 0, 0, mibsTime);
629
- }
630
- });
631
- }
632
- if (enabled) {
633
- const encoding = opts.encoding;
634
- client.on('data', (chunk) => {
635
- if (buffer) {
636
- if (typeof buffer === 'string') {
637
- buffer += typeof chunk === 'string' ? chunk : chunk.toString(encoding);
638
- }
639
- else if (Array.isArray(buffer)) {
640
- buffer.push(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk);
641
- }
642
- else {
643
- buffer = Buffer.concat([buffer, typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk]);
644
- }
645
- }
646
- else {
647
- buffer = typeof chunk === 'string' ? chunk : [chunk];
648
- }
649
- if (contentLength > 0) {
650
- dataLength += Buffer.byteLength(chunk, encoding);
651
- parent.updateProgress("request", progressId, dataLength, contentLength);
652
- }
653
- if (maxBufferSize > 0) {
654
- if (contentLength === 0) {
655
- dataLength += Buffer.byteLength(chunk, encoding);
656
- }
657
- if (dataLength > maxBufferSize) {
658
- this.terminate((0, types_1.errorValue)("Size limit was exceeded", this.uri.toString()));
659
- }
660
- }
661
- });
662
- }
663
- client.once('end', () => {
664
- if (this.closed || this.aborted) {
665
- return;
666
- }
667
- this.close();
668
- const encoding = opts.encoding;
669
- let result, messageUnit, titleBgColor;
670
- if (buffer) {
671
- if (Array.isArray(buffer)) {
672
- buffer = Buffer.concat(buffer);
673
- if (encoding) {
674
- buffer = buffer.toString(encoding);
675
- }
676
- }
677
- dataLength = Buffer.byteLength(buffer, encoding);
678
- if (mibsTime) {
679
- messageUnit = (0, util_1.getTransferRate)(dataLength, (0, types_1.convertTime)(process.hrtime(mibsTime), false) * 1000);
680
- }
681
- if (contentLength > 0) {
682
- parent.updateProgress("request", progressId, dataLength, dataLength);
683
- }
684
- if (typeof buffer === 'string') {
685
- if (buffer.startsWith('\uFEFF') && encoding !== 'utf16le' && encoding !== 'utf-16le') {
686
- buffer = buffer.substring(1);
687
- }
688
- if (config.outFormat) {
689
- const { out: format, parser } = config.outFormat;
690
- let packageName;
691
- try {
692
- switch (format) {
693
- case 'yaml':
694
- result = yaml.load(buffer, parser);
695
- break;
696
- case 'json5':
697
- result = require(packageName = 'json5').parse(buffer);
698
- break;
699
- case 'xml':
700
- result = new (require(packageName = 'fast-xml-parser').XMLParser)(parser).parse(buffer);
701
- break;
702
- case 'toml':
703
- result = require(packageName = 'toml').parse(buffer);
704
- break;
705
- default:
706
- result = JSON.parse(buffer);
707
- break;
708
- }
709
- if (!(0, types_1.isObject)(result)) {
710
- result = null;
711
- }
712
- }
713
- catch (err) {
714
- if (this.status && !(packageName && instance.checkPackage(err, packageName))) {
715
- instance.writeFail(["Unable to parse URI response", format], err, 1024);
716
- }
717
- result = null;
718
- }
719
- }
720
- }
721
- if (result === undefined) {
722
- result = buffer;
723
- }
724
- }
725
- else {
726
- if (contentLength > 0) {
727
- parent.updateProgress("request", progressId, 0, contentLength);
728
- }
729
- if (enabled && instance.readExpect === 'always') {
730
- this.terminate("No data received");
731
- return;
732
- }
733
- result = encoding && !pipeline ? '' : null;
734
- titleBgColor = 'bgBlue';
735
- }
736
- if (log) {
737
- instance.writeTimeProcess('HTTP' + config.httpVersion, config.statusMessage || this.uri.toString(), this.startTime, { type: 1024, queue: !!parent, titleBgColor, messageUnit, messageUnitMinWidth: 9, delayTime, bypassLog: LOG_STDOUT });
738
- }
739
- this.resolve(result);
740
- });
741
- config.host.success(this.httpVersion);
742
- }
743
- redirectResponse(statusCode, location) {
744
- if (location) {
745
- if (this.config.follow_redirect === false || this.config.followRedirect === false) {
746
- this.terminate(this.formatStatus(statusCode, "Follow redirect was disabled"));
747
- }
748
- else if (++this.redirects <= this.redirectLimit) {
749
- this.abortResponse();
750
- this.setConfig(Request.fromURL(this.config.url, location));
751
- this.init();
752
- }
753
- else {
754
- this.terminate(this.formatStatus(statusCode, "Exceeded redirect limit"));
755
- }
756
- }
757
- else {
758
- this.terminate(this.formatStatus(statusCode, "Missing redirect location"));
759
- }
760
- }
761
- errorResponse(err) {
762
- if (Fetch.wasAborted(err)) {
763
- this.terminate(err);
764
- }
765
- else if ((0, util_1.checkRetryable)(err) && ++this.retries <= this.retryLimit) {
766
- this.abortResponse();
767
- if (Fetch.isConnectionTimeout(err)) {
768
- this.retryTimeout();
769
- }
770
- else {
771
- setTimeout(() => {
772
- this.init();
773
- }, this.retryWait);
774
- }
775
- }
776
- else {
777
- this.config.host.error(this.httpVersion);
778
- this.terminate(err);
779
- }
780
- }
781
- retryResponse(statusCode, retryAfter) {
782
- this.abortResponse();
783
- if (retryAfter && this.retryAfter > 0) {
784
- let offset = +retryAfter || new Date(retryAfter);
785
- if (offset instanceof Date) {
786
- offset = Math.max(0, offset.getTime() - Date.now());
787
- }
788
- else {
789
- offset *= 1000;
790
- }
791
- if (offset > 0) {
792
- if (offset <= this.retryAfter) {
793
- this.sendWarning(`Retry After (${retryAfter})`);
794
- setTimeout(() => {
795
- this.init();
796
- }, offset);
797
- }
798
- else {
799
- this.terminate(this.formatStatus(statusCode));
800
- }
801
- return;
802
- }
803
- }
804
- this.sendWarning(this.formatRetry(Request.fromStatusCode(statusCode)));
805
- if ((0, util_1.isRetryable)(statusCode, true)) {
806
- process.nextTick(this.init.bind(this));
807
- }
808
- else {
809
- setTimeout(() => {
810
- this.init();
811
- }, this.retryWait);
812
- }
813
- }
814
- isRetry(value) {
815
- return (0, util_1.isRetryable)(value) && ++this.retries <= this.retryLimit;
816
- }
817
- retryTimeout() {
818
- this.sendWarning(this.formatRetry("HTTP connection timeout"));
819
- this.init();
820
- }
821
- terminate(err) {
822
- if (this.timeout) {
823
- clearTimeout(this.timeout);
824
- }
825
- if (!this.closed) {
826
- this.cleanup();
827
- this.close();
828
- this.reject(typeof err === 'string' ? new Error(err) : err);
829
- }
830
- }
831
- sendWarning(message) {
832
- if (this.status) {
833
- const { host, url } = this.config;
834
- this.instance.formatMessage(1024, 'HTTP' + this.httpVersion, [message, host.origin], url.toString(), { ...module_1.LOG_STYLE_WARN });
835
- }
836
- }
837
- formatStatus(value, hint) {
838
- return value + ': ' + (hint || Request.fromStatusCode(value)) + ` (${this.uri.toString()})`;
839
- }
840
- formatNgFlags(value, statusCode, location) {
841
- return location ? `Using HTTP 1.1 for URL redirect (${location})` : this.formatStatus(statusCode, value ? 'NGHTTP2 Error ' + value : '');
842
- }
843
- formatRetry(message) {
844
- return message + ` (${this.retries} / ${this.retryLimit})`;
845
- }
846
- close() {
847
- if (this.timeout) {
848
- clearTimeout(this.timeout);
849
- }
850
- this.closed = true;
851
- if (this.aborted && !this.client.aborted && !this.client.destroyed) {
852
- this.opts.outAbort?.abort();
853
- }
854
- }
855
- cleanup() {
856
- const outAbort = this.opts.outAbort;
857
- if (outAbort) {
858
- this.downloading.delete(outAbort);
859
- }
860
- if ((0, types_1.isString)(this.pipeTo) && this.outStream) {
861
- (0, util_1.cleanupStream)(this.outStream, this.pipeTo);
862
- }
863
- }
864
- get destroyed() {
865
- return this.client.destroyed || this.httpVersion === 2 && this.client.aborted;
866
- }
867
- get downloading() {
868
- return this.instance[kDownloading];
869
- }
870
- get httpVersion() {
871
- return this.config.httpVersion;
872
- }
873
- get outAbort() {
874
- return this.config.outAbort;
875
- }
876
- get pipeTo() {
877
- return this.opts.pipeTo;
878
- }
879
- get retryLimit() {
880
- return this.settings.retryLimit;
881
- }
882
- get retryWait() {
883
- return this.settings.retryWait;
884
- }
885
- get retryAfter() {
886
- return this.settings.retryAfter;
887
- }
888
- get redirectLimit() {
889
- return this.settings.redirectLimit;
890
- }
891
- get settings() {
892
- return this.instance['_config'];
893
- }
894
- }
895
382
  class Request extends module_1 {
896
383
  static async purgeMemory(percent = 1, limit = 0, parent) {
897
384
  if (percent >= 1) {
@@ -985,9 +472,8 @@ class Request extends module_1 {
985
472
  READ_TIMEOUT = read_timeout;
986
473
  }
987
474
  if ((0, types_1.isObject)(agent)) {
988
- let keep_alive;
989
- ({ keep_alive, timeout: agent_timeout } = agent);
990
- if ((agent_timeout = (0, util_1.fromSeconds)(agent_timeout)) > 0) {
475
+ let { keep_alive, timeout } = agent;
476
+ if ((agent_timeout = (0, util_1.fromSeconds)(timeout)) > 0) {
991
477
  AGENT_TIMEOUT = agent_timeout;
992
478
  }
993
479
  else {
@@ -1020,19 +506,13 @@ class Request extends module_1 {
1020
506
  [TLS.TEXT, TLS.FILE] = validateCerts(certs);
1021
507
  }
1022
508
  HTTP.PROXY = getProxySettings(request, agent_timeout);
1023
- const time_format = request.settings?.time_format;
1024
- switch (time_format) {
1025
- case 'readable':
1026
- case 'relative':
1027
- case 'none':
1028
- LOG_TIMEFORMAT = time_format;
1029
- break;
1030
- }
1031
509
  host_1.defineHostConfig(request);
510
+ if ('defineHostConfig' in HTTP_ADAPTER) {
511
+ HTTP_ADAPTER.defineHostConfig(request);
512
+ }
1032
513
  }
1033
514
  LOG_HTTP = this.hasLogType(1024);
1034
515
  LOG_TIMEPROCESS = this.hasLogType(256);
1035
- LOG_STDOUT = module_1.hasLogType(32768);
1036
516
  return true;
1037
517
  }
1038
518
  static readCACert(value, cache) {
@@ -1048,153 +528,10 @@ class Request extends module_1 {
1048
528
  return typeof value === 'string' && (value = value.trim()).length > 0 && REGEXP_PEMCERT.test(value);
1049
529
  }
1050
530
  static fromURL(url, value) {
1051
- if (this.isURL(value)) {
1052
- return value;
1053
- }
1054
- const auth = host_1.formatBasicAuth(url);
1055
- return url.protocol + '//' + (auth && (auth + '@')) + url.hostname + (url.port ? ':' + url.port : '') + (value.startsWith('/') ? '' : '/') + value;
531
+ return (0, util_1.fromURL)(url, value);
1056
532
  }
1057
533
  static fromStatusCode(value) {
1058
- value = +value;
1059
- if (value < 200) {
1060
- switch (value) {
1061
- case 100:
1062
- return 'Continue';
1063
- case 101:
1064
- return 'Switching Protocol';
1065
- case 102:
1066
- return 'Processing';
1067
- case 103:
1068
- return 'Early Hints';
1069
- }
1070
- }
1071
- else if (value < 300) {
1072
- switch (value) {
1073
- case 200:
1074
- return 'OK';
1075
- case 201:
1076
- return 'Created';
1077
- case 202:
1078
- return 'Accepted';
1079
- case 203:
1080
- return 'Non-Authoritative Information';
1081
- case 204:
1082
- return 'No Content';
1083
- case 205:
1084
- return 'Reset Content';
1085
- case 206:
1086
- return 'Partial Content';
1087
- }
1088
- }
1089
- else if (value < 400) {
1090
- switch (value) {
1091
- case 300:
1092
- return 'Multiple Choice';
1093
- case 301:
1094
- return 'Moved Permanently';
1095
- case 302:
1096
- return 'Found';
1097
- case 303:
1098
- return 'See Other';
1099
- case 304:
1100
- return 'Not Modified';
1101
- case 305:
1102
- return 'Use Proxy';
1103
- case 307:
1104
- return 'Temporary Redirect';
1105
- case 308:
1106
- return 'Permanent Redirect';
1107
- }
1108
- }
1109
- else if (value < 500) {
1110
- switch (value) {
1111
- case 400:
1112
- return 'Bad Request';
1113
- case 401:
1114
- return 'Upgrade Required';
1115
- case 402:
1116
- return 'Payment Required';
1117
- case 403:
1118
- return 'Forbidden';
1119
- case 404:
1120
- return 'Not Found';
1121
- case 405:
1122
- return 'Method Not Allowed';
1123
- case 406:
1124
- return 'Not Acceptable';
1125
- case 407:
1126
- return 'Proxy Authentication Required';
1127
- case 408:
1128
- return 'Request Timeout';
1129
- case 409:
1130
- return 'Conflict';
1131
- case 410:
1132
- return 'Gone';
1133
- case 411:
1134
- return 'Length Required';
1135
- case 412:
1136
- return 'Precondition Failed';
1137
- case 413:
1138
- return 'Payload Too Large';
1139
- case 414:
1140
- return 'URI Too Long';
1141
- case 415:
1142
- return 'Unsupported Media Type';
1143
- case 416:
1144
- return 'Range Not Satisfiable';
1145
- case 417:
1146
- return 'Expectation Failed';
1147
- case 421:
1148
- return 'Misdirected Request';
1149
- case 422:
1150
- return 'Unprocessable Entity';
1151
- case 423:
1152
- return 'Locked';
1153
- case 424:
1154
- return 'Failed Dependency';
1155
- case 425:
1156
- return 'Too Early';
1157
- case 426:
1158
- return 'Upgrade Required';
1159
- case 428:
1160
- return 'Precondition Required';
1161
- case 429:
1162
- return 'Too Many Requests';
1163
- case 431:
1164
- return 'Request Header Fields Too Large';
1165
- case 451:
1166
- return 'Unavailable For Legal Reasons';
1167
- }
1168
- }
1169
- else {
1170
- switch (value) {
1171
- case 500:
1172
- return 'Internal Server Error';
1173
- case 501:
1174
- return 'Not Implemented';
1175
- case 502:
1176
- return 'Bad Gateway';
1177
- case 503:
1178
- return 'Service Unavailable';
1179
- case 504:
1180
- return 'Gateway Timeout';
1181
- case 505:
1182
- return 'HTTP Version Not Supported';
1183
- case 506:
1184
- return 'Variant Also Negotiates';
1185
- case 507:
1186
- return 'Insufficient Storage';
1187
- case 508:
1188
- return 'Loop Detected';
1189
- case 509:
1190
- return 'Bandwidth Limit Exceeded';
1191
- case 510:
1192
- return 'Not Extended';
1193
- case 511:
1194
- return 'Network Authentication Required';
1195
- }
1196
- }
1197
- return "Unknown";
534
+ return (0, util_1.fromStatusCode)(value);
1198
535
  }
1199
536
  static defineHttpAgent(options) {
1200
537
  const { keepAlive, timeout = 0 } = options;
@@ -1243,6 +580,11 @@ class Request extends module_1 {
1243
580
  }
1244
581
  }
1245
582
  }
583
+ static defineHttpAdapter(module) {
584
+ if (isFunction(module) && module.prototype instanceof adapter_1) {
585
+ HTTP_ADAPTER = module;
586
+ }
587
+ }
1246
588
  static getAria2Path() {
1247
589
  return ARIA2.BIN;
1248
590
  }
@@ -1271,9 +613,10 @@ class Request extends module_1 {
1271
613
  this[_h] = [{}, {}];
1272
614
  this[_j] = null;
1273
615
  this[_k] = null;
1274
- this[_l] = new Set();
1275
- this[_m] = {};
1276
- this[_o] = [Object.create(null)];
616
+ this[_l] = HTTP_ADAPTER;
617
+ this[_m] = new Set();
618
+ this[_o] = {};
619
+ this[_p] = [Object.create(null)];
1277
620
  if ((0, types_1.isPlainObject)(data)) {
1278
621
  const { headers, read_timeout, agent, use, connect, certs } = data;
1279
622
  const timeout = (0, util_1.fromSeconds)(data.timeout);
@@ -1355,7 +698,7 @@ class Request extends module_1 {
1355
698
  count = Math.max(count, value);
1356
699
  }
1357
700
  });
1358
- if (LOG_STDOUT) {
701
+ if (module_1.hasLogType(32768)) {
1359
702
  output.sort((a, b) => {
1360
703
  if (a[2] === b[2]) {
1361
704
  return a[1] < b[1] ? -1 : 1;
@@ -1556,7 +899,24 @@ class Request extends module_1 {
1556
899
  if (!include && !exclude && !localhost) {
1557
900
  return proxy;
1558
901
  }
1559
- 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))) {
902
+ if (exclude) {
903
+ let valid = true;
904
+ for (const value of exclude) {
905
+ if (value.startsWith('!')) {
906
+ if (REGEXP_GLOBWITHIN.test(value.substring(1))) {
907
+ valid = true;
908
+ break;
909
+ }
910
+ }
911
+ else if (valid && (REGEXP_GLOBWITHIN.test(value) ? pm.isMatch(uri, value) : uri.startsWith(value))) {
912
+ valid = false;
913
+ }
914
+ }
915
+ if (!valid) {
916
+ return;
917
+ }
918
+ }
919
+ if ((0, types_1.isArray)(include) && !include.some(value => REGEXP_GLOBWITHIN.test(value) ? pm.isMatch(uri, value) : uri.startsWith(value))) {
1560
920
  return;
1561
921
  }
1562
922
  return proxy;
@@ -1848,7 +1208,7 @@ class Request extends module_1 {
1848
1208
  opts.push(`"${escapeShellQuote(uri)}"`);
1849
1209
  args = args.concat(init, opts);
1850
1210
  const startTime = Date.now();
1851
- let out = '', message = '', aborted;
1211
+ let out = '', message = '', aborted = false;
1852
1212
  const errorResponse = (pid, err) => {
1853
1213
  aborted = true;
1854
1214
  closeTorrent(pid);
@@ -1983,7 +1343,7 @@ class Request extends module_1 {
1983
1343
  return { ...options, host, url };
1984
1344
  }
1985
1345
  open(uri, options) {
1986
- let { host, url, httpVersion, method = 'GET', search, encoding, format, headers: outgoing, postData, keepAlive, agentTimeout, socketPath, timeout = this._config.connectTimeout, outStream } = options, headers = (0, util_1.parseOutgoingHeaders)(outgoing), getting = false, posting = false;
1346
+ let { host, url, httpVersion, method = 'GET', search, encoding, format, headers: outgoing, socketPath, expectContinue = false, timeout = this._config.connectTimeout, outStream } = options, headers = (0, util_1.parseOutgoingHeaders)(outgoing), getting = false, posting = false;
1987
1347
  switch (method = method.toUpperCase()) {
1988
1348
  case 'GET':
1989
1349
  case 'DELETE':
@@ -2066,10 +1426,29 @@ class Request extends module_1 {
2066
1426
  const pathname = url.pathname + (socketPath ? '' : url.search);
2067
1427
  const proxy = this.proxyOf(uri, host.localhost);
2068
1428
  const version = this.httpVersion;
2069
- let request, ca, cert, key, ciphers, minVersion, baseHeaders = this.headersOf(uri);
1429
+ const baseHeaders = this.headersOf(uri);
1430
+ let request, ca, cert, key, ciphers, minVersion;
2070
1431
  if (getting && this.acceptEncoding && !host.localhost && !baseHeaders?.['accept-encoding']) {
2071
1432
  (headers ||= {})['accept-encoding'] ||= 'gzip, deflate, br' + (LIB_ZSTD ? ', zstd' : '');
2072
1433
  }
1434
+ if (posting && options.postData) {
1435
+ if (expectContinue) {
1436
+ (headers ||= {}).expect = '100-continue';
1437
+ }
1438
+ else {
1439
+ let expect;
1440
+ if (headers && 'expect' in headers) {
1441
+ expect = headers.expect;
1442
+ }
1443
+ else if (baseHeaders) {
1444
+ expect = baseHeaders.expect;
1445
+ }
1446
+ expectContinue = expect === '100-continue';
1447
+ }
1448
+ }
1449
+ else {
1450
+ expectContinue = false;
1451
+ }
2073
1452
  if (secure) {
2074
1453
  const certs = this[kCerts]?.[0][origin] || this.host && TLS.TEXT[origin];
2075
1454
  if (certs) {
@@ -2082,10 +1461,14 @@ class Request extends module_1 {
2082
1461
  const listenerMap = {};
2083
1462
  const onEvent = request.on.bind(request);
2084
1463
  const onceEvent = request.once.bind(request);
2085
- let connected, emitter;
1464
+ let connected = false, emitter;
2086
1465
  request.on('response', response => {
2087
- connected = true;
2088
1466
  const statusCode = response[':status'];
1467
+ if (expectContinue) {
1468
+ abortHeaders.call(this, url.href, request, options, statusCode, "Did not receive continue acknowledgment");
1469
+ return;
1470
+ }
1471
+ connected = true;
2089
1472
  if (this.matchStatus(statusCode, url, response, request, options) && statusCode >= 200 && statusCode < 300) {
2090
1473
  if (emitter = checkEncoding(request, request, statusCode, outStream, response['content-encoding'])) {
2091
1474
  for (const event in listenerMap) {
@@ -2114,8 +1497,8 @@ class Request extends module_1 {
2114
1497
  this[kConnectHttp][1][origin] = (this[kConnectHttp][1][origin] || 0) + 1;
2115
1498
  }
2116
1499
  }
2117
- request.setTimeout(this._config.timeout);
2118
1500
  this.matchHeaders(url, response, request, options);
1501
+ request.setTimeout(this._config.timeout);
2119
1502
  });
2120
1503
  request.on = function (event, listener) {
2121
1504
  switch (event) {
@@ -2159,16 +1542,14 @@ class Request extends module_1 {
2159
1542
  else {
2160
1543
  let agent;
2161
1544
  if (!socketPath) {
1545
+ let { keepAlive, agentTimeout } = options;
2162
1546
  if (proxy) {
2163
1547
  const pkg = secure ? 'https-proxy-agent' : 'http-proxy-agent';
2164
1548
  try {
2165
1549
  keepAlive ??= proxy.keepAlive;
2166
1550
  agentTimeout ??= proxy.agentTimeout;
2167
1551
  const proxyHeaders = this[kHeaders] && getBaseHeaders(proxy.host.href, this[kHeaders]) || getBaseHeaders(proxy.host.href, HTTP.HEADERS);
2168
- agent = require(pkg)(proxy.host, typeof keepAlive === 'boolean' || agentTimeout > 0 || proxyHeaders ? { keepAlive: keepAlive ?? true, timeout: agentTimeout, headers: proxyHeaders } : undefined);
2169
- if (proxyHeaders) {
2170
- baseHeaders = { ...baseHeaders, ...proxyHeaders };
2171
- }
1552
+ agent = require(pkg)(proxy.host, (typeof keepAlive === 'boolean' || agentTimeout > 0) && agentTimeout !== 0 ? { keepAlive: keepAlive ?? true, timeout: agentTimeout, headers: proxyHeaders } : { headers: proxyHeaders });
2172
1553
  }
2173
1554
  catch (err) {
2174
1555
  this.checkPackage(err, pkg, "Unknown");
@@ -2208,10 +1589,12 @@ class Request extends module_1 {
2208
1589
  }, response => {
2209
1590
  const statusCode = response.statusCode;
2210
1591
  const incoming = response.headers;
2211
- if (this.matchStatus(statusCode, url, incoming, request, options) && (getting || posting) && statusCode >= 200 && statusCode < 300) {
1592
+ if (!expectContinue && this.matchStatus(statusCode, url, incoming, request, options) && (getting || posting) && statusCode >= 200 && statusCode < 300) {
2212
1593
  let source = checkEncoding(request, response, statusCode, outStream, incoming['content-encoding']);
2213
1594
  if (source) {
2214
- source.once('finish', () => request.emit('end'));
1595
+ source.once('finish', () => {
1596
+ request.emit('end');
1597
+ });
2215
1598
  }
2216
1599
  else {
2217
1600
  if (encoding) {
@@ -2228,7 +1611,9 @@ class Request extends module_1 {
2228
1611
  });
2229
1612
  }
2230
1613
  else {
2231
- response.once('end', () => request.emit('end'));
1614
+ response.once('end', () => {
1615
+ request.emit('end');
1616
+ });
2232
1617
  }
2233
1618
  source = response;
2234
1619
  }
@@ -2273,9 +1658,15 @@ class Request extends module_1 {
2273
1658
  .once('end', () => {
2274
1659
  request.emit('end');
2275
1660
  });
1661
+ if (expectContinue) {
1662
+ abortHeaders.call(this, url.href, request, options, statusCode, "Did not receive continue acknowledgment");
1663
+ return;
1664
+ }
2276
1665
  }
2277
1666
  if (this._config.timeout) {
2278
- response.setTimeout(this._config.timeout, () => request.emit('timeout'));
1667
+ response.setTimeout(this._config.timeout, () => {
1668
+ request.emit('timeout');
1669
+ });
2279
1670
  }
2280
1671
  this.matchHeaders(url, incoming, request, options);
2281
1672
  });
@@ -2295,15 +1686,32 @@ class Request extends module_1 {
2295
1686
  ac.abort(new Error("Aborted by process"));
2296
1687
  }, { once: true });
2297
1688
  }
2298
- if (posting) {
2299
- if ((0, types_1.isString)(postData) || Buffer.isBuffer(postData)) {
2300
- request.write(postData);
2301
- }
2302
- else if (postData instanceof stream.Stream) {
2303
- postData.pipe(request);
1689
+ const sendBody = () => {
1690
+ if (posting) {
1691
+ const postData = options.postData;
1692
+ if ((0, types_1.isString)(postData) || Buffer.isBuffer(postData)) {
1693
+ request.write(postData);
1694
+ }
1695
+ else if (postData instanceof stream.Stream) {
1696
+ postData.pipe(request);
1697
+ }
2304
1698
  }
1699
+ };
1700
+ if (expectContinue) {
1701
+ const pending = setTimeout(() => {
1702
+ request.end();
1703
+ }, options.expectTimeout || 5 * 1000);
1704
+ request.on('continue', () => {
1705
+ clearTimeout(pending);
1706
+ expectContinue = false;
1707
+ sendBody();
1708
+ request.end();
1709
+ });
1710
+ }
1711
+ else {
1712
+ sendBody();
1713
+ request.end();
2305
1714
  }
2306
- request.end();
2307
1715
  return request;
2308
1716
  }
2309
1717
  head(uri, options) {
@@ -2344,14 +1752,13 @@ class Request extends module_1 {
2344
1752
  }
2345
1753
  let dataEncoding;
2346
1754
  if ((0, types_1.isPlainObject)(options)) {
2347
- let formData;
2348
- ({ formData, dataEncoding } = options);
2349
- if (!putting && formData) {
2350
- (parts ||= []).push(...Array.isArray(formData) ? formData : [formData]);
1755
+ if (!putting && options.formData) {
1756
+ (parts ||= []).push(...Array.isArray(options.formData) ? options.formData : [options.formData]);
2351
1757
  }
2352
1758
  else {
2353
1759
  contentType ||= options.contentType;
2354
1760
  }
1761
+ dataEncoding = options.dataEncoding;
2355
1762
  }
2356
1763
  else {
2357
1764
  options = {};
@@ -2364,7 +1771,7 @@ class Request extends module_1 {
2364
1771
  }
2365
1772
  }
2366
1773
  if (!putting && (parts || contentType === "multipart/form-data" || contentType === 'form-data')) {
2367
- let valid;
1774
+ let valid = false;
2368
1775
  if ((0, types_1.isArray)(parts)) {
2369
1776
  const write = combined.create();
2370
1777
  const boundary = crypto.randomUUID().replaceAll('-', '');
@@ -2446,7 +1853,7 @@ class Request extends module_1 {
2446
1853
  }
2447
1854
  else {
2448
1855
  if (contentType && !contentType.includes('/')) {
2449
- contentType = 'application/' + contentType.trim();
1856
+ contentType = 'application/' + contentType;
2450
1857
  }
2451
1858
  if (!(0, types_1.isPlainObject)(data)) {
2452
1859
  data = module_1.asString(data);
@@ -2468,14 +1875,35 @@ class Request extends module_1 {
2468
1875
  headers['content-type'] = contentType || "text/plain";
2469
1876
  return this.get(uri, options);
2470
1877
  }
2471
- async get(uri, options = {}) {
2472
- const opts = (typeof options === 'string' ? { format: options, encoding: 'utf-8' } : options);
1878
+ async get(uri, options) {
1879
+ const opts = (typeof options === 'string' ? { format: options, encoding: 'utf-8' } : options || {});
2473
1880
  if (this.readExpect === 'string') {
2474
1881
  opts.encoding = (0, types_1.getEncoding)(opts.encoding);
2475
1882
  }
2476
- return new Fetch(this, uri, opts).start();
1883
+ const singleton = this[kSingleton];
1884
+ const verbose = !opts.silent && !singleton || opts.silent === false;
1885
+ const log = verbose && LOG_HTTP && LOG_TIMEPROCESS;
1886
+ const state = Object.freeze({
1887
+ verbose,
1888
+ log,
1889
+ singleton,
1890
+ config: this._config
1891
+ });
1892
+ return new this[kAdapter](this, state, uri, opts).start();
2477
1893
  }
2478
- reset() {
1894
+ reset(adapter) {
1895
+ if (adapter) {
1896
+ if (adapter.timeout) {
1897
+ clearTimeout(adapter.timeout);
1898
+ adapter.timeout = null;
1899
+ }
1900
+ const ac = adapter.abortController;
1901
+ if (ac) {
1902
+ this[kDownloading].delete(ac);
1903
+ adapter.abortController = null;
1904
+ }
1905
+ return;
1906
+ }
2479
1907
  this[kPendingDns] = Object.create(null);
2480
1908
  this[kDownloading].clear();
2481
1909
  }
@@ -2545,6 +1973,11 @@ class Request extends module_1 {
2545
1973
  }
2546
1974
  return true;
2547
1975
  }
1976
+ set adapter(value) {
1977
+ if (isFunction(value) && value.prototype instanceof adapter_1) {
1978
+ this[kAdapter] = value;
1979
+ }
1980
+ }
2548
1981
  set agentTimeout(value) {
2549
1982
  if (value > 0) {
2550
1983
  this[kAgentTimeout] = value;
@@ -2585,5 +2018,5 @@ class Request extends module_1 {
2585
2018
  return this.module.settings ||= {};
2586
2019
  }
2587
2020
  }
2588
- _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;
2021
+ _a = kSingleton, _b = kHttpVersion, _c = kHeaders, _d = kCerts, _e = kBaseURL, _f = kConnectDns, _g = kPendingDns, _h = kConnectHttp, _j = kStatusOn, _k = kHeadersOn, _l = kAdapter, _m = kDownloading, _o = kHostInfo, _p = kSession;
2589
2022
  module.exports = Request;