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