@e-mc/request 0.8.20 → 0.8.22

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/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2024 An Pham
1
+ Copyright 2023 An Pham
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  ## Interface
11
11
 
12
- - https://www.unpkg.com/@e-mc/types@0.8.20/lib/index.d.ts
12
+ - https://www.unpkg.com/@e-mc/types@0.8.22/lib/index.d.ts
13
13
 
14
14
  ```typescript
15
15
  import type { IModule, ModuleConstructor } from "./index";
@@ -82,9 +82,9 @@ interface RequestConstructor extends ModuleConstructor {
82
82
 
83
83
  ## References
84
84
 
85
- - https://www.unpkg.com/@e-mc/types@0.8.20/lib/http.d.ts
86
- - https://www.unpkg.com/@e-mc/types@0.8.20/lib/request.d.ts
87
- - https://www.unpkg.com/@e-mc/types@0.8.20/lib/settings.d.ts
85
+ - https://www.unpkg.com/@e-mc/types@0.8.22/lib/http.d.ts
86
+ - https://www.unpkg.com/@e-mc/types@0.8.22/lib/request.d.ts
87
+ - https://www.unpkg.com/@e-mc/types@0.8.22/lib/settings.d.ts
88
88
 
89
89
  ## LICENSE
90
90
 
@@ -0,0 +1,561 @@
1
+ "use strict";
2
+ const fs = require("node:fs");
3
+ const http2 = require("node:http2");
4
+ const yaml = require("js-yaml");
5
+ const types_1 = require("@e-mc/types");
6
+ const module_1 = require("@e-mc/module");
7
+ const util_1 = require("@e-mc/request/util");
8
+ const kOutStream = Symbol('outStream');
9
+ const kOptions = Symbol('options');
10
+ let LOG_TIMEFORMAT = 'readable';
11
+ class HttpAdapter {
12
+ instance;
13
+ state;
14
+ uri;
15
+ static isUnsupported(value) {
16
+ return value === 421 || value === 505;
17
+ }
18
+ static isDowngrade(err) {
19
+ return err instanceof Error && (err.code === 'ERR_HTTP2_ERROR' || this.isUnsupported(Math.abs(err.errno)));
20
+ }
21
+ static wasAborted(err) {
22
+ return err instanceof Error && err.message.startsWith("Aborted");
23
+ }
24
+ static isConnectionError(err) {
25
+ switch (err instanceof Error && err.code) {
26
+ case 'ETIMEDOUT':
27
+ case 'ECONNRESET':
28
+ return true;
29
+ default:
30
+ return false;
31
+ }
32
+ }
33
+ static defineHostConfig({ settings }) {
34
+ const time_format = settings?.time_format;
35
+ switch (time_format) {
36
+ case 'readable':
37
+ case 'relative':
38
+ case 'none':
39
+ LOG_TIMEFORMAT = time_format;
40
+ break;
41
+ }
42
+ }
43
+ contentLength = 0;
44
+ retries = 0;
45
+ redirects = 0;
46
+ closed = false;
47
+ aborted = false;
48
+ timeout = null;
49
+ dataTime = null;
50
+ delayTime = undefined;
51
+ opts;
52
+ client;
53
+ resolve;
54
+ reject;
55
+ startTime;
56
+ [kOutStream] = null;
57
+ [kOptions];
58
+ constructor(instance, state, uri, options) {
59
+ this.instance = instance;
60
+ this.state = state;
61
+ this.uri = uri;
62
+ this[kOptions] = options;
63
+ this.startTime = state.log ? process.hrtime.bigint() : BigInt(0);
64
+ this.setOpts();
65
+ }
66
+ async start() {
67
+ return new Promise((resolve, reject) => {
68
+ this.resolve = resolve;
69
+ this.reject = reject;
70
+ this.init();
71
+ });
72
+ }
73
+ init() {
74
+ this.aborted = false;
75
+ this.setWriteStream();
76
+ this.client = this.instance.open(this.uri, this.opts);
77
+ if (this.opts.httpVersion === 2) {
78
+ this.client
79
+ .on('response', (headers, flags) => {
80
+ if (this.destroyed) {
81
+ return;
82
+ }
83
+ const statusCode = headers[':status'];
84
+ if (statusCode < 300) {
85
+ this.acceptResponse(headers);
86
+ }
87
+ else if (statusCode < 400) {
88
+ this.redirectResponse(statusCode, headers.location);
89
+ }
90
+ else if (statusCode === 401 ||
91
+ statusCode === 402 ||
92
+ statusCode === 403 ||
93
+ statusCode === 404 ||
94
+ statusCode === 407 ||
95
+ statusCode === 410) {
96
+ this.terminate(this.formatStatus(statusCode));
97
+ }
98
+ else if (this.isRetry(statusCode)) {
99
+ this.retryResponse(statusCode, headers['retry-after']);
100
+ }
101
+ else if (HttpAdapter.isUnsupported(statusCode)) {
102
+ this.retryDownload(true, this.formatNgFlags(http2.constants.NGHTTP2_PROTOCOL_ERROR, statusCode));
103
+ }
104
+ else {
105
+ switch (flags) {
106
+ case http2.constants.NGHTTP2_PROTOCOL_ERROR:
107
+ case http2.constants.NGHTTP2_INADEQUATE_SECURITY:
108
+ case http2.constants.NGHTTP2_HTTP_1_1_REQUIRED:
109
+ this.retryDownload(true, this.formatNgFlags(flags, statusCode, headers.location));
110
+ break;
111
+ default:
112
+ this.retryDownload(false, this.formatStatus(statusCode));
113
+ break;
114
+ }
115
+ }
116
+ })
117
+ .on('unknownProtocol', () => {
118
+ if (this.aborted) {
119
+ return;
120
+ }
121
+ this.retryDownload(true, 'Unknown protocol (HTTP/2)');
122
+ })
123
+ .on('aborted', () => {
124
+ this.aborted = true;
125
+ this.terminate((0, types_1.createAbortError)());
126
+ })
127
+ .on('error', async (err) => {
128
+ if (this.aborted) {
129
+ return;
130
+ }
131
+ if (HttpAdapter.wasAborted(err)) {
132
+ this.errorResponse(err);
133
+ }
134
+ else {
135
+ switch (!HttpAdapter.isDowngrade(err) && await this.host.hasProtocol(2)) {
136
+ case 1:
137
+ this.errorResponse(err);
138
+ break;
139
+ case 2:
140
+ this.retryDownload(false, err);
141
+ break;
142
+ default:
143
+ this.retryDownload(true, err);
144
+ break;
145
+ }
146
+ }
147
+ });
148
+ }
149
+ else {
150
+ this.client
151
+ .on('response', res => {
152
+ if (this.destroyed) {
153
+ return;
154
+ }
155
+ const statusCode = res.statusCode;
156
+ if (statusCode < 300) {
157
+ this.acceptResponse(res.headers);
158
+ }
159
+ else if (statusCode < 400) {
160
+ this.redirectResponse(statusCode, res.headers.location);
161
+ }
162
+ else if (this.isRetry(statusCode)) {
163
+ this.retryResponse(statusCode, res.headers['retry-after']);
164
+ }
165
+ else {
166
+ this.terminate(this.formatStatus(statusCode));
167
+ }
168
+ })
169
+ .on('abort', () => {
170
+ this.aborted = true;
171
+ this.terminate((0, types_1.createAbortError)());
172
+ })
173
+ .on('error', err => {
174
+ if (this.aborted) {
175
+ return;
176
+ }
177
+ this.errorResponse(err);
178
+ });
179
+ }
180
+ this.client.on('timeout', () => {
181
+ if (this.aborted) {
182
+ return;
183
+ }
184
+ if (++this.retries <= this.retryLimit) {
185
+ this.abortResponse();
186
+ this.retryTimeout();
187
+ }
188
+ else {
189
+ this.terminate(this.formatStatus(408));
190
+ }
191
+ });
192
+ }
193
+ setOpts(uri) {
194
+ if (uri) {
195
+ this.uri = uri;
196
+ }
197
+ this.opts = this.instance.opts(this.uri, this[kOptions]);
198
+ }
199
+ setWriteStream() {
200
+ const pipeTo = this.pipeTo;
201
+ if (typeof pipeTo === 'string') {
202
+ try {
203
+ this.outStream = fs.createWriteStream(pipeTo, { emitClose: false, highWaterMark: this.host.streamSize });
204
+ }
205
+ catch (err) {
206
+ this.terminate(err);
207
+ }
208
+ }
209
+ else if (pipeTo) {
210
+ this.outStream = pipeTo;
211
+ }
212
+ }
213
+ retryDownload(downgrade, message) {
214
+ if (this.aborted) {
215
+ return;
216
+ }
217
+ this.abortResponse();
218
+ if (downgrade) {
219
+ const host = this.host;
220
+ host.failed(2);
221
+ if (host.version > 1) {
222
+ if (this.state.verbose) {
223
+ this.instance.formatMessage(1024, 'HTTP2', ["Unsupported protocol", host.origin], message, { failed: true });
224
+ }
225
+ host.version = 1;
226
+ }
227
+ }
228
+ this.opts.httpVersion = 1;
229
+ this.init();
230
+ }
231
+ acceptResponse(headers) {
232
+ const opts = this.opts;
233
+ if ('outHeaders' in opts) {
234
+ opts.outHeaders = headers;
235
+ }
236
+ if ('outFilename' in opts) {
237
+ opts.outFilename = (0, util_1.parseHeader)(headers, 'content-disposition');
238
+ }
239
+ const pipeline = this.pipeTo ? !(0, types_1.isString)(this.pipeTo) : false;
240
+ const enabled = opts.connected?.call(this.client, headers) !== false && !pipeline;
241
+ const maxBufferSize = opts.maxBufferSize ? (0, types_1.alignSize)(opts.maxBufferSize) : 0;
242
+ this.contentLength = parseInt(headers['content-length'] || '0');
243
+ const updating = opts.progressId !== undefined && !!this.instance.host && this.contentLength > 0;
244
+ const readTimeout = this.instance.readTimeout;
245
+ let log = this.state.log, buffer = null, dataLength = 0;
246
+ this.client.once('readable', () => {
247
+ if (readTimeout > 0) {
248
+ this.timeout = setTimeout(() => {
249
+ this.terminate((0, types_1.errorValue)("Timeout was exceeded", this.uri.toString()));
250
+ }, readTimeout);
251
+ }
252
+ if (log) {
253
+ switch (this.instance.settings?.time_format || LOG_TIMEFORMAT) {
254
+ case 'readable':
255
+ this.delayTime = process.hrtime.bigint() - this.startTime;
256
+ break;
257
+ case 'relative':
258
+ this.delayTime = Date.now() - this.instance.startTime;
259
+ break;
260
+ case 'none':
261
+ if (!this.silent) {
262
+ log = false;
263
+ }
264
+ break;
265
+ }
266
+ }
267
+ this.dataTime = process.hrtime.bigint();
268
+ if (updating) {
269
+ this.updateProgress(0, 0);
270
+ }
271
+ });
272
+ if (enabled) {
273
+ const encoding = opts.encoding;
274
+ this.client.on('data', (chunk) => {
275
+ if (buffer) {
276
+ if (typeof buffer === 'string') {
277
+ buffer += typeof chunk === 'string' ? chunk : chunk.toString(encoding);
278
+ }
279
+ else if (Array.isArray(buffer)) {
280
+ buffer.push(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk);
281
+ }
282
+ else {
283
+ buffer = Buffer.concat([buffer, typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk]);
284
+ }
285
+ }
286
+ else {
287
+ buffer = typeof chunk === 'string' ? chunk : [chunk];
288
+ }
289
+ if (updating) {
290
+ dataLength += Buffer.byteLength(chunk, encoding);
291
+ this.updateProgress(dataLength, this.contentLength);
292
+ }
293
+ if (maxBufferSize > 0) {
294
+ if (!updating) {
295
+ dataLength += Buffer.byteLength(chunk, encoding);
296
+ }
297
+ if (dataLength > maxBufferSize) {
298
+ this.terminate((0, types_1.errorValue)("Size limit was exceeded", this.uri.toString()));
299
+ }
300
+ }
301
+ });
302
+ }
303
+ this.client.once('end', () => {
304
+ if (this.closed || this.aborted) {
305
+ return;
306
+ }
307
+ this.close();
308
+ const encoding = opts.encoding;
309
+ let result;
310
+ if (buffer) {
311
+ if (Array.isArray(buffer)) {
312
+ buffer = Buffer.concat(buffer);
313
+ if (encoding) {
314
+ buffer = buffer.toString(encoding);
315
+ }
316
+ }
317
+ dataLength = Buffer.byteLength(buffer, encoding);
318
+ if (updating) {
319
+ this.updateProgress(dataLength, dataLength);
320
+ }
321
+ if (typeof buffer === 'string') {
322
+ if (buffer.startsWith('\uFEFF') && encoding !== 'utf16le' && encoding !== 'utf-16le') {
323
+ buffer = buffer.substring(1);
324
+ }
325
+ if (opts.outFormat) {
326
+ const { out: format, parser } = opts.outFormat;
327
+ let packageName;
328
+ try {
329
+ switch (format) {
330
+ case 'yaml':
331
+ result = yaml.load(buffer, parser);
332
+ break;
333
+ case 'json5':
334
+ result = require(packageName = 'json5').parse(buffer);
335
+ break;
336
+ case 'xml':
337
+ result = new (require(packageName = 'fast-xml-parser').XMLParser)(parser).parse(buffer);
338
+ break;
339
+ case 'toml':
340
+ result = require(packageName = 'toml').parse(buffer);
341
+ break;
342
+ default:
343
+ result = JSON.parse(buffer);
344
+ break;
345
+ }
346
+ if (!(0, types_1.isObject)(result)) {
347
+ result = null;
348
+ }
349
+ }
350
+ catch (err) {
351
+ if (this.state.verbose && !(packageName && this.instance.checkPackage(err, packageName))) {
352
+ this.instance.writeFail(["Unable to parse URI response", format], err, 1024);
353
+ }
354
+ result = null;
355
+ }
356
+ }
357
+ }
358
+ if (result === undefined) {
359
+ result = buffer;
360
+ }
361
+ }
362
+ else {
363
+ if (updating) {
364
+ this.updateProgress(0, this.contentLength);
365
+ }
366
+ if (enabled && this.instance.readExpect === 'always') {
367
+ this.terminate("No data received");
368
+ return;
369
+ }
370
+ result = encoding && !pipeline ? '' : null;
371
+ }
372
+ this.endResponse(result, dataLength, log);
373
+ });
374
+ this.host.success(this.httpVersion);
375
+ }
376
+ updateProgress(dataLength, contentLength) {
377
+ const { host, moduleName } = this.instance;
378
+ host.updateProgress(moduleName, this.opts.progressId, dataLength, contentLength, this.dataTime);
379
+ }
380
+ endResponse(result, dataLength = 0, logging = this.state.log) {
381
+ if (logging) {
382
+ const messageUnit = this.dataTime && dataLength > 0 ? (0, util_1.getTransferRate)(dataLength, (0, types_1.convertTime)(process.hrtime.bigint() - this.dataTime, false) * 1000) : undefined;
383
+ this.instance.writeTimeProcess('HTTP' + this.httpVersion, this.opts.statusMessage || this.uri.toString(), this.startTime, {
384
+ type: 1024,
385
+ queue: !!this.instance.host,
386
+ titleBgColor: !result ? 'bgBlue' : undefined,
387
+ messageUnit,
388
+ messageUnitMinWidth: 9,
389
+ delayTime: this.delayTime,
390
+ bypassLog: module_1.hasLogType(32768)
391
+ });
392
+ }
393
+ this.resolve(result);
394
+ }
395
+ redirectResponse(statusCode, location) {
396
+ if (location) {
397
+ if (this.opts.followRedirect === false) {
398
+ this.terminate(this.formatStatus(statusCode, "Follow redirect was disabled"));
399
+ }
400
+ else if (++this.redirects <= this.redirectLimit) {
401
+ this.abortResponse();
402
+ this.setOpts((0, util_1.fromURL)(this.opts.url, location));
403
+ this.init();
404
+ }
405
+ else {
406
+ this.terminate(this.formatStatus(statusCode, "Exceeded redirect limit"));
407
+ }
408
+ }
409
+ else {
410
+ this.terminate(this.formatStatus(statusCode, "Missing redirect location"));
411
+ }
412
+ }
413
+ abortResponse() {
414
+ if (this.closed) {
415
+ return;
416
+ }
417
+ this.aborted = true;
418
+ this.client.destroy();
419
+ this.instance.reset(this);
420
+ this.cleanup();
421
+ }
422
+ errorResponse(err) {
423
+ if (HttpAdapter.wasAborted(err)) {
424
+ this.terminate(err);
425
+ }
426
+ else if ((0, util_1.checkRetryable)(err) && ++this.retries <= this.retryLimit) {
427
+ this.abortResponse();
428
+ if (HttpAdapter.isConnectionError(err)) {
429
+ this.retryTimeout();
430
+ }
431
+ else {
432
+ setTimeout(() => {
433
+ this.init();
434
+ }, this.retryWait);
435
+ }
436
+ }
437
+ else {
438
+ this.host.error(this.httpVersion);
439
+ this.terminate(err);
440
+ }
441
+ }
442
+ retryResponse(statusCode, retryAfter) {
443
+ this.abortResponse();
444
+ if (retryAfter && this.retryAfter > 0) {
445
+ let offset = +retryAfter || new Date(retryAfter);
446
+ if (offset instanceof Date) {
447
+ offset = Math.max(0, offset.getTime() - Date.now());
448
+ }
449
+ else {
450
+ offset *= 1000;
451
+ }
452
+ if (offset > 0) {
453
+ if (offset <= this.retryAfter) {
454
+ this.sendWarning(`Retry After (${retryAfter})`);
455
+ setTimeout(() => {
456
+ this.init();
457
+ }, offset);
458
+ }
459
+ else {
460
+ this.terminate(this.formatStatus(statusCode));
461
+ }
462
+ return;
463
+ }
464
+ }
465
+ this.sendWarning(this.formatRetry((0, util_1.fromStatusCode)(statusCode)));
466
+ if ((0, util_1.isRetryable)(statusCode, true)) {
467
+ setImmediate(this.init.bind(this));
468
+ }
469
+ else {
470
+ setTimeout(() => {
471
+ this.init();
472
+ }, this.retryWait);
473
+ }
474
+ }
475
+ isRetry(value) {
476
+ return (0, util_1.isRetryable)(value) && ++this.retries <= this.retryLimit;
477
+ }
478
+ retryTimeout() {
479
+ this.sendWarning(this.formatRetry("HTTP connection timeout"));
480
+ this.init();
481
+ }
482
+ terminate(err) {
483
+ if (this.closed) {
484
+ return;
485
+ }
486
+ this.cleanup();
487
+ this.close();
488
+ this.reject(typeof err === 'string' ? new Error(err) : err);
489
+ }
490
+ sendWarning(message) {
491
+ if (this.state.verbose) {
492
+ const { host, url } = this.opts;
493
+ this.instance.formatMessage(1024, 'HTTP' + this.httpVersion, [message, host.origin], url.toString(), { ...module_1.LOG_STYLE_WARN });
494
+ }
495
+ }
496
+ formatStatus(value, hint) {
497
+ return value + ': ' + (hint || (0, util_1.fromStatusCode)(value)) + ` (${this.uri.toString()})`;
498
+ }
499
+ close() {
500
+ this.closed = true;
501
+ this.instance.reset(this);
502
+ if (this.aborted && !this.client.aborted) {
503
+ this.abortController?.abort();
504
+ }
505
+ }
506
+ cleanup() {
507
+ if ((0, types_1.isString)(this.pipeTo) && this.outStream) {
508
+ (0, util_1.cleanupStream)(this.outStream, this.pipeTo);
509
+ this.outStream = null;
510
+ }
511
+ }
512
+ formatNgFlags(value, statusCode, location) {
513
+ return location ? `Using HTTP 1.1 for URL redirect (${location})` : this.formatStatus(statusCode, value ? 'NGHTTP2 Error ' + value : '');
514
+ }
515
+ formatRetry(message) {
516
+ return `${message} (${this.retries} / ${this.retryLimit})`;
517
+ }
518
+ set abortController(value) {
519
+ this.opts.outAbort = value;
520
+ }
521
+ get abortController() {
522
+ return this.opts.outAbort || null;
523
+ }
524
+ set outStream(value) {
525
+ this[kOutStream] = value;
526
+ if (value) {
527
+ this.opts.outStream = value;
528
+ }
529
+ }
530
+ get outStream() {
531
+ return this[kOutStream];
532
+ }
533
+ get destroyed() {
534
+ return this.client.destroyed || this.httpVersion === 2 && this.client.aborted;
535
+ }
536
+ get host() {
537
+ return this.opts.host;
538
+ }
539
+ get httpVersion() {
540
+ return this.opts.httpVersion;
541
+ }
542
+ get pipeTo() {
543
+ return this.opts.pipeTo;
544
+ }
545
+ get silent() {
546
+ return this.opts.silent === false;
547
+ }
548
+ get retryLimit() {
549
+ return this.state.config.retryLimit;
550
+ }
551
+ get retryWait() {
552
+ return this.state.config.retryWait;
553
+ }
554
+ get retryAfter() {
555
+ return this.state.config.retryAfter;
556
+ }
557
+ get redirectLimit() {
558
+ return this.state.config.redirectLimit;
559
+ }
560
+ }
561
+ module.exports = HttpAdapter;
package/index.js CHANGED
@@ -316,8 +316,8 @@ function decompressEncoding(value, chunkSize) {
316
316
  break;
317
317
  }
318
318
  }
319
- function abortHeaders(href, request, options) {
320
- const reason = (0, types_1.errorValue)("Aborted by client", href);
319
+ function abortHeaders(href, request, options, statusCode = '') {
320
+ const reason = (0, types_1.errorMessage)(statusCode, "Aborted by client", href);
321
321
  const outAbort = options.outAbort;
322
322
  if (outAbort) {
323
323
  outAbort.abort(reason);
@@ -1061,13 +1061,13 @@ class Request extends module_1.default {
1061
1061
  return Promise.reject(err);
1062
1062
  }
1063
1063
  }
1064
- let pathname, headers, binOpts, silent;
1064
+ let pathname, headers, binOpts, signal, silent;
1065
1065
  if (options) {
1066
1066
  if (typeof options === 'string') {
1067
1067
  pathname = options;
1068
1068
  }
1069
1069
  else {
1070
- ({ pathname, headers, binOpts, silent } = options);
1070
+ ({ pathname, headers, binOpts, signal, silent } = options);
1071
1071
  if ((0, types_1.isArray)(binOpts)) {
1072
1072
  let next = false;
1073
1073
  binOpts = binOpts.filter(opt => !((0, types_1.isString)(opt) && /^-[a-z][\S\s]*$/i.test(opt.trim()))).map((opt) => {
@@ -1371,7 +1371,13 @@ class Request extends module_1.default {
1371
1371
  }
1372
1372
  for (const item of ARIA2.PID_QUEUE) {
1373
1373
  try {
1374
- process.kill(item[0], 0);
1374
+ if (pid === item[0] && (signal === null || signal === void 0 ? void 0 : signal.aborted)) {
1375
+ process.kill(item[0]);
1376
+ closeTorrent(item[0]);
1377
+ }
1378
+ else {
1379
+ process.kill(item[0], 0);
1380
+ }
1375
1381
  }
1376
1382
  catch {
1377
1383
  closeTorrent(item[0]);
@@ -1686,6 +1692,9 @@ class Request extends module_1.default {
1686
1692
  const ac = new AbortController();
1687
1693
  this[kDownloading].add(options.outAbort = ac);
1688
1694
  stream.addAbortSignal(ac.signal, request);
1695
+ if (options.signal) {
1696
+ stream.addAbortSignal(options.signal, request);
1697
+ }
1689
1698
  this.signal.addEventListener('abort', () => ac.abort(new Error("Aborted by process")), { once: true });
1690
1699
  }
1691
1700
  if (posting) {
@@ -1898,7 +1907,7 @@ class Request extends module_1.default {
1898
1907
  }
1899
1908
  const client = this.open(href, request);
1900
1909
  const { host, url, encoding, outFormat } = request;
1901
- let buffer, aborted;
1910
+ let buffer, aborted = false;
1902
1911
  ({ httpVersion, outAbort } = request);
1903
1912
  const isAborted = () => client.destroyed || httpVersion === 2 && client.aborted;
1904
1913
  const isRetry = (value) => (0, util_1.isRetryable)(value) && ++retries <= this._config.retryLimit;
@@ -1914,14 +1923,11 @@ class Request extends module_1.default {
1914
1923
  if (timeout) {
1915
1924
  clearTimeout(timeout);
1916
1925
  }
1917
- buffer = null;
1918
- aborted = true;
1919
1926
  if (outAbort) {
1920
- if (!client.aborted) {
1921
- outAbort.abort();
1922
- }
1923
1927
  this[kDownloading].delete(outAbort);
1924
1928
  }
1929
+ buffer = null;
1930
+ aborted = true;
1925
1931
  client.destroy();
1926
1932
  };
1927
1933
  const retryTimeout = () => {
@@ -1946,7 +1952,6 @@ class Request extends module_1.default {
1946
1952
  var _o;
1947
1953
  if (readTimeout > 0) {
1948
1954
  timeout = setTimeout(() => {
1949
- abortResponse();
1950
1955
  throwError((0, types_1.errorValue)("Timeout was exceeded", href.toString()));
1951
1956
  }, readTimeout);
1952
1957
  }
@@ -2070,9 +2075,9 @@ class Request extends module_1.default {
2070
2075
  host.success(httpVersion);
2071
2076
  };
2072
2077
  const redirectResponse = (statusCode, location) => {
2073
- abortResponse();
2074
2078
  if (location) {
2075
2079
  if (++redirects <= this._config.redirectLimit) {
2080
+ abortResponse();
2076
2081
  downloadUri.call(this, Request.fromURL(url, location));
2077
2082
  }
2078
2083
  else {
@@ -2084,11 +2089,11 @@ class Request extends module_1.default {
2084
2089
  }
2085
2090
  };
2086
2091
  const errorResponse = (err) => {
2087
- abortResponse();
2088
2092
  if (wasAborted(err)) {
2089
2093
  throwError(err);
2090
2094
  }
2091
2095
  else if ((0, util_1.checkRetryable)(err) && ++retries <= this._config.retryLimit) {
2096
+ abortResponse();
2092
2097
  if (isConnectionTimeout(err)) {
2093
2098
  retryTimeout();
2094
2099
  }
@@ -2233,7 +2238,6 @@ class Request extends module_1.default {
2233
2238
  retryResponse(statusCode, res.headers['retry-after']);
2234
2239
  }
2235
2240
  else {
2236
- abortResponse();
2237
2241
  throwError(formatStatus(statusCode));
2238
2242
  }
2239
2243
  })
@@ -2251,8 +2255,8 @@ class Request extends module_1.default {
2251
2255
  if (aborted) {
2252
2256
  return;
2253
2257
  }
2254
- abortResponse();
2255
2258
  if (++retries <= this._config.retryLimit) {
2259
+ abortResponse();
2256
2260
  retryTimeout();
2257
2261
  }
2258
2262
  else {
@@ -2294,7 +2298,7 @@ class Request extends module_1.default {
2294
2298
  for (const callback of called) {
2295
2299
  try {
2296
2300
  if (callback(code, headers, url) === true) {
2297
- abortHeaders.call(this, href, request, options);
2301
+ abortHeaders.call(this, href, request, options, code);
2298
2302
  return false;
2299
2303
  }
2300
2304
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e-mc/request",
3
- "version": "0.8.20",
3
+ "version": "0.8.22",
4
4
  "description": "Request constructor for E-mc.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -20,8 +20,8 @@
20
20
  "license": "MIT",
21
21
  "homepage": "https://github.com/anpham6/e-mc#readme",
22
22
  "dependencies": {
23
- "@e-mc/module": "0.8.20",
24
- "@e-mc/types": "0.8.20",
23
+ "@e-mc/module": "0.8.22",
24
+ "@e-mc/types": "0.8.22",
25
25
  "combined-stream": "^1.0.8",
26
26
  "js-yaml": "^4.1.0",
27
27
  "picomatch": "^3.0.1",