@e-mc/request 0.8.27 → 0.8.29
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 +4 -4
- package/http/adapter/index.js +43 -20
- package/http/host/altsvc/index.js +92 -0
- package/index.js +44 -21
- package/package.json +3 -3
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.
|
|
12
|
+
- https://www.unpkg.com/@e-mc/types@0.8.29/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.
|
|
86
|
-
- https://www.unpkg.com/@e-mc/types@0.8.
|
|
87
|
-
- https://www.unpkg.com/@e-mc/types@0.8.
|
|
85
|
+
- https://www.unpkg.com/@e-mc/types@0.8.29/lib/http.d.ts
|
|
86
|
+
- https://www.unpkg.com/@e-mc/types@0.8.29/lib/request.d.ts
|
|
87
|
+
- https://www.unpkg.com/@e-mc/types@0.8.29/lib/settings.d.ts
|
|
88
88
|
|
|
89
89
|
## LICENSE
|
|
90
90
|
|
package/http/adapter/index.js
CHANGED
|
@@ -5,28 +5,28 @@ const yaml = require("js-yaml");
|
|
|
5
5
|
const types_1 = require("@e-mc/types");
|
|
6
6
|
const module_1 = require("@e-mc/module");
|
|
7
7
|
const util_1 = require("@e-mc/request/util");
|
|
8
|
+
const kHttpAdapter = Symbol.for('request:http:adapter:constructor');
|
|
8
9
|
let LOG_TIMEFORMAT = 'readable';
|
|
10
|
+
const isConstructor = (value) => typeof value === 'function' && !!value.prototype?.constructor.name;
|
|
9
11
|
class HttpAdapter {
|
|
10
12
|
instance;
|
|
11
13
|
state;
|
|
12
14
|
uri;
|
|
15
|
+
static [kHttpAdapter] = true;
|
|
16
|
+
static constructorOf(value) {
|
|
17
|
+
return isConstructor(value) && value[kHttpAdapter] === true;
|
|
18
|
+
}
|
|
13
19
|
static isUnsupported(value) {
|
|
14
20
|
return value === 421 || value === 505;
|
|
15
21
|
}
|
|
16
22
|
static isDowngrade(err) {
|
|
17
|
-
return
|
|
23
|
+
return (0, types_1.isErrorCode)(err, 'ERR_HTTP2_ERROR') || err instanceof Error && this.isUnsupported(Math.abs(err.errno));
|
|
18
24
|
}
|
|
19
25
|
static wasAborted(err) {
|
|
20
26
|
return err instanceof Error && err.message.startsWith("Aborted");
|
|
21
27
|
}
|
|
22
28
|
static isConnectionError(err) {
|
|
23
|
-
|
|
24
|
-
case 'ETIMEDOUT':
|
|
25
|
-
case 'ECONNRESET':
|
|
26
|
-
return true;
|
|
27
|
-
default:
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
29
|
+
return (0, types_1.isErrorCode)(err, 'ETIMEDOUT', 'ECONNRESET');
|
|
30
30
|
}
|
|
31
31
|
static defineHostConfig({ settings }) {
|
|
32
32
|
const time_format = settings?.time_format;
|
|
@@ -79,13 +79,21 @@ class HttpAdapter {
|
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
const statusCode = headers[':status'];
|
|
82
|
-
if (statusCode
|
|
83
|
-
this.acceptResponse(headers);
|
|
82
|
+
if (statusCode === 204 || statusCode === 304) {
|
|
83
|
+
this.acceptResponse(headers, true);
|
|
84
|
+
}
|
|
85
|
+
else if (statusCode < 300) {
|
|
86
|
+
this.acceptResponse(headers, false);
|
|
84
87
|
}
|
|
85
|
-
else if (statusCode
|
|
88
|
+
else if (statusCode === 301 ||
|
|
89
|
+
statusCode === 302 ||
|
|
90
|
+
statusCode === 303 ||
|
|
91
|
+
statusCode === 307 ||
|
|
92
|
+
statusCode === 308) {
|
|
86
93
|
this.redirectResponse(statusCode, headers.location);
|
|
87
94
|
}
|
|
88
|
-
else if (statusCode ===
|
|
95
|
+
else if (statusCode === 305 ||
|
|
96
|
+
statusCode === 401 ||
|
|
89
97
|
statusCode === 402 ||
|
|
90
98
|
statusCode === 403 ||
|
|
91
99
|
statusCode === 404 ||
|
|
@@ -151,10 +159,17 @@ class HttpAdapter {
|
|
|
151
159
|
return;
|
|
152
160
|
}
|
|
153
161
|
const statusCode = res.statusCode;
|
|
154
|
-
if (statusCode
|
|
155
|
-
this.acceptResponse(res.headers);
|
|
162
|
+
if (statusCode === 204 || statusCode === 304) {
|
|
163
|
+
this.acceptResponse(res.headers, true);
|
|
156
164
|
}
|
|
157
|
-
else if (statusCode <
|
|
165
|
+
else if (statusCode < 300) {
|
|
166
|
+
this.acceptResponse(res.headers, false);
|
|
167
|
+
}
|
|
168
|
+
else if (statusCode === 301 ||
|
|
169
|
+
statusCode === 302 ||
|
|
170
|
+
statusCode === 303 ||
|
|
171
|
+
statusCode === 307 ||
|
|
172
|
+
statusCode === 308) {
|
|
158
173
|
this.redirectResponse(statusCode, res.headers.location);
|
|
159
174
|
}
|
|
160
175
|
else if (this.isRetry(statusCode)) {
|
|
@@ -226,7 +241,7 @@ class HttpAdapter {
|
|
|
226
241
|
this.opts.httpVersion = 1;
|
|
227
242
|
this.init();
|
|
228
243
|
}
|
|
229
|
-
acceptResponse(headers) {
|
|
244
|
+
acceptResponse(headers, empty = false) {
|
|
230
245
|
const opts = this.opts;
|
|
231
246
|
if ('outHeaders' in opts) {
|
|
232
247
|
opts.outHeaders = headers;
|
|
@@ -238,7 +253,7 @@ class HttpAdapter {
|
|
|
238
253
|
const enabled = opts.connected?.call(this.client, headers) !== false && !pipeline;
|
|
239
254
|
const maxBufferSize = opts.maxBufferSize ? (0, types_1.alignSize)(opts.maxBufferSize) : 0;
|
|
240
255
|
this.contentLength = parseInt(headers['content-length'] || '0');
|
|
241
|
-
const updating = opts.progressId !== undefined && !!this.instance.host && this.contentLength > 0;
|
|
256
|
+
const updating = opts.progressId !== undefined && !!this.instance.host && this.contentLength > 0 && !empty;
|
|
242
257
|
const readTimeout = this.instance.readTimeout;
|
|
243
258
|
let log = this.state.log, buffer = null, dataLength = 0;
|
|
244
259
|
this.client.once('readable', () => {
|
|
@@ -267,7 +282,7 @@ class HttpAdapter {
|
|
|
267
282
|
this.updateProgress(0, 0);
|
|
268
283
|
}
|
|
269
284
|
});
|
|
270
|
-
if (enabled) {
|
|
285
|
+
if (enabled && !empty) {
|
|
271
286
|
const encoding = opts.encoding;
|
|
272
287
|
this.client.on('data', (chunk) => {
|
|
273
288
|
if (buffer) {
|
|
@@ -340,7 +355,12 @@ class HttpAdapter {
|
|
|
340
355
|
result = new (require(packageName = 'fast-xml-parser').XMLParser)(parser).parse(buffer);
|
|
341
356
|
break;
|
|
342
357
|
case 'toml':
|
|
343
|
-
|
|
358
|
+
try {
|
|
359
|
+
result = require('smol-toml').parse(buffer);
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
result = require(packageName = 'toml').parse(buffer);
|
|
363
|
+
}
|
|
344
364
|
break;
|
|
345
365
|
default:
|
|
346
366
|
result = JSON.parse(buffer);
|
|
@@ -366,7 +386,7 @@ class HttpAdapter {
|
|
|
366
386
|
if (updating) {
|
|
367
387
|
this.updateProgress(0, this.contentLength);
|
|
368
388
|
}
|
|
369
|
-
if (enabled && this.instance.readExpect === 'always') {
|
|
389
|
+
if (enabled && this.instance.readExpect === 'always' && !empty) {
|
|
370
390
|
this.terminate("No data received");
|
|
371
391
|
return;
|
|
372
392
|
}
|
|
@@ -402,6 +422,9 @@ class HttpAdapter {
|
|
|
402
422
|
}
|
|
403
423
|
else if (++this.redirects <= this.redirectLimit) {
|
|
404
424
|
this.abortResponse();
|
|
425
|
+
if (this.opts.method?.toUpperCase() === 'PUT' && statusCode !== 307 && statusCode !== 308) {
|
|
426
|
+
this.#options.method = 'GET';
|
|
427
|
+
}
|
|
405
428
|
this.setOpts((0, util_1.fromURL)(this.opts.url, location));
|
|
406
429
|
this.init();
|
|
407
430
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
class HttpHostAltSvc {
|
|
3
|
+
host;
|
|
4
|
+
#location = {};
|
|
5
|
+
#available = [];
|
|
6
|
+
#errors = [];
|
|
7
|
+
#versionData;
|
|
8
|
+
constructor(host, versionData) {
|
|
9
|
+
this.host = host;
|
|
10
|
+
this.#versionData = versionData;
|
|
11
|
+
}
|
|
12
|
+
did(version) {
|
|
13
|
+
return this.#versionData[version].status !== -1;
|
|
14
|
+
}
|
|
15
|
+
next() {
|
|
16
|
+
const queue = this.#available.shift();
|
|
17
|
+
if (queue) {
|
|
18
|
+
const { hostname, port, version, expires } = queue;
|
|
19
|
+
const ms = expires - Date.now();
|
|
20
|
+
if (ms < 0) {
|
|
21
|
+
return this.next();
|
|
22
|
+
}
|
|
23
|
+
let timeout = null;
|
|
24
|
+
if (!isNaN(ms)) {
|
|
25
|
+
timeout = setTimeout(() => {
|
|
26
|
+
if (!this.next()) {
|
|
27
|
+
this.host.version = 1;
|
|
28
|
+
}
|
|
29
|
+
}, ms);
|
|
30
|
+
}
|
|
31
|
+
this.#location = { hostname, port, version, timeout, origin: this.host.protocol + '//' + hostname + ':' + port };
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
close(error) {
|
|
37
|
+
const { hostname, port, version, timeout } = this.#location;
|
|
38
|
+
if (hostname) {
|
|
39
|
+
this.#location = {};
|
|
40
|
+
if (timeout) {
|
|
41
|
+
clearTimeout(timeout);
|
|
42
|
+
}
|
|
43
|
+
if (error) {
|
|
44
|
+
this.#errors.push({ hostname, port, version });
|
|
45
|
+
return this.next();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
clear(version) {
|
|
51
|
+
if (version) {
|
|
52
|
+
if (this.#available.length === 0) {
|
|
53
|
+
this.flag(version, 0);
|
|
54
|
+
}
|
|
55
|
+
else if (!this.close(true)) {
|
|
56
|
+
this.flag(version, -1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.close();
|
|
61
|
+
this.#available = [];
|
|
62
|
+
this.#errors = [];
|
|
63
|
+
for (const item of this.#versionData) {
|
|
64
|
+
if (item.alpn !== 0) {
|
|
65
|
+
item.status = -1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
flag(version, value) {
|
|
71
|
+
this.#versionData[version - 1].status = value;
|
|
72
|
+
}
|
|
73
|
+
valid(hostname, port, version) {
|
|
74
|
+
return !this.errors.find(item => item.hostname === hostname && item.port === port && item.version === version);
|
|
75
|
+
}
|
|
76
|
+
set available(value) {
|
|
77
|
+
this.#available = value;
|
|
78
|
+
}
|
|
79
|
+
get errors() {
|
|
80
|
+
return this.#errors;
|
|
81
|
+
}
|
|
82
|
+
get hostname() {
|
|
83
|
+
return this.#location.hostname;
|
|
84
|
+
}
|
|
85
|
+
get port() {
|
|
86
|
+
return this.#location.port;
|
|
87
|
+
}
|
|
88
|
+
get origin() {
|
|
89
|
+
return this.#location.origin;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
module.exports = HttpHostAltSvc;
|
package/index.js
CHANGED
|
@@ -159,11 +159,17 @@ function getProxySettings(request, agentTimeout) {
|
|
|
159
159
|
return null;
|
|
160
160
|
}
|
|
161
161
|
function closeTorrent(pid) {
|
|
162
|
-
const index = ARIA2.PID_QUEUE.findIndex(value =>
|
|
162
|
+
const index = ARIA2.PID_QUEUE.findIndex(value => value[0] === pid);
|
|
163
163
|
if (index !== -1) {
|
|
164
164
|
ARIA2.PID_QUEUE.splice(index, 1);
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
|
+
function resetAria2() {
|
|
168
|
+
if (ARIA2.PID_TIMER) {
|
|
169
|
+
clearInterval(ARIA2.PID_TIMER);
|
|
170
|
+
ARIA2.PID_TIMER = null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
167
173
|
function clearDnsLookup() {
|
|
168
174
|
DNS.CACHE = Object.create(null);
|
|
169
175
|
DNS.TIMEOUT.forEach(value => clearTimeout(value));
|
|
@@ -181,7 +187,7 @@ function resetHttpHost(version) {
|
|
|
181
187
|
const host = HTTP.HOST[origin];
|
|
182
188
|
if (host.secure && host.version === 1) {
|
|
183
189
|
const failed = host.failed(2, true);
|
|
184
|
-
if (failed === 0 && host.
|
|
190
|
+
if (failed === 0 && host.error(2, true) < 10 || failed < 3 && host.success(2, true) > 0) {
|
|
185
191
|
host.version = version;
|
|
186
192
|
}
|
|
187
193
|
}
|
|
@@ -266,6 +272,8 @@ function checkEncoding(request, response, statusCode, outStream, contentEncoding
|
|
|
266
272
|
case 206:
|
|
267
273
|
request.emit('error', (0, types_1.errorValue)("Aborted", 'Partial content'));
|
|
268
274
|
case 204:
|
|
275
|
+
case 205:
|
|
276
|
+
case 304:
|
|
269
277
|
return;
|
|
270
278
|
default:
|
|
271
279
|
contentEncoding = contentEncoding.trim();
|
|
@@ -666,7 +674,7 @@ class Request extends module_1.default {
|
|
|
666
674
|
break;
|
|
667
675
|
}
|
|
668
676
|
if (expires !== undefined) {
|
|
669
|
-
if (
|
|
677
|
+
if ((0, types_1.isString)(expires)) {
|
|
670
678
|
expires = (0, types_1.parseExpires)(expires);
|
|
671
679
|
}
|
|
672
680
|
if (expires >= 0) {
|
|
@@ -897,8 +905,12 @@ class Request extends module_1.default {
|
|
|
897
905
|
}
|
|
898
906
|
break;
|
|
899
907
|
case 'readExpect':
|
|
900
|
-
|
|
901
|
-
|
|
908
|
+
switch (value) {
|
|
909
|
+
case 'string':
|
|
910
|
+
case 'always':
|
|
911
|
+
case 'none':
|
|
912
|
+
this[name] = value;
|
|
913
|
+
break;
|
|
902
914
|
}
|
|
903
915
|
break;
|
|
904
916
|
}
|
|
@@ -1368,13 +1380,9 @@ class Request extends module_1.default {
|
|
|
1368
1380
|
stderr.setEncoding('utf-8').on('data', (value) => message += value);
|
|
1369
1381
|
if (pid !== undefined && module_1.default.isFile(uri, 'torrent')) {
|
|
1370
1382
|
if (!ARIA2.PID_TIMER) {
|
|
1371
|
-
const clearTimer = () => {
|
|
1372
|
-
clearInterval(ARIA2.PID_TIMER);
|
|
1373
|
-
ARIA2.PID_TIMER = null;
|
|
1374
|
-
};
|
|
1375
1383
|
ARIA2.PID_TIMER = setInterval(() => {
|
|
1376
1384
|
if (ARIA2.PID_QUEUE.length === 0) {
|
|
1377
|
-
|
|
1385
|
+
resetAria2();
|
|
1378
1386
|
return;
|
|
1379
1387
|
}
|
|
1380
1388
|
for (const item of ARIA2.PID_QUEUE) {
|
|
@@ -1409,7 +1417,7 @@ class Request extends module_1.default {
|
|
|
1409
1417
|
ARIA2.PID_QUEUE.push(item);
|
|
1410
1418
|
}
|
|
1411
1419
|
else {
|
|
1412
|
-
|
|
1420
|
+
resetAria2();
|
|
1413
1421
|
}
|
|
1414
1422
|
}
|
|
1415
1423
|
}, (ARIA2.UPDATE_STATUS || 30) * 1000);
|
|
@@ -1942,7 +1950,7 @@ class Request extends module_1.default {
|
|
|
1942
1950
|
formatWarning(`Connection timeout (${retries} / ${this._config.retryLimit})`);
|
|
1943
1951
|
downloadUri.call(this, href);
|
|
1944
1952
|
};
|
|
1945
|
-
const acceptResponse = (headers) => {
|
|
1953
|
+
const acceptResponse = (headers, empty) => {
|
|
1946
1954
|
var _o;
|
|
1947
1955
|
if ('outHeaders' in opts) {
|
|
1948
1956
|
opts.outHeaders = headers;
|
|
@@ -1976,7 +1984,7 @@ class Request extends module_1.default {
|
|
|
1976
1984
|
}
|
|
1977
1985
|
});
|
|
1978
1986
|
}
|
|
1979
|
-
if (enabled) {
|
|
1987
|
+
if (enabled && !empty) {
|
|
1980
1988
|
client.on('data', (chunk) => {
|
|
1981
1989
|
if (buffer) {
|
|
1982
1990
|
if (typeof buffer === 'string') {
|
|
@@ -2067,7 +2075,7 @@ class Request extends module_1.default {
|
|
|
2067
2075
|
result = buffer;
|
|
2068
2076
|
}
|
|
2069
2077
|
}
|
|
2070
|
-
else if (enabled && this.readExpect === 'always') {
|
|
2078
|
+
else if (enabled && !empty && this.readExpect === 'always') {
|
|
2071
2079
|
throwError('No data received');
|
|
2072
2080
|
return;
|
|
2073
2081
|
}
|
|
@@ -2166,13 +2174,21 @@ class Request extends module_1.default {
|
|
|
2166
2174
|
return;
|
|
2167
2175
|
}
|
|
2168
2176
|
const statusCode = headers[':status'];
|
|
2169
|
-
if (statusCode
|
|
2170
|
-
acceptResponse(headers);
|
|
2177
|
+
if (statusCode === 204 || statusCode === 304) {
|
|
2178
|
+
acceptResponse(headers, true);
|
|
2179
|
+
}
|
|
2180
|
+
else if (statusCode < 300) {
|
|
2181
|
+
acceptResponse(headers, false);
|
|
2171
2182
|
}
|
|
2172
|
-
else if (statusCode
|
|
2183
|
+
else if (statusCode === 301 ||
|
|
2184
|
+
statusCode === 302 ||
|
|
2185
|
+
statusCode === 303 ||
|
|
2186
|
+
statusCode === 307 ||
|
|
2187
|
+
statusCode === 308) {
|
|
2173
2188
|
redirectResponse(statusCode, headers.location);
|
|
2174
2189
|
}
|
|
2175
|
-
else if (statusCode ===
|
|
2190
|
+
else if (statusCode === 305 ||
|
|
2191
|
+
statusCode === 401 ||
|
|
2176
2192
|
statusCode === 402 ||
|
|
2177
2193
|
statusCode === 403 ||
|
|
2178
2194
|
statusCode === 404 ||
|
|
@@ -2236,10 +2252,17 @@ class Request extends module_1.default {
|
|
|
2236
2252
|
return;
|
|
2237
2253
|
}
|
|
2238
2254
|
const statusCode = res.statusCode;
|
|
2239
|
-
if (statusCode
|
|
2240
|
-
acceptResponse(res.headers);
|
|
2255
|
+
if (statusCode === 204 || statusCode === 304) {
|
|
2256
|
+
acceptResponse(res.headers, true);
|
|
2257
|
+
}
|
|
2258
|
+
else if (statusCode < 300) {
|
|
2259
|
+
acceptResponse(res.headers, false);
|
|
2241
2260
|
}
|
|
2242
|
-
else if (statusCode
|
|
2261
|
+
else if (statusCode === 301 ||
|
|
2262
|
+
statusCode === 302 ||
|
|
2263
|
+
statusCode === 303 ||
|
|
2264
|
+
statusCode === 307 ||
|
|
2265
|
+
statusCode === 308) {
|
|
2243
2266
|
redirectResponse(statusCode, res.headers.location);
|
|
2244
2267
|
}
|
|
2245
2268
|
else if (isRetry(statusCode)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/request",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.29",
|
|
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.
|
|
24
|
-
"@e-mc/types": "0.8.
|
|
23
|
+
"@e-mc/module": "0.8.29",
|
|
24
|
+
"@e-mc/types": "0.8.29",
|
|
25
25
|
"combined-stream": "^1.0.8",
|
|
26
26
|
"js-yaml": "^4.1.0",
|
|
27
27
|
"picomatch": "^3.0.1",
|