@e-mc/request 0.13.9 → 0.14.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/README.md +5 -5
- package/http/adapter/index.js +34 -37
- package/http/host/altsvc/index.d.ts +5 -0
- package/http/host/altsvc/index.js +2 -0
- package/http/host/index.js +8 -21
- package/index.js +217 -205
- package/package.json +4 -4
- package/util.js +41 -39
package/index.js
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
2
|
+
|
|
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
|
+
const qs = require('node:querystring');
|
|
15
|
+
const combined = require('combined-stream');
|
|
16
|
+
const pm = require('picomatch');
|
|
17
|
+
const which = require('which');
|
|
18
|
+
const { fileURLToPath } = require('node:url');
|
|
19
|
+
const { createAbortError, errorMessage, errorValue, formatTime, getEncoding, getLogCurrent, isArray, isObject, isPlainObject, isString, parseExpires, sanitizeArgs, sanitizeCmd, supported } = require('@e-mc/types');
|
|
20
|
+
const Module = require('@e-mc/module');
|
|
21
|
+
const { asInt, fromSeconds, fromStatusCode, getBasicAuth, normalizeHeaders, parseOutgoingHeaders, trimPath } = require('@e-mc/request/util');
|
|
22
|
+
const HttpHost = require('@e-mc/request/http/host');
|
|
23
|
+
const HttpAdapter = require('@e-mc/request/http/adapter');
|
|
23
24
|
const kRequest = Symbol.for('request:constructor');
|
|
24
|
-
const SUPPORTED_NODE20 =
|
|
25
|
-
const SUPPORTED_ZSTD =
|
|
26
|
-
const SUPPORTED_FILE =
|
|
27
|
-
const SUPPORTED_PROXY =
|
|
25
|
+
const SUPPORTED_NODE20 = supported(20);
|
|
26
|
+
const SUPPORTED_ZSTD = supported(23, 8) || supported(22, 15, true);
|
|
27
|
+
const SUPPORTED_FILE = supported(19, 2) || supported(18, 13, true);
|
|
28
|
+
const SUPPORTED_PROXY = supported(24, 5);
|
|
28
29
|
const REGEXP_GLOBWITHIN = /\\\?|(?:(?<!\\)(?:\*|\[!?[^!\]]+\]|\{(?:[^,]+,)+[^}]+\}|[!?+*@]\((?:[^|]+\|)*[^)]+\)|\?.*\?|\?$))/;
|
|
29
30
|
const REGEXP_RCLONE = /^rclone:\?/i;
|
|
30
31
|
const HTTP = {
|
|
@@ -45,7 +46,7 @@ const DNS = {
|
|
|
45
46
|
FAMILY: 0
|
|
46
47
|
};
|
|
47
48
|
const ARIA2 = {
|
|
48
|
-
BIN: which.sync(
|
|
49
|
+
BIN: which.sync(Module.PLATFORM_WIN32 ? 'aria2c.exe' : 'aria2c', { nothrow: true }) || '',
|
|
49
50
|
EXEC_UID: undefined,
|
|
50
51
|
EXEC_GID: undefined,
|
|
51
52
|
PID_TIMER: null,
|
|
@@ -68,7 +69,7 @@ const ARIA2 = {
|
|
|
68
69
|
CONF_PATH: ''
|
|
69
70
|
};
|
|
70
71
|
const RCLONE = {
|
|
71
|
-
BIN: which.sync(
|
|
72
|
+
BIN: which.sync(Module.PLATFORM_WIN32 ? 'rclone.exe' : 'rclone', { nothrow: true }) || '',
|
|
72
73
|
EXEC_UID: undefined,
|
|
73
74
|
EXEC_GID: undefined,
|
|
74
75
|
CHECK_FIRST: false,
|
|
@@ -78,6 +79,9 @@ const RCLONE = {
|
|
|
78
79
|
CUTOFF_MODE: '',
|
|
79
80
|
DIFFER: '',
|
|
80
81
|
ERROR: '',
|
|
82
|
+
FORMAT: '',
|
|
83
|
+
SEPARATOR: '',
|
|
84
|
+
TIMEFORMAT: '',
|
|
81
85
|
HASH: '',
|
|
82
86
|
IGNORE_CASE_SYNC: false,
|
|
83
87
|
IGNORE_CHECKSUM: false,
|
|
@@ -99,6 +103,7 @@ const RCLONE = {
|
|
|
99
103
|
NO_TRAVERSE: false,
|
|
100
104
|
NO_UPDATE_DIR_MODTIME: false,
|
|
101
105
|
NO_UPDATE_MODTIME: false,
|
|
106
|
+
ORDER_BY: '',
|
|
102
107
|
REFRESH_TIMES: false,
|
|
103
108
|
SIZE_ONLY: false,
|
|
104
109
|
STREAMING_UPLOAD_CUTOFF: '',
|
|
@@ -110,7 +115,7 @@ const RCLONE = {
|
|
|
110
115
|
TIMEOUT: '',
|
|
111
116
|
CONFIG: ''
|
|
112
117
|
};
|
|
113
|
-
let HTTP_ADAPTER =
|
|
118
|
+
let HTTP_ADAPTER = HttpAdapter;
|
|
114
119
|
let KEEP_ALIVE = null;
|
|
115
120
|
let ACCEPT_ENCODING = false;
|
|
116
121
|
let READ_TIMEOUT = 0;
|
|
@@ -137,19 +142,19 @@ function setDnsCache(hostname, value, expires) {
|
|
|
137
142
|
function getProxySettings(request, agentTimeout) {
|
|
138
143
|
const proxy = request.proxy;
|
|
139
144
|
if (proxy && (proxy.origin || proxy.address && proxy.port)) {
|
|
140
|
-
const origin = proxy.origin || ((!
|
|
145
|
+
const origin = proxy.origin || ((!Module.isURL(proxy.address) ? asInt(proxy.port) === 80 ? 'http://' : 'https://' : '') + proxy.address + ':' + proxy.port);
|
|
141
146
|
try {
|
|
142
147
|
let host = new URL(origin), include, exclude;
|
|
143
148
|
if (proxy.username) {
|
|
144
|
-
host = new URL(host.protocol + '//' +
|
|
149
|
+
host = new URL(host.protocol + '//' + getBasicAuth(proxy.username, proxy.password) + host.host);
|
|
145
150
|
}
|
|
146
|
-
if (
|
|
151
|
+
if (isArray(proxy.include)) {
|
|
147
152
|
include = proxy.include;
|
|
148
153
|
}
|
|
149
|
-
if (
|
|
154
|
+
if (isArray(proxy.exclude)) {
|
|
150
155
|
exclude = proxy.exclude;
|
|
151
156
|
}
|
|
152
|
-
const keepAliveMsecs =
|
|
157
|
+
const keepAliveMsecs = asInt(proxy.keep_alive_interval);
|
|
153
158
|
return { host, include, exclude, keepAlive: proxy.keep_alive, keepAliveMsecs: keepAliveMsecs > 0 ? keepAliveMsecs : undefined, agentTimeout };
|
|
154
159
|
}
|
|
155
160
|
catch {
|
|
@@ -257,7 +262,7 @@ function validateCerts(certs) {
|
|
|
257
262
|
}
|
|
258
263
|
function checkFile(values) {
|
|
259
264
|
for (let pathname of values) {
|
|
260
|
-
if (
|
|
265
|
+
if (Module.isPath(pathname = path.resolve(pathname))) {
|
|
261
266
|
return pathname;
|
|
262
267
|
}
|
|
263
268
|
}
|
|
@@ -266,7 +271,7 @@ function parseSize(value, zero) {
|
|
|
266
271
|
if (zero && (value === '0' || value === 0)) {
|
|
267
272
|
return 0;
|
|
268
273
|
}
|
|
269
|
-
if (
|
|
274
|
+
if (isString(value) && /^\d+[KM]$/.test(value = value.trim().toUpperCase())) {
|
|
270
275
|
return value;
|
|
271
276
|
}
|
|
272
277
|
}
|
|
@@ -280,7 +285,7 @@ function copySearchParams(url, base) {
|
|
|
280
285
|
function checkEncoding(request, statusCode, contentEncoding) {
|
|
281
286
|
switch (statusCode) {
|
|
282
287
|
case 206:
|
|
283
|
-
request.emit('error',
|
|
288
|
+
request.emit('error', errorValue("Aborted", 'Partial content'));
|
|
284
289
|
case 204:
|
|
285
290
|
case 205:
|
|
286
291
|
case 304:
|
|
@@ -290,7 +295,7 @@ function checkEncoding(request, statusCode, contentEncoding) {
|
|
|
290
295
|
}
|
|
291
296
|
function sendBody(request, options) {
|
|
292
297
|
const postData = options.postData;
|
|
293
|
-
if (
|
|
298
|
+
if (isString(postData) || Buffer.isBuffer(postData)) {
|
|
294
299
|
request.write(postData);
|
|
295
300
|
}
|
|
296
301
|
else if (postData instanceof stream.Stream) {
|
|
@@ -306,7 +311,7 @@ function resetAria2() {
|
|
|
306
311
|
}
|
|
307
312
|
function escapeShellQuote(value) {
|
|
308
313
|
value = value.replace(/(?<!\\)"/g, '\\"');
|
|
309
|
-
return
|
|
314
|
+
return Module.PLATFORM_WIN32 ? value : value.replace(/(?<!\\)\$/g, '\\$');
|
|
310
315
|
}
|
|
311
316
|
function failedDns(err, pending) {
|
|
312
317
|
for (const cb of pending) {
|
|
@@ -324,27 +329,27 @@ function setBinExec(settings, target) {
|
|
|
324
329
|
if (bin === false) {
|
|
325
330
|
target.BIN = '';
|
|
326
331
|
}
|
|
327
|
-
else if (bin &&
|
|
332
|
+
else if (bin && Module.isPath(bin = path.resolve(bin), true)) {
|
|
328
333
|
target.BIN = bin;
|
|
329
334
|
}
|
|
330
|
-
if (
|
|
335
|
+
if (isPlainObject(exec)) {
|
|
331
336
|
let { uid, gid } = exec;
|
|
332
|
-
target.EXEC_UID = (uid =
|
|
333
|
-
target.EXEC_GID = (gid =
|
|
337
|
+
target.EXEC_UID = (uid = asInt(uid)) >= 0 ? uid : undefined;
|
|
338
|
+
target.EXEC_GID = (gid = asInt(gid)) >= 0 ? gid : undefined;
|
|
334
339
|
}
|
|
335
340
|
}
|
|
336
341
|
function checkBinTarget(instance, name, uri, pathname, command, binOpts) {
|
|
337
342
|
if (!pathname) {
|
|
338
|
-
throw
|
|
343
|
+
throw errorMessage(name, "Invalid parameters", 'pathname');
|
|
339
344
|
}
|
|
340
345
|
pathname = path.resolve(pathname);
|
|
341
346
|
if ((instance.host || instance.hasPermission('fs') || process.permission) && !instance.canWrite(pathname)) {
|
|
342
|
-
throw
|
|
347
|
+
throw errorMessage(name, "Unsupported access", pathname);
|
|
343
348
|
}
|
|
344
349
|
let target;
|
|
345
350
|
switch (command) {
|
|
346
351
|
case 'copyurl':
|
|
347
|
-
if (
|
|
352
|
+
if (Module.isDir(pathname) || isDirEnd(pathname)) {
|
|
348
353
|
target = pathname;
|
|
349
354
|
if (!binOpts || !binOpts.includes('--auto-filename') && !binOpts.includes('--header-filename')) {
|
|
350
355
|
pathname = path.join(pathname, path.basename(new URL(uri).pathname));
|
|
@@ -358,8 +363,8 @@ function checkBinTarget(instance, name, uri, pathname, command, binOpts) {
|
|
|
358
363
|
target = pathname;
|
|
359
364
|
break;
|
|
360
365
|
}
|
|
361
|
-
if (!
|
|
362
|
-
throw
|
|
366
|
+
if (!Module.createDir(target)) {
|
|
367
|
+
throw errorMessage(name, "Path is not a directory", target);
|
|
363
368
|
}
|
|
364
369
|
return pathname;
|
|
365
370
|
}
|
|
@@ -398,12 +403,12 @@ function setBinHeaders(args, headers) {
|
|
|
398
403
|
}
|
|
399
404
|
function appendAria2Proxy(args, protocol, host) {
|
|
400
405
|
const { origin, username, password } = host;
|
|
401
|
-
args
|
|
406
|
+
quoteOpt(args, `${protocol}-proxy`, origin);
|
|
402
407
|
if (username) {
|
|
403
|
-
args
|
|
408
|
+
quoteOpt(args, `${protocol}-proxy-user`, decodeURIComponent(username));
|
|
404
409
|
}
|
|
405
410
|
if (password) {
|
|
406
|
-
args
|
|
411
|
+
quoteOpt(args, `${protocol}-proxy-passwd`, decodeURIComponent(password));
|
|
407
412
|
}
|
|
408
413
|
}
|
|
409
414
|
function createAgentOptions(options) {
|
|
@@ -419,10 +424,11 @@ const hasResponse = (value) => value >= 200 && (value < 300 || value === 304);
|
|
|
419
424
|
const isDirEnd = (value) => (value = value.at(-1), value === '/' || value === path.sep);
|
|
420
425
|
const configureDns = (family, options) => family === 0 ? options : { family, hints: family === 6 ? dns.V4MAPPED : 0 };
|
|
421
426
|
const ignoreOpt = (opts, ...values) => !opts?.some(opt => values.some(value => opt === value || opt.startsWith(value + '=')));
|
|
427
|
+
const quoteOpt = (items, name, value) => isString(value) ? items.push(`--${name}="${escapeShellQuote(value)}"`) : 0;
|
|
422
428
|
const escapeQuote = (value) => value.replace(/[\\"]/g, capture => '\\' + capture);
|
|
423
|
-
const rcloneSize = (value) =>
|
|
424
|
-
const rcloneDuration = (value) =>
|
|
425
|
-
class Request extends
|
|
429
|
+
const rcloneSize = (value) => isString(value) ? /^\d+(?:B|[KMGTP]i?)$/i.exec(value)?.[0] : undefined;
|
|
430
|
+
const rcloneDuration = (value) => isString(value) ? /^\d+(?:h|m|s|ms|ns)$/.exec(value)?.[0] : undefined;
|
|
431
|
+
class Request extends Module {
|
|
426
432
|
static [kRequest] = true;
|
|
427
433
|
static async purgeMemory(percent = 1, limit = 0, parent) {
|
|
428
434
|
if (percent >= 1) {
|
|
@@ -446,20 +452,20 @@ class Request extends module_1 {
|
|
|
446
452
|
const aria2 = download.aria2;
|
|
447
453
|
let { update_status, check_integrity, bt_stop_timeout, min_split_size, disk_cache, lowest_speed_limit, always_resume, file_allocation, proxy, no_proxy, conf_path } = aria2;
|
|
448
454
|
setBinExec(download.aria2, ARIA2);
|
|
449
|
-
if (
|
|
455
|
+
if (isPlainObject(update_status)) {
|
|
450
456
|
const { interval, broadcast_only } = update_status;
|
|
451
457
|
if (typeof broadcast_only === 'boolean') {
|
|
452
458
|
ARIA2.UPDATE_BROADCAST_ONLY = broadcast_only;
|
|
453
459
|
}
|
|
454
460
|
update_status = interval;
|
|
455
461
|
}
|
|
456
|
-
if ((update_status =
|
|
462
|
+
if ((update_status = asInt(update_status)) >= 0) {
|
|
457
463
|
ARIA2.UPDATE_STATUS = update_status;
|
|
458
464
|
}
|
|
459
465
|
if (typeof check_integrity === 'boolean') {
|
|
460
466
|
ARIA2.CHECK_INTEGRITY = check_integrity;
|
|
461
467
|
}
|
|
462
|
-
if ((bt_stop_timeout =
|
|
468
|
+
if ((bt_stop_timeout = asInt(bt_stop_timeout)) >= 0) {
|
|
463
469
|
ARIA2.BT_STOP_TIMEOUT = bt_stop_timeout;
|
|
464
470
|
}
|
|
465
471
|
if (min_split_size = parseSize(min_split_size, false)) {
|
|
@@ -474,7 +480,7 @@ class Request extends module_1 {
|
|
|
474
480
|
if (typeof always_resume === 'boolean') {
|
|
475
481
|
ARIA2.ALWAYS_RESUME = always_resume;
|
|
476
482
|
}
|
|
477
|
-
if (
|
|
483
|
+
if (isString(file_allocation)) {
|
|
478
484
|
const value = file_allocation.toLowerCase();
|
|
479
485
|
switch (value) {
|
|
480
486
|
case 'none':
|
|
@@ -501,21 +507,21 @@ class Request extends module_1 {
|
|
|
501
507
|
if (typeof no_proxy === 'string') {
|
|
502
508
|
ARIA2.NO_PROXY = no_proxy;
|
|
503
509
|
}
|
|
504
|
-
if (conf_path === '' ||
|
|
510
|
+
if (conf_path === '' || isString(conf_path) && this.isPath(conf_path = path.resolve(conf_path))) {
|
|
505
511
|
ARIA2.CONF_PATH = conf_path;
|
|
506
512
|
}
|
|
507
513
|
for (const name of ['max_concurrent_downloads', 'max_connection_per_server', 'bt_tracker_connect_timeout', 'bt_tracker_timeout']) {
|
|
508
514
|
let value = aria2[name];
|
|
509
|
-
if ((value =
|
|
515
|
+
if ((value = asInt(value)) > 0) {
|
|
510
516
|
ARIA2[name.toUpperCase()] = value;
|
|
511
517
|
}
|
|
512
518
|
}
|
|
513
519
|
}
|
|
514
520
|
if (download?.rclone) {
|
|
515
521
|
const rclone = download.rclone;
|
|
516
|
-
let { cutoff_mode, hash, max_backlog, max_duration, max_transfer, modify_window, multi_thread_chunk_size, multi_thread_cutoff, multi_thread_streams, multi_thread_write_buffer_size, streaming_upload_cutoff, bind, contimeout, timeout } = rclone;
|
|
522
|
+
let { cutoff_mode, format, separator, timeformat, hash, max_backlog, max_duration, max_transfer, modify_window, multi_thread_chunk_size, multi_thread_cutoff, multi_thread_streams, multi_thread_write_buffer_size, order_by, streaming_upload_cutoff, bind, contimeout, timeout } = rclone;
|
|
517
523
|
setBinExec(download.rclone, RCLONE);
|
|
518
|
-
if (
|
|
524
|
+
if (isString(cutoff_mode)) {
|
|
519
525
|
const value = cutoff_mode.toUpperCase();
|
|
520
526
|
switch (value) {
|
|
521
527
|
case 'HARD':
|
|
@@ -525,7 +531,7 @@ class Request extends module_1 {
|
|
|
525
531
|
break;
|
|
526
532
|
}
|
|
527
533
|
}
|
|
528
|
-
if (
|
|
534
|
+
if (isString(hash)) {
|
|
529
535
|
switch (hash.toLowerCase()) {
|
|
530
536
|
case 'md5':
|
|
531
537
|
RCLONE.HASH = 'md5';
|
|
@@ -538,7 +544,16 @@ class Request extends module_1 {
|
|
|
538
544
|
break;
|
|
539
545
|
}
|
|
540
546
|
}
|
|
541
|
-
if (
|
|
547
|
+
if (format) {
|
|
548
|
+
RCLONE.FORMAT = format;
|
|
549
|
+
}
|
|
550
|
+
if (separator) {
|
|
551
|
+
RCLONE.SEPARATOR = separator;
|
|
552
|
+
}
|
|
553
|
+
if (timeformat) {
|
|
554
|
+
RCLONE.TIMEFORMAT = timeformat;
|
|
555
|
+
}
|
|
556
|
+
if ((max_backlog = asInt(max_backlog)) > 0) {
|
|
542
557
|
RCLONE.MAX_BACKLOG = max_backlog;
|
|
543
558
|
}
|
|
544
559
|
if (max_duration = rcloneDuration(max_duration)) {
|
|
@@ -556,12 +571,15 @@ class Request extends module_1 {
|
|
|
556
571
|
if (multi_thread_cutoff = rcloneSize(multi_thread_cutoff)) {
|
|
557
572
|
RCLONE.MULTI_THREAD_CUTOFF = multi_thread_cutoff;
|
|
558
573
|
}
|
|
559
|
-
if ((multi_thread_streams =
|
|
574
|
+
if ((multi_thread_streams = asInt(multi_thread_streams)) > 0) {
|
|
560
575
|
RCLONE.MULTI_THREAD_STREAMS = multi_thread_streams;
|
|
561
576
|
}
|
|
562
577
|
if (multi_thread_write_buffer_size = rcloneSize(multi_thread_write_buffer_size)) {
|
|
563
578
|
RCLONE.MULTI_THREAD_WRITE_BUFFER_SIZE = multi_thread_write_buffer_size;
|
|
564
579
|
}
|
|
580
|
+
if (order_by) {
|
|
581
|
+
RCLONE.ORDER_BY = order_by;
|
|
582
|
+
}
|
|
565
583
|
if (streaming_upload_cutoff = rcloneSize(streaming_upload_cutoff)) {
|
|
566
584
|
RCLONE.STREAMING_UPLOAD_CUTOFF = streaming_upload_cutoff;
|
|
567
585
|
}
|
|
@@ -582,22 +600,22 @@ class Request extends module_1 {
|
|
|
582
600
|
}
|
|
583
601
|
for (const name of ['combined', 'differ', 'error', 'config']) {
|
|
584
602
|
let value = rclone[name];
|
|
585
|
-
if (value === '' ||
|
|
603
|
+
if (value === '' || isString(value) && this.isPath(value = path.resolve(value), true)) {
|
|
586
604
|
RCLONE[name.toUpperCase()] = value;
|
|
587
605
|
}
|
|
588
606
|
}
|
|
589
607
|
}
|
|
590
608
|
if (request) {
|
|
591
609
|
let { read_timeout, max_concurrent_streams, agent, use, headers, certs } = request, agent_timeout;
|
|
592
|
-
if ((read_timeout =
|
|
610
|
+
if ((read_timeout = fromSeconds(read_timeout)) >= 0) {
|
|
593
611
|
READ_TIMEOUT = read_timeout;
|
|
594
612
|
}
|
|
595
|
-
if ((max_concurrent_streams =
|
|
613
|
+
if ((max_concurrent_streams = asInt(max_concurrent_streams)) > 0) {
|
|
596
614
|
MAX_CONCURRENT_STREAMS = max_concurrent_streams;
|
|
597
615
|
}
|
|
598
616
|
if (agent) {
|
|
599
617
|
let { keep_alive, timeout, proxy_env } = agent;
|
|
600
|
-
if ((agent_timeout =
|
|
618
|
+
if ((agent_timeout = fromSeconds(timeout)) > 0) {
|
|
601
619
|
AGENT_TIMEOUT = agent_timeout;
|
|
602
620
|
}
|
|
603
621
|
else {
|
|
@@ -609,7 +627,7 @@ class Request extends module_1 {
|
|
|
609
627
|
else {
|
|
610
628
|
keep_alive = undefined;
|
|
611
629
|
}
|
|
612
|
-
const keepAliveMsecs =
|
|
630
|
+
const keepAliveMsecs = asInt(agent.keep_alive_interval);
|
|
613
631
|
this.defineHttpAgent({ keepAlive: keep_alive, timeout: agent_timeout, proxyEnv: proxy_env, keepAliveMsecs: keepAliveMsecs > 0 ? keepAliveMsecs : undefined });
|
|
614
632
|
}
|
|
615
633
|
if (use) {
|
|
@@ -617,7 +635,7 @@ class Request extends module_1 {
|
|
|
617
635
|
if (typeof accept_encoding === 'boolean') {
|
|
618
636
|
ACCEPT_ENCODING = accept_encoding;
|
|
619
637
|
}
|
|
620
|
-
switch (http_version =
|
|
638
|
+
switch (http_version = asInt(http_version)) {
|
|
621
639
|
case 1:
|
|
622
640
|
case 2:
|
|
623
641
|
HTTP.VERSION = http_version;
|
|
@@ -625,15 +643,15 @@ class Request extends module_1 {
|
|
|
625
643
|
}
|
|
626
644
|
}
|
|
627
645
|
for (const href in headers) {
|
|
628
|
-
if (
|
|
629
|
-
HTTP.HEADERS[href] =
|
|
646
|
+
if (isObject(headers[href])) {
|
|
647
|
+
HTTP.HEADERS[href] = normalizeHeaders(headers[href]);
|
|
630
648
|
}
|
|
631
649
|
}
|
|
632
|
-
if (
|
|
650
|
+
if (isPlainObject(certs)) {
|
|
633
651
|
[TLS.TEXT, TLS.FILE] = validateCerts(certs);
|
|
634
652
|
}
|
|
635
653
|
HTTP.PROXY = getProxySettings(request, agent_timeout);
|
|
636
|
-
|
|
654
|
+
HttpHost.defineHostConfig(request);
|
|
637
655
|
if ('defineHostConfig' in HTTP_ADAPTER) {
|
|
638
656
|
HTTP_ADAPTER.defineHostConfig(request);
|
|
639
657
|
}
|
|
@@ -681,7 +699,7 @@ class Request extends module_1 {
|
|
|
681
699
|
DNS.FAMILY = 6;
|
|
682
700
|
break;
|
|
683
701
|
default:
|
|
684
|
-
switch (family =
|
|
702
|
+
switch (family = asInt(family)) {
|
|
685
703
|
case 0:
|
|
686
704
|
case 4:
|
|
687
705
|
case 6:
|
|
@@ -691,8 +709,8 @@ class Request extends module_1 {
|
|
|
691
709
|
break;
|
|
692
710
|
}
|
|
693
711
|
if (expires !== undefined) {
|
|
694
|
-
if (
|
|
695
|
-
expires =
|
|
712
|
+
if (isString(expires)) {
|
|
713
|
+
expires = parseExpires(expires);
|
|
696
714
|
}
|
|
697
715
|
if (expires >= 0) {
|
|
698
716
|
DNS.EXPIRES = expires !== Infinity ? Math.min(expires, this.MAX_TIMEOUT) : Infinity;
|
|
@@ -700,13 +718,13 @@ class Request extends module_1 {
|
|
|
700
718
|
}
|
|
701
719
|
for (const hostname in resolve) {
|
|
702
720
|
const { address, family: ipv } = resolve[hostname];
|
|
703
|
-
if (address && (family =
|
|
721
|
+
if (address && (family = asInt(ipv) && (family === 4 || family === 6) ? family : net.isIPv6(address) ? 6 : net.isIPv4(address) ? 4 : 0)) {
|
|
704
722
|
DNS.CACHE[hostname] = [{ address, family }];
|
|
705
723
|
}
|
|
706
724
|
}
|
|
707
725
|
}
|
|
708
726
|
static defineHttpAdapter(module) {
|
|
709
|
-
if (
|
|
727
|
+
if (HttpAdapter.constructorOf(module)) {
|
|
710
728
|
HTTP_ADAPTER = module;
|
|
711
729
|
}
|
|
712
730
|
}
|
|
@@ -754,22 +772,22 @@ class Request extends module_1 {
|
|
|
754
772
|
#session = [Object.create(null)];
|
|
755
773
|
constructor(data) {
|
|
756
774
|
super();
|
|
757
|
-
if (
|
|
775
|
+
if (isPlainObject(data)) {
|
|
758
776
|
const { headers, read_timeout, agent, use, connect, certs } = data;
|
|
759
|
-
const timeout =
|
|
777
|
+
const timeout = fromSeconds(data.timeout);
|
|
760
778
|
let value;
|
|
761
|
-
this.readTimeout = (value =
|
|
779
|
+
this.readTimeout = (value = fromSeconds(read_timeout)) >= 0 ? value : READ_TIMEOUT;
|
|
762
780
|
this.keepAlive = typeof (value = agent?.keep_alive) === 'boolean' ? value : KEEP_ALIVE;
|
|
763
781
|
this.acceptEncoding = typeof (value = use?.accept_encoding) === 'boolean' ? value : ACCEPT_ENCODING;
|
|
764
|
-
this.#ipVersion = (value =
|
|
765
|
-
if ((value =
|
|
782
|
+
this.#ipVersion = (value = asInt(data.dns?.family)) && (value === 4 || value === 6) ? value : 0;
|
|
783
|
+
if ((value = fromSeconds(agent?.timeout)) >= 0) {
|
|
766
784
|
this.#agentTimeout = value;
|
|
767
785
|
}
|
|
768
786
|
else {
|
|
769
787
|
this.#agentTimeout = AGENT_TIMEOUT;
|
|
770
788
|
value = undefined;
|
|
771
789
|
}
|
|
772
|
-
if ((value =
|
|
790
|
+
if ((value = asInt(use?.http_version)) === 1 || value === 2) {
|
|
773
791
|
this.#httpVersion = value;
|
|
774
792
|
}
|
|
775
793
|
const proxy = getProxySettings(data, value);
|
|
@@ -777,18 +795,20 @@ class Request extends module_1 {
|
|
|
777
795
|
this.proxy = proxy;
|
|
778
796
|
}
|
|
779
797
|
this.parseHeaders(headers);
|
|
780
|
-
if (
|
|
798
|
+
if (isObject(certs)) {
|
|
781
799
|
this.#certs = validateCerts(certs);
|
|
782
800
|
}
|
|
783
|
-
if (
|
|
784
|
-
this.apply({
|
|
801
|
+
if (isObject(connect)) {
|
|
802
|
+
this.apply({
|
|
803
|
+
client: {
|
|
785
804
|
timeout,
|
|
786
|
-
connectTimeout:
|
|
787
|
-
redirectLimit:
|
|
788
|
-
retryWait:
|
|
789
|
-
retryAfter:
|
|
790
|
-
retryLimit:
|
|
791
|
-
}
|
|
805
|
+
connectTimeout: fromSeconds(connect.timeout),
|
|
806
|
+
redirectLimit: asInt(connect.redirect_limit),
|
|
807
|
+
retryWait: fromSeconds(connect.retry_wait),
|
|
808
|
+
retryAfter: fromSeconds(connect.retry_after),
|
|
809
|
+
retryLimit: asInt(connect.retry_limit)
|
|
810
|
+
}
|
|
811
|
+
});
|
|
792
812
|
}
|
|
793
813
|
else if (timeout >= 0) {
|
|
794
814
|
this.apply({ client: { timeout } });
|
|
@@ -822,7 +842,7 @@ class Request extends module_1 {
|
|
|
822
842
|
const item = log[i];
|
|
823
843
|
if (item[1] === title && Array.isArray(item[2]) && item[2][0].startsWith(origin)) {
|
|
824
844
|
item[1] = '';
|
|
825
|
-
item[2][0] = item[2][0].
|
|
845
|
+
item[2][0] = item[2][0].slice(origin.length);
|
|
826
846
|
item[4].titleBgColor &&= undefined;
|
|
827
847
|
item[4].titleJustify = 'right';
|
|
828
848
|
args.push(item);
|
|
@@ -833,7 +853,7 @@ class Request extends module_1 {
|
|
|
833
853
|
count = Math.max(count, value);
|
|
834
854
|
}
|
|
835
855
|
});
|
|
836
|
-
if (
|
|
856
|
+
if (Module.hasLogType(32768)) {
|
|
837
857
|
output.sort((a, b) => {
|
|
838
858
|
if (a[2] === b[2]) {
|
|
839
859
|
return a[1] < b[1] ? -1 : 1;
|
|
@@ -842,7 +862,7 @@ class Request extends module_1 {
|
|
|
842
862
|
});
|
|
843
863
|
const width = count.toString().length;
|
|
844
864
|
for (const [title, origin, downloads, messages] of output) {
|
|
845
|
-
const options = { ...title === 'HTTP1' ?
|
|
865
|
+
const options = { ...title === 'HTTP1' ? Module.LOG_STYLE_NOTICE : Module.LOG_STYLE_INFO };
|
|
846
866
|
if (messages.length === 1) {
|
|
847
867
|
const message = messages[0];
|
|
848
868
|
message[1] = title;
|
|
@@ -892,7 +912,7 @@ class Request extends module_1 {
|
|
|
892
912
|
this.ipVersion = ipVersion;
|
|
893
913
|
}
|
|
894
914
|
if (readTimeout !== undefined) {
|
|
895
|
-
this.readTimeout =
|
|
915
|
+
this.readTimeout = fromSeconds(readTimeout);
|
|
896
916
|
}
|
|
897
917
|
}
|
|
898
918
|
return this;
|
|
@@ -916,7 +936,7 @@ class Request extends module_1 {
|
|
|
916
936
|
this._config.retryWait = Math.min(retryWait, 600 * 1000);
|
|
917
937
|
}
|
|
918
938
|
if (retryAfter >= 0) {
|
|
919
|
-
this._config.retryAfter = Math.min(retryAfter,
|
|
939
|
+
this._config.retryAfter = Math.min(retryAfter, Module.MAX_TIMEOUT);
|
|
920
940
|
}
|
|
921
941
|
if (retryLimit >= 0) {
|
|
922
942
|
this._config.retryLimit = retryLimit;
|
|
@@ -1056,7 +1076,7 @@ class Request extends module_1 {
|
|
|
1056
1076
|
let valid = true;
|
|
1057
1077
|
for (const value of exclude) {
|
|
1058
1078
|
if (value.startsWith('!')) {
|
|
1059
|
-
if (REGEXP_GLOBWITHIN.test(value.
|
|
1079
|
+
if (REGEXP_GLOBWITHIN.test(value.slice(1))) {
|
|
1060
1080
|
valid = true;
|
|
1061
1081
|
break;
|
|
1062
1082
|
}
|
|
@@ -1069,7 +1089,7 @@ class Request extends module_1 {
|
|
|
1069
1089
|
return;
|
|
1070
1090
|
}
|
|
1071
1091
|
}
|
|
1072
|
-
if (
|
|
1092
|
+
if (isArray(include) && !include.some(value => REGEXP_GLOBWITHIN.test(value) ? pm.isMatch(uri, value) : uri.startsWith(value))) {
|
|
1073
1093
|
return;
|
|
1074
1094
|
}
|
|
1075
1095
|
return proxy;
|
|
@@ -1080,9 +1100,9 @@ class Request extends module_1 {
|
|
|
1080
1100
|
callback = globUrl;
|
|
1081
1101
|
globUrl = '*';
|
|
1082
1102
|
}
|
|
1083
|
-
if (
|
|
1103
|
+
if (isString(globUrl) && typeof callback === 'function') {
|
|
1084
1104
|
const on = this.#statusOn ||= new Map();
|
|
1085
|
-
for (const item of
|
|
1105
|
+
for (const item of Array.isArray(code) ? code : [code]) {
|
|
1086
1106
|
let status = on.get(item);
|
|
1087
1107
|
if (!status) {
|
|
1088
1108
|
on.set(item, status = []);
|
|
@@ -1096,9 +1116,9 @@ class Request extends module_1 {
|
|
|
1096
1116
|
callback = globUrl;
|
|
1097
1117
|
globUrl = '*';
|
|
1098
1118
|
}
|
|
1099
|
-
if (
|
|
1119
|
+
if (isString(globUrl) && typeof callback === 'function') {
|
|
1100
1120
|
const on = this.#headersOn ||= new Map();
|
|
1101
|
-
for (const item of
|
|
1121
|
+
for (const item of Array.isArray(name) ? name : [name]) {
|
|
1102
1122
|
let headers = on.get(item);
|
|
1103
1123
|
if (!headers) {
|
|
1104
1124
|
on.set(item, headers = []);
|
|
@@ -1112,20 +1132,20 @@ class Request extends module_1 {
|
|
|
1112
1132
|
}
|
|
1113
1133
|
async aria2c(uri, options = {}) {
|
|
1114
1134
|
if (!ARIA2.BIN) {
|
|
1115
|
-
return Promise.reject(
|
|
1135
|
+
return Promise.reject(errorMessage("aria2", "Binary not found"));
|
|
1116
1136
|
}
|
|
1117
1137
|
let pathname, headers, binOpts, signal, silent;
|
|
1118
1138
|
if (typeof options === 'string') {
|
|
1119
1139
|
pathname = options;
|
|
1120
1140
|
}
|
|
1121
1141
|
else if (options instanceof URL) {
|
|
1122
|
-
pathname =
|
|
1142
|
+
pathname = fileURLToPath(options);
|
|
1123
1143
|
}
|
|
1124
1144
|
else {
|
|
1125
1145
|
({ signal, silent } = options);
|
|
1126
1146
|
({ pathname, headers, binOpts } = this.parseBinOpts(options, ['--daemon'], ['--input-file']));
|
|
1127
1147
|
}
|
|
1128
|
-
if (
|
|
1148
|
+
if (isString(uri) && Module.isURL(uri)) {
|
|
1129
1149
|
uri = new URL(uri);
|
|
1130
1150
|
}
|
|
1131
1151
|
pathname = checkBinTarget(this, "aria2", uri, pathname, 'aria2', binOpts);
|
|
@@ -1179,9 +1199,7 @@ class Request extends module_1 {
|
|
|
1179
1199
|
if (ARIA2.LOWEST_SPEED_LIMIT !== null) {
|
|
1180
1200
|
opts.push('--lowest-speed-limit=' + ARIA2.LOWEST_SPEED_LIMIT);
|
|
1181
1201
|
}
|
|
1182
|
-
|
|
1183
|
-
opts.push(`--conf-path="${escapeShellQuote(ARIA2.CONF_PATH)}"`);
|
|
1184
|
-
}
|
|
1202
|
+
quoteOpt(opts, 'conf-path', ARIA2.CONF_PATH);
|
|
1185
1203
|
if (!ARIA2.ALWAYS_RESUME) {
|
|
1186
1204
|
opts.push('--always-resume=false', '--keep-unfinished-download-result=false');
|
|
1187
1205
|
}
|
|
@@ -1194,9 +1212,7 @@ class Request extends module_1 {
|
|
|
1194
1212
|
if (retryWait > 0) {
|
|
1195
1213
|
opts.push('--retry-wait=' + Math.min(Math.ceil(retryWait / 1000), 600));
|
|
1196
1214
|
}
|
|
1197
|
-
|
|
1198
|
-
opts.push(`--no-proxy="${ARIA2.NO_PROXY}"`);
|
|
1199
|
-
}
|
|
1215
|
+
quoteOpt(opts, 'no-proxy', ARIA2.NO_PROXY);
|
|
1200
1216
|
let proxy;
|
|
1201
1217
|
if (protocol) {
|
|
1202
1218
|
if (this.agentTimeout === 0) {
|
|
@@ -1213,13 +1229,11 @@ class Request extends module_1 {
|
|
|
1213
1229
|
const secure = this.#certs?.[1][origin] || this.host && TLS.FILE[origin];
|
|
1214
1230
|
if (secure) {
|
|
1215
1231
|
if (secure.ca && ignoreOpt(binOpts, '--ca-certificate')) {
|
|
1216
|
-
args
|
|
1232
|
+
quoteOpt(args, 'ca-certificate', secure.ca);
|
|
1217
1233
|
}
|
|
1218
1234
|
if (secure.cert && ignoreOpt(binOpts, '--certificate', '--private-key')) {
|
|
1219
|
-
args
|
|
1220
|
-
|
|
1221
|
-
args.push(`--private-key="${escapeShellQuote(secure.key)}"`);
|
|
1222
|
-
}
|
|
1235
|
+
quoteOpt(args, 'certificate', secure.cert);
|
|
1236
|
+
quoteOpt(args, 'private-key', secure.key);
|
|
1223
1237
|
}
|
|
1224
1238
|
}
|
|
1225
1239
|
}
|
|
@@ -1233,10 +1247,10 @@ class Request extends module_1 {
|
|
|
1233
1247
|
const prefix = protocol === 'https' ? 'http' : protocol;
|
|
1234
1248
|
if (ignoreOpt(binOpts, `--${prefix}-user`, `--${prefix}-passwd`)) {
|
|
1235
1249
|
if (username) {
|
|
1236
|
-
args
|
|
1250
|
+
quoteOpt(args, `${prefix}-user`, decodeURIComponent(username));
|
|
1237
1251
|
}
|
|
1238
1252
|
if (password) {
|
|
1239
|
-
args
|
|
1253
|
+
quoteOpt(args, `${prefix}-passwd`, decodeURIComponent(password));
|
|
1240
1254
|
}
|
|
1241
1255
|
}
|
|
1242
1256
|
if (ignoreOpt(binOpts, `--${protocol}-proxy`, `--${protocol}-proxy-user`, `--${protocol}-proxy-passwd`)) {
|
|
@@ -1265,15 +1279,15 @@ class Request extends module_1 {
|
|
|
1265
1279
|
closeTorrent(pid);
|
|
1266
1280
|
reject(err);
|
|
1267
1281
|
};
|
|
1268
|
-
const { pid, stdout, stderr } = child_process.spawn(
|
|
1282
|
+
const { pid, stdout, stderr } = child_process.spawn(sanitizeCmd(ARIA2.BIN, args), { cwd: pathname, shell: true, signal: signal || this.signal, uid: ARIA2.EXEC_UID, gid: ARIA2.EXEC_GID })
|
|
1269
1283
|
.on('exit', code => {
|
|
1270
1284
|
closeTorrent(pid);
|
|
1271
1285
|
if (this.aborted) {
|
|
1272
|
-
errorResponse(pid,
|
|
1286
|
+
errorResponse(pid, createAbortError());
|
|
1273
1287
|
return;
|
|
1274
1288
|
}
|
|
1275
1289
|
if (code) {
|
|
1276
|
-
reject(
|
|
1290
|
+
reject(errorValue(message || "Unknown", 'Exit status: ' + code));
|
|
1277
1291
|
return;
|
|
1278
1292
|
}
|
|
1279
1293
|
const result = [];
|
|
@@ -1318,7 +1332,7 @@ class Request extends module_1 {
|
|
|
1318
1332
|
});
|
|
1319
1333
|
stdout.setEncoding('utf8').on('data', (value) => out += value);
|
|
1320
1334
|
stderr.setEncoding('utf8').on('data', (value) => message += value);
|
|
1321
|
-
if (pid !== undefined &&
|
|
1335
|
+
if (pid !== undefined && Module.isFile(uri, 'torrent')) {
|
|
1322
1336
|
if (!ARIA2.PID_TIMER) {
|
|
1323
1337
|
ARIA2.PID_TIMER = setInterval(() => {
|
|
1324
1338
|
if (ARIA2.PID_QUEUE.length === 0) {
|
|
@@ -1346,15 +1360,12 @@ class Request extends module_1 {
|
|
|
1346
1360
|
return;
|
|
1347
1361
|
}
|
|
1348
1362
|
if ((!ARIA2.UPDATE_BROADCAST_ONLY || item[2]) && this.host?.logState !== 0) {
|
|
1349
|
-
let progressBar;
|
|
1350
|
-
if (item[2]) {
|
|
1351
|
-
|
|
1352
|
-
}
|
|
1353
|
-
else {
|
|
1354
|
-
const current = (0, types_1.getLogCurrent)();
|
|
1363
|
+
let progressBar = true;
|
|
1364
|
+
if (!item[2]) {
|
|
1365
|
+
const current = getLogCurrent();
|
|
1355
1366
|
progressBar = current?.type === 128 && current.title === "aria2";
|
|
1356
1367
|
}
|
|
1357
|
-
this.formatMessage(128, "aria2", ['Downloading...',
|
|
1368
|
+
this.formatMessage(128, "aria2", ['Downloading...', formatTime(startTime, true)], (Module.PLATFORM_WIN32 ? 'taskkill /f /pid' : 'kill') + ` ${item[0]} -> ` + item[1], { ...Module.LOG_STYLE_INFO, progressBar, broadcastId: item[2] });
|
|
1358
1369
|
}
|
|
1359
1370
|
ARIA2.PID_QUEUE.push(item);
|
|
1360
1371
|
}
|
|
@@ -1366,7 +1377,7 @@ class Request extends module_1 {
|
|
|
1366
1377
|
}
|
|
1367
1378
|
async rclone(uri, options = {}) {
|
|
1368
1379
|
if (!RCLONE.BIN) {
|
|
1369
|
-
return Promise.reject(
|
|
1380
|
+
return Promise.reject(errorMessage("rclone", "Binary not found"));
|
|
1370
1381
|
}
|
|
1371
1382
|
uri = uri.toString();
|
|
1372
1383
|
let pathname, headers, binOpts, silent;
|
|
@@ -1375,7 +1386,7 @@ class Request extends module_1 {
|
|
|
1375
1386
|
options = {};
|
|
1376
1387
|
}
|
|
1377
1388
|
else if (options instanceof URL) {
|
|
1378
|
-
pathname =
|
|
1389
|
+
pathname = fileURLToPath(options);
|
|
1379
1390
|
options = {};
|
|
1380
1391
|
}
|
|
1381
1392
|
else {
|
|
@@ -1391,7 +1402,7 @@ class Request extends module_1 {
|
|
|
1391
1402
|
source = uri.replace(REGEXP_RCLONE, '');
|
|
1392
1403
|
break;
|
|
1393
1404
|
default:
|
|
1394
|
-
return Promise.reject(
|
|
1405
|
+
return Promise.reject(errorMessage("rclone", "Invalid command", command || uri));
|
|
1395
1406
|
}
|
|
1396
1407
|
pathname = checkBinTarget(this, "rclone", uri, pathname, command, binOpts);
|
|
1397
1408
|
silent ??= this.#singleton;
|
|
@@ -1428,6 +1439,13 @@ class Request extends module_1 {
|
|
|
1428
1439
|
if (RCLONE.CSV) {
|
|
1429
1440
|
opts.push('--csv');
|
|
1430
1441
|
}
|
|
1442
|
+
if (RCLONE.FORMAT) {
|
|
1443
|
+
opts.push('--format=' + RCLONE.FORMAT);
|
|
1444
|
+
}
|
|
1445
|
+
if (RCLONE.SEPARATOR) {
|
|
1446
|
+
opts.push('--separator=' + RCLONE.SEPARATOR);
|
|
1447
|
+
}
|
|
1448
|
+
quoteOpt(opts, 'timeformat', RCLONE.TIMEFORMAT);
|
|
1431
1449
|
if (RCLONE.HASH) {
|
|
1432
1450
|
opts.push('--hash=' + RCLONE.HASH);
|
|
1433
1451
|
}
|
|
@@ -1479,6 +1497,7 @@ class Request extends module_1 {
|
|
|
1479
1497
|
if (RCLONE.MULTI_THREAD_WRITE_BUFFER_SIZE) {
|
|
1480
1498
|
opts.push('--multi-thread-buffer-size=' + RCLONE.MULTI_THREAD_WRITE_BUFFER_SIZE);
|
|
1481
1499
|
}
|
|
1500
|
+
quoteOpt(opts, 'order-by', RCLONE.ORDER_BY);
|
|
1482
1501
|
if (RCLONE.NO_CHECK_DEST) {
|
|
1483
1502
|
opts.push('--no-check-dest');
|
|
1484
1503
|
}
|
|
@@ -1521,23 +1540,15 @@ class Request extends module_1 {
|
|
|
1521
1540
|
else if (this._config.timeout > 0) {
|
|
1522
1541
|
opts.push(`--timeout=${this._config.timeout}ms`);
|
|
1523
1542
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
opts.push(`--differ="${escapeShellQuote(RCLONE.DIFFER)}"`);
|
|
1529
|
-
}
|
|
1530
|
-
if (RCLONE.ERROR) {
|
|
1531
|
-
opts.push(`--error="${escapeShellQuote(RCLONE.ERROR)}"`);
|
|
1532
|
-
}
|
|
1533
|
-
if (RCLONE.CONFIG) {
|
|
1534
|
-
opts.push(`--config="${escapeShellQuote(RCLONE.CONFIG)}"`);
|
|
1535
|
-
}
|
|
1543
|
+
quoteOpt(opts, 'combined', RCLONE.COMBINED);
|
|
1544
|
+
quoteOpt(opts, 'differ', RCLONE.DIFFER);
|
|
1545
|
+
quoteOpt(opts, 'error', RCLONE.ERROR);
|
|
1546
|
+
quoteOpt(opts, 'config', RCLONE.CONFIG);
|
|
1536
1547
|
setBinHeaders(args, headers);
|
|
1537
|
-
const cwd =
|
|
1548
|
+
const cwd = Module.isDir(pathname) ? pathname : path.dirname(pathname);
|
|
1538
1549
|
const cmd = [source, pathname];
|
|
1539
1550
|
args = this.mergeBinOpts(args, opts, binOpts, { name: "rclone", bin: RCLONE.BIN, cmd }).concat(init, opts);
|
|
1540
|
-
args.push(...cmd.map(value =>
|
|
1551
|
+
args.push(...cmd.map(value => sanitizeCmd(value)));
|
|
1541
1552
|
args.unshift(command);
|
|
1542
1553
|
const startTime = Date.now();
|
|
1543
1554
|
const out = [];
|
|
@@ -1548,19 +1559,19 @@ class Request extends module_1 {
|
|
|
1548
1559
|
const parseOutput = (value) => {
|
|
1549
1560
|
try {
|
|
1550
1561
|
const data = JSON.parse(value);
|
|
1551
|
-
if (
|
|
1562
|
+
if (isPlainObject(data)) {
|
|
1552
1563
|
switch (data.level) {
|
|
1553
1564
|
case 'info':
|
|
1554
|
-
if (data.size > 0 &&
|
|
1565
|
+
if (data.size > 0 && isString(data.object)) {
|
|
1555
1566
|
out.push(data);
|
|
1556
1567
|
}
|
|
1557
|
-
else if (
|
|
1568
|
+
else if (isPlainObject(data.stats)) {
|
|
1558
1569
|
if (data.stats.fatalError) {
|
|
1559
1570
|
commitLog(2, data.msg);
|
|
1560
1571
|
}
|
|
1561
1572
|
else {
|
|
1562
1573
|
if (command === 'copyurl' && data.stats.totalTransfers > 0) {
|
|
1563
|
-
data.object =
|
|
1574
|
+
data.object = Module.isPath(pathname, true) ? pathname : '';
|
|
1564
1575
|
out.push(data);
|
|
1565
1576
|
}
|
|
1566
1577
|
commitLog(4, data.msg);
|
|
@@ -1577,14 +1588,14 @@ class Request extends module_1 {
|
|
|
1577
1588
|
commitLog(2, err);
|
|
1578
1589
|
}
|
|
1579
1590
|
};
|
|
1580
|
-
const { stdout, stderr } = child_process.spawn(
|
|
1591
|
+
const { stdout, stderr } = child_process.spawn(sanitizeCmd(RCLONE.BIN, args), { cwd, shell: true, signal: this.signal, uid: RCLONE.EXEC_UID, gid: RCLONE.EXEC_GID })
|
|
1581
1592
|
.on('exit', code => {
|
|
1582
1593
|
if (options.signal || this.aborted) {
|
|
1583
|
-
reject(
|
|
1594
|
+
reject(createAbortError());
|
|
1584
1595
|
return;
|
|
1585
1596
|
}
|
|
1586
1597
|
if (code) {
|
|
1587
|
-
reject(
|
|
1598
|
+
reject(errorValue("Unknown", 'Exit status: ' + code));
|
|
1588
1599
|
return;
|
|
1589
1600
|
}
|
|
1590
1601
|
if (out.length > 0 && !silent && LOG_HTTP && LOG_TIMEPROCESS) {
|
|
@@ -1642,15 +1653,15 @@ class Request extends module_1 {
|
|
|
1642
1653
|
}
|
|
1643
1654
|
let host;
|
|
1644
1655
|
if (this.host) {
|
|
1645
|
-
host = HTTP.HOST[url.origin] ||= new
|
|
1656
|
+
host = HTTP.HOST[url.origin] ||= new HttpHost(url, HTTP.VERSION);
|
|
1646
1657
|
}
|
|
1647
1658
|
else {
|
|
1648
|
-
host = this.#hostInfo[url.origin] ||= new
|
|
1659
|
+
host = this.#hostInfo[url.origin] ||= new HttpHost(url, this.httpVersion || 1);
|
|
1649
1660
|
}
|
|
1650
1661
|
return { ...options, host, url };
|
|
1651
1662
|
}
|
|
1652
1663
|
open(uri, options) {
|
|
1653
|
-
let { host, url, httpVersion, method = 'GET', search, encoding, format, socketPath, expectContinue = false, timeout = this._config.connectTimeout, outStream } = options, headers =
|
|
1664
|
+
let { host, url, httpVersion, method = 'GET', search, encoding, format, socketPath, expectContinue = false, timeout = this._config.connectTimeout, outStream } = options, headers = parseOutgoingHeaders(options.headers), getting = false, posting = false;
|
|
1654
1665
|
switch (method = method.toUpperCase()) {
|
|
1655
1666
|
case 'GET':
|
|
1656
1667
|
case 'DELETE':
|
|
@@ -1663,7 +1674,7 @@ class Request extends module_1 {
|
|
|
1663
1674
|
}
|
|
1664
1675
|
if (format) {
|
|
1665
1676
|
let parser;
|
|
1666
|
-
if (
|
|
1677
|
+
if (isObject(format)) {
|
|
1667
1678
|
({ out: format = 'json', parser } = format);
|
|
1668
1679
|
}
|
|
1669
1680
|
if (format.includes('/')) {
|
|
@@ -1689,7 +1700,7 @@ class Request extends module_1 {
|
|
|
1689
1700
|
break;
|
|
1690
1701
|
}
|
|
1691
1702
|
headers.accept += ', text/plain';
|
|
1692
|
-
options.encoding =
|
|
1703
|
+
options.encoding = getEncoding(encoding);
|
|
1693
1704
|
if (!options.outBlob) {
|
|
1694
1705
|
options.outFormat = { out: format, parser };
|
|
1695
1706
|
}
|
|
@@ -1780,7 +1791,7 @@ class Request extends module_1 {
|
|
|
1780
1791
|
else {
|
|
1781
1792
|
conn = session[0].at(-1);
|
|
1782
1793
|
}
|
|
1783
|
-
request = conn.request({ ...baseHeaders, ...
|
|
1794
|
+
request = conn.request({ ...baseHeaders, ...HttpHost.getBasicAuth(url), ...headers, ':path': pathname, ':method': method });
|
|
1784
1795
|
if (getting) {
|
|
1785
1796
|
const listenerMap = {};
|
|
1786
1797
|
const onEvent = request.on.bind(request);
|
|
@@ -1797,7 +1808,7 @@ class Request extends module_1 {
|
|
|
1797
1808
|
const contentEncoding = response['content-encoding'];
|
|
1798
1809
|
if (checkEncoding(request, statusCode, contentEncoding) && (emitter = this.pipeline(request, contentEncoding, outStream))) {
|
|
1799
1810
|
if (typeof emitter === 'number') {
|
|
1800
|
-
this.abortHeaders(request, options, { href: url.href, statusCode: emitter, message:
|
|
1811
|
+
this.abortHeaders(request, options, { href: url.href, statusCode: emitter, message: fromStatusCode(emitter) });
|
|
1801
1812
|
}
|
|
1802
1813
|
else {
|
|
1803
1814
|
for (const event in listenerMap) {
|
|
@@ -1820,7 +1831,7 @@ class Request extends module_1 {
|
|
|
1820
1831
|
});
|
|
1821
1832
|
}
|
|
1822
1833
|
if (encoding) {
|
|
1823
|
-
request.setEncoding(
|
|
1834
|
+
request.setEncoding(getEncoding(encoding));
|
|
1824
1835
|
}
|
|
1825
1836
|
}
|
|
1826
1837
|
if (LOG_HTTP) {
|
|
@@ -1906,7 +1917,7 @@ class Request extends module_1 {
|
|
|
1906
1917
|
}
|
|
1907
1918
|
}
|
|
1908
1919
|
}
|
|
1909
|
-
const basicAuth =
|
|
1920
|
+
const basicAuth = HttpHost.getBasicAuth(url);
|
|
1910
1921
|
if (baseHeaders || basicAuth) {
|
|
1911
1922
|
headers = { ...baseHeaders, ...basicAuth, ...headers };
|
|
1912
1923
|
}
|
|
@@ -1932,7 +1943,7 @@ class Request extends module_1 {
|
|
|
1932
1943
|
let source;
|
|
1933
1944
|
if (checkEncoding(request, statusCode, contentEncoding) && (source = this.pipeline(response, contentEncoding, outStream))) {
|
|
1934
1945
|
if (typeof source === 'number') {
|
|
1935
|
-
this.abortHeaders(request, options, { href: url.href, statusCode: source, message:
|
|
1946
|
+
this.abortHeaders(request, options, { href: url.href, statusCode: source, message: fromStatusCode(source) });
|
|
1936
1947
|
}
|
|
1937
1948
|
else {
|
|
1938
1949
|
source.once('finish', () => {
|
|
@@ -1942,7 +1953,7 @@ class Request extends module_1 {
|
|
|
1942
1953
|
}
|
|
1943
1954
|
else {
|
|
1944
1955
|
if (encoding) {
|
|
1945
|
-
response.setEncoding(
|
|
1956
|
+
response.setEncoding(getEncoding(encoding));
|
|
1946
1957
|
}
|
|
1947
1958
|
if (outStream) {
|
|
1948
1959
|
stream.pipeline(response, outStream, err => {
|
|
@@ -2061,7 +2072,7 @@ class Request extends module_1 {
|
|
|
2061
2072
|
return this.open(out.url, out);
|
|
2062
2073
|
}
|
|
2063
2074
|
async put(uri, data, contentType, options) {
|
|
2064
|
-
if (
|
|
2075
|
+
if (isPlainObject(contentType)) {
|
|
2065
2076
|
options = contentType;
|
|
2066
2077
|
}
|
|
2067
2078
|
else {
|
|
@@ -2080,7 +2091,7 @@ class Request extends module_1 {
|
|
|
2080
2091
|
contentType = undefined;
|
|
2081
2092
|
}
|
|
2082
2093
|
else {
|
|
2083
|
-
if (
|
|
2094
|
+
if (isPlainObject(contentType)) {
|
|
2084
2095
|
options = contentType;
|
|
2085
2096
|
putting = options.method === 'PUT';
|
|
2086
2097
|
contentType = undefined;
|
|
@@ -2091,7 +2102,7 @@ class Request extends module_1 {
|
|
|
2091
2102
|
}
|
|
2092
2103
|
}
|
|
2093
2104
|
let dataEncoding;
|
|
2094
|
-
if (
|
|
2105
|
+
if (isPlainObject(options)) {
|
|
2095
2106
|
if (!putting && options.formData) {
|
|
2096
2107
|
(parts ||= []).push(...Array.isArray(options.formData) ? options.formData : [options.formData]);
|
|
2097
2108
|
}
|
|
@@ -2103,12 +2114,12 @@ class Request extends module_1 {
|
|
|
2103
2114
|
else {
|
|
2104
2115
|
options = {};
|
|
2105
2116
|
}
|
|
2106
|
-
const headers =
|
|
2117
|
+
const headers = parseOutgoingHeaders(options.headers, 'content-type', 'content-length') || {};
|
|
2107
2118
|
if (!putting && (parts || contentType === "multipart/form-data" || contentType === 'form-data')) {
|
|
2108
2119
|
let valid = false;
|
|
2109
|
-
if (
|
|
2120
|
+
if (isArray(parts)) {
|
|
2110
2121
|
const write = combined.create();
|
|
2111
|
-
const boundary = crypto.randomUUID().
|
|
2122
|
+
const boundary = crypto.randomUUID().replace(/-/g, '');
|
|
2112
2123
|
contentType = "multipart/form-data" + `; boundary="${boundary}"`;
|
|
2113
2124
|
let contentLength = 0;
|
|
2114
2125
|
const createPart = (name, filename, type) => {
|
|
@@ -2120,33 +2131,33 @@ class Request extends module_1 {
|
|
|
2120
2131
|
};
|
|
2121
2132
|
const addValue = (name, value) => {
|
|
2122
2133
|
if (value !== undefined) {
|
|
2123
|
-
const disposition = createPart(name) +
|
|
2134
|
+
const disposition = createPart(name) + Module.asString(value) + "\r\n";
|
|
2124
2135
|
write.append(disposition);
|
|
2125
2136
|
contentLength += Buffer.byteLength(disposition);
|
|
2126
2137
|
}
|
|
2127
2138
|
};
|
|
2128
|
-
if (
|
|
2139
|
+
if (isPlainObject(data)) {
|
|
2129
2140
|
for (const name in data) {
|
|
2130
2141
|
addValue(name, data[name]);
|
|
2131
2142
|
}
|
|
2132
2143
|
}
|
|
2133
2144
|
for (const part of parts) {
|
|
2134
2145
|
let name, target, value, type, filename;
|
|
2135
|
-
if (
|
|
2146
|
+
if (isPlainObject(part)) {
|
|
2136
2147
|
({ name, data: target, value, contentType: type, filename } = part);
|
|
2137
2148
|
}
|
|
2138
|
-
else if (
|
|
2149
|
+
else if (supported(18, 13) && part instanceof File) {
|
|
2139
2150
|
name = part.name;
|
|
2140
2151
|
type = part.type;
|
|
2141
2152
|
target = Buffer.from(await part.arrayBuffer());
|
|
2142
2153
|
}
|
|
2143
|
-
if (!
|
|
2144
|
-
throw
|
|
2154
|
+
if (!isString(name)) {
|
|
2155
|
+
throw errorValue('Name of file part was invalid', uri.toString());
|
|
2145
2156
|
}
|
|
2146
2157
|
if (target) {
|
|
2147
2158
|
if (typeof target === 'string') {
|
|
2148
2159
|
filename ||= path.basename(target);
|
|
2149
|
-
type ||=
|
|
2160
|
+
type ||= Module.lookupMime(filename);
|
|
2150
2161
|
target = fs.readFileSync(target);
|
|
2151
2162
|
}
|
|
2152
2163
|
else if (stream.Readable.isReadable(target)) {
|
|
@@ -2157,17 +2168,17 @@ class Request extends module_1 {
|
|
|
2157
2168
|
target = Buffer.concat(chunks);
|
|
2158
2169
|
}
|
|
2159
2170
|
if (!Buffer.isBuffer(target)) {
|
|
2160
|
-
throw
|
|
2171
|
+
throw errorMessage('File', "Unknown", "multipart/form-data");
|
|
2161
2172
|
}
|
|
2162
2173
|
if (!type || !filename) {
|
|
2163
|
-
const result = await
|
|
2174
|
+
const result = await Module.resolveMime(target);
|
|
2164
2175
|
let ext;
|
|
2165
2176
|
if (result) {
|
|
2166
2177
|
type ||= result.mime;
|
|
2167
2178
|
ext = result.ext;
|
|
2168
2179
|
}
|
|
2169
2180
|
else if (type) {
|
|
2170
|
-
ext =
|
|
2181
|
+
ext = Module.lookupMime(type, true);
|
|
2171
2182
|
}
|
|
2172
2183
|
if (ext && !filename) {
|
|
2173
2184
|
filename = crypto.randomUUID() + '.' + ext;
|
|
@@ -2191,15 +2202,15 @@ class Request extends module_1 {
|
|
|
2191
2202
|
}
|
|
2192
2203
|
}
|
|
2193
2204
|
if (!valid) {
|
|
2194
|
-
return Promise.reject(
|
|
2205
|
+
return Promise.reject(errorValue("No files were attached", "multipart/form-data"));
|
|
2195
2206
|
}
|
|
2196
2207
|
}
|
|
2197
2208
|
else {
|
|
2198
2209
|
if (contentType && !contentType.includes('/')) {
|
|
2199
2210
|
contentType = 'application/' + contentType;
|
|
2200
2211
|
}
|
|
2201
|
-
if (!
|
|
2202
|
-
data =
|
|
2212
|
+
if (!isPlainObject(data)) {
|
|
2213
|
+
data = Module.asString(data);
|
|
2203
2214
|
}
|
|
2204
2215
|
else if (contentType === "application/x-www-form-urlencoded") {
|
|
2205
2216
|
data = qs.stringify(data);
|
|
@@ -2208,7 +2219,7 @@ class Request extends module_1 {
|
|
|
2208
2219
|
data = JSON.stringify(data);
|
|
2209
2220
|
contentType ||= "application/json";
|
|
2210
2221
|
}
|
|
2211
|
-
headers['content-length'] = Buffer.byteLength(data,
|
|
2222
|
+
headers['content-length'] = Buffer.byteLength(data, getEncoding(dataEncoding)).toString();
|
|
2212
2223
|
}
|
|
2213
2224
|
if (!putting) {
|
|
2214
2225
|
options.method = 'POST';
|
|
@@ -2222,7 +2233,7 @@ class Request extends module_1 {
|
|
|
2222
2233
|
async get(uri, options) {
|
|
2223
2234
|
const opts = (typeof options === 'string' ? { format: options, encoding: 'utf8' } : options || {});
|
|
2224
2235
|
if (this.readExpect === 'string') {
|
|
2225
|
-
opts.encoding =
|
|
2236
|
+
opts.encoding = getEncoding(opts.encoding);
|
|
2226
2237
|
}
|
|
2227
2238
|
const singleton = this.#singleton;
|
|
2228
2239
|
const verbose = !opts.silent && !singleton || opts.silent === false;
|
|
@@ -2373,7 +2384,7 @@ class Request extends module_1 {
|
|
|
2373
2384
|
return true;
|
|
2374
2385
|
}
|
|
2375
2386
|
abortHeaders(request, options, { href, statusCode = '', message = "Aborted by client" } = {}) {
|
|
2376
|
-
const reason =
|
|
2387
|
+
const reason = errorMessage(statusCode, message, href);
|
|
2377
2388
|
const outAbort = options.outAbort;
|
|
2378
2389
|
if (outAbort) {
|
|
2379
2390
|
outAbort.abort(reason);
|
|
@@ -2384,19 +2395,19 @@ class Request extends module_1 {
|
|
|
2384
2395
|
parseBinOpts(options, ignore, skip, doubleQuote = options.shellExpansion) {
|
|
2385
2396
|
let pathname = options.pathname, binOpts;
|
|
2386
2397
|
if (pathname instanceof URL) {
|
|
2387
|
-
pathname =
|
|
2398
|
+
pathname = fileURLToPath(pathname);
|
|
2388
2399
|
}
|
|
2389
|
-
else if (!
|
|
2400
|
+
else if (!isString(pathname)) {
|
|
2390
2401
|
if (!this.host) {
|
|
2391
2402
|
return {};
|
|
2392
2403
|
}
|
|
2393
2404
|
pathname = process.cwd();
|
|
2394
2405
|
}
|
|
2395
|
-
if (
|
|
2406
|
+
if (isArray(options.binOpts)) {
|
|
2396
2407
|
let next = false;
|
|
2397
|
-
binOpts = options.binOpts.filter((opt) => !(
|
|
2408
|
+
binOpts = options.binOpts.filter((opt) => !(isString(opt) && /^-[a-z].*$/i.test(opt))).map((opt) => {
|
|
2398
2409
|
if (next) {
|
|
2399
|
-
if (!
|
|
2410
|
+
if (!Module.asString(opt).startsWith('--')) {
|
|
2400
2411
|
return [];
|
|
2401
2412
|
}
|
|
2402
2413
|
next = false;
|
|
@@ -2421,12 +2432,12 @@ class Request extends module_1 {
|
|
|
2421
2432
|
case '--help':
|
|
2422
2433
|
return [];
|
|
2423
2434
|
default:
|
|
2424
|
-
return match[3] ? [match[1] + '=' +
|
|
2435
|
+
return match[3] ? [match[1] + '=' + sanitizeArgs(match[3], doubleQuote)] : [match[1]];
|
|
2425
2436
|
}
|
|
2426
2437
|
}
|
|
2427
2438
|
}
|
|
2428
2439
|
else if (value) {
|
|
2429
|
-
return [
|
|
2440
|
+
return [sanitizeArgs(value, doubleQuote)];
|
|
2430
2441
|
}
|
|
2431
2442
|
break;
|
|
2432
2443
|
}
|
|
@@ -2434,15 +2445,15 @@ class Request extends module_1 {
|
|
|
2434
2445
|
case 'boolean':
|
|
2435
2446
|
return [opt.toString()];
|
|
2436
2447
|
default:
|
|
2437
|
-
if (
|
|
2438
|
-
return opt.filter(item =>
|
|
2448
|
+
if (isArray(opt)) {
|
|
2449
|
+
return opt.filter(item => isString(item)).map(item => sanitizeArgs(item, doubleQuote));
|
|
2439
2450
|
}
|
|
2440
2451
|
break;
|
|
2441
2452
|
}
|
|
2442
2453
|
return [];
|
|
2443
2454
|
}).flat();
|
|
2444
2455
|
}
|
|
2445
|
-
return { pathname, headers:
|
|
2456
|
+
return { pathname, headers: parseOutgoingHeaders(options.headers), binOpts };
|
|
2446
2457
|
}
|
|
2447
2458
|
mergeBinOpts(args, opts, binOpts, options) {
|
|
2448
2459
|
if (binOpts) {
|
|
@@ -2461,8 +2472,8 @@ class Request extends module_1 {
|
|
|
2461
2472
|
}
|
|
2462
2473
|
if (options && args.length > 0) {
|
|
2463
2474
|
const { name, bin, cmd = [] } = options;
|
|
2464
|
-
if (
|
|
2465
|
-
this.formatMessage(32768, name.toUpperCase(), [bin].concat(cmd).join(' '), args.join(' '), { ...
|
|
2475
|
+
if (Module.hasLogType(32768)) {
|
|
2476
|
+
this.formatMessage(32768, name.toUpperCase(), [bin].concat(cmd).join(' '), args.join(' '), { ...Module.LOG_STYLE_WARN });
|
|
2466
2477
|
}
|
|
2467
2478
|
else {
|
|
2468
2479
|
this.addLog(4, path.basename(bin) + ' ' + args.join(' '), name);
|
|
@@ -2471,14 +2482,14 @@ class Request extends module_1 {
|
|
|
2471
2482
|
return args;
|
|
2472
2483
|
}
|
|
2473
2484
|
parseHeaders(outgoing) {
|
|
2474
|
-
if (
|
|
2485
|
+
if (isPlainObject(outgoing)) {
|
|
2475
2486
|
Object.assign(this.#headers ||= {}, outgoing);
|
|
2476
2487
|
}
|
|
2477
2488
|
}
|
|
2478
2489
|
findHeadersByUri(uri, outgoing = this.#headers) {
|
|
2479
2490
|
if (outgoing) {
|
|
2480
2491
|
const data = [];
|
|
2481
|
-
uri =
|
|
2492
|
+
uri = trimPath(uri);
|
|
2482
2493
|
for (const pathname in outgoing) {
|
|
2483
2494
|
if (pathname === uri || uri.startsWith(pathname + '/')) {
|
|
2484
2495
|
data.push([pathname, outgoing[pathname]]);
|
|
@@ -2489,7 +2500,7 @@ class Request extends module_1 {
|
|
|
2489
2500
|
const headers = data[0][1];
|
|
2490
2501
|
let result = HTTP.CACHE.get(headers);
|
|
2491
2502
|
if (!result) {
|
|
2492
|
-
result =
|
|
2503
|
+
result = normalizeHeaders(headers);
|
|
2493
2504
|
HTTP.CACHE.set(headers, result);
|
|
2494
2505
|
}
|
|
2495
2506
|
return result;
|
|
@@ -2497,7 +2508,7 @@ class Request extends module_1 {
|
|
|
2497
2508
|
}
|
|
2498
2509
|
}
|
|
2499
2510
|
set adapter(value) {
|
|
2500
|
-
if (
|
|
2511
|
+
if (HttpAdapter.constructorOf(value)) {
|
|
2501
2512
|
this.#adapter = value;
|
|
2502
2513
|
}
|
|
2503
2514
|
}
|
|
@@ -2541,4 +2552,5 @@ class Request extends module_1 {
|
|
|
2541
2552
|
return this.module.settings ||= {};
|
|
2542
2553
|
}
|
|
2543
2554
|
}
|
|
2555
|
+
|
|
2544
2556
|
module.exports = Request;
|