@e-mc/request 0.13.5 → 0.13.7
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 +9 -1
- package/http/host/altsvc/index.js +92 -0
- package/http/host/index.js +70 -120
- package/index.js +154 -153
- package/package.json +3 -3
- package/util.d.ts +3 -3
- package/util.js +41 -21
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## Interface
|
|
11
11
|
|
|
12
|
-
* [View Source](https://www.unpkg.com/@e-mc/types@0.13.
|
|
12
|
+
* [View Source](https://www.unpkg.com/@e-mc/types@0.13.7/lib/index.d.ts)
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import type { IModule, ModuleConstructor } from "./index";
|
|
@@ -252,9 +252,9 @@ instance.get("http://hostname/path/config.yml", options).then(data => {
|
|
|
252
252
|
|
|
253
253
|
## References
|
|
254
254
|
|
|
255
|
-
- https://www.unpkg.com/@e-mc/types@0.13.
|
|
256
|
-
- https://www.unpkg.com/@e-mc/types@0.13.
|
|
257
|
-
- https://www.unpkg.com/@e-mc/types@0.13.
|
|
255
|
+
- https://www.unpkg.com/@e-mc/types@0.13.7/lib/http.d.ts
|
|
256
|
+
- https://www.unpkg.com/@e-mc/types@0.13.7/lib/request.d.ts
|
|
257
|
+
- https://www.unpkg.com/@e-mc/types@0.13.7/lib/settings.d.ts
|
|
258
258
|
|
|
259
259
|
* https://www.npmjs.com/package/@types/node
|
|
260
260
|
|
package/http/adapter/index.js
CHANGED
|
@@ -355,7 +355,12 @@ class HttpAdapter {
|
|
|
355
355
|
result = new (require(packageName = 'fast-xml-parser').XMLParser)(parser).parse(buffer);
|
|
356
356
|
break;
|
|
357
357
|
case 'toml':
|
|
358
|
-
|
|
358
|
+
try {
|
|
359
|
+
result = require('smol-toml').parse(buffer);
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
result = require(packageName = 'toml').parse(buffer);
|
|
363
|
+
}
|
|
359
364
|
break;
|
|
360
365
|
default:
|
|
361
366
|
result = JSON.parse(buffer);
|
|
@@ -417,6 +422,9 @@ class HttpAdapter {
|
|
|
417
422
|
}
|
|
418
423
|
else if (++this.redirects <= this.redirectLimit) {
|
|
419
424
|
this.abortResponse();
|
|
425
|
+
if (this.opts.method?.toUpperCase() === 'PUT' && statusCode !== 307 && statusCode !== 308) {
|
|
426
|
+
this.#options.method = 'GET';
|
|
427
|
+
}
|
|
420
428
|
this.setOpts((0, util_1.fromURL)(this.opts.url, location));
|
|
421
429
|
this.init();
|
|
422
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/http/host/index.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const tls = require("node:tls");
|
|
3
3
|
const types_1 = require("@e-mc/types");
|
|
4
|
+
const altsvc_1 = require("@e-mc/request/http/host/altsvc");
|
|
4
5
|
const HOST_LOCAL = new Set(['localhost']);
|
|
5
6
|
const HOST_STREAM = new Map();
|
|
6
7
|
const HOST_HTTP_1_1 = [];
|
|
7
8
|
const HOST_ALPN_H2C = [];
|
|
8
9
|
const HOST_ALPN_H2 = [];
|
|
9
|
-
(
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
for (const { address } of nic[name].filter(item => item.internal)) {
|
|
13
|
-
HOST_LOCAL.add(address);
|
|
14
|
-
}
|
|
10
|
+
for (const network of Object.entries(require('node:os').networkInterfaces())) {
|
|
11
|
+
for (const { address } of network[1].filter(item => item.internal)) {
|
|
12
|
+
HOST_LOCAL.add(address);
|
|
15
13
|
}
|
|
16
|
-
}
|
|
14
|
+
}
|
|
15
|
+
const createData = () => ({ success: 0, failed: 0, errors: 0, alpn: 1, status: -1 });
|
|
17
16
|
class HttpHost {
|
|
18
17
|
static normalizeOrigin(value) {
|
|
19
18
|
return (value = value.trim()).replace(/\/+$/, '') + (!/:\d+$/.test(value) ? ':' + (value.startsWith('https') ? '443' : '80') : '');
|
|
@@ -64,19 +63,14 @@ class HttpHost {
|
|
|
64
63
|
localhost;
|
|
65
64
|
_tlsConnect = null;
|
|
66
65
|
#version;
|
|
67
|
-
#altSvc = [];
|
|
68
|
-
#altSvcQueue = [];
|
|
69
|
-
#altSvcError = [];
|
|
70
66
|
#protocol;
|
|
71
67
|
#secure;
|
|
72
68
|
#hostname;
|
|
73
69
|
#port;
|
|
74
70
|
#origin;
|
|
75
71
|
#streamSize;
|
|
76
|
-
#versionData = [
|
|
77
|
-
|
|
78
|
-
[0, 0, 0, -1, -1]
|
|
79
|
-
];
|
|
72
|
+
#versionData = [createData(), createData()];
|
|
73
|
+
#altSvc;
|
|
80
74
|
constructor(url, httpVersion = 1) {
|
|
81
75
|
const { protocol, hostname } = url;
|
|
82
76
|
const secure = protocol === 'https:';
|
|
@@ -89,6 +83,7 @@ class HttpHost {
|
|
|
89
83
|
this.#origin = url.origin;
|
|
90
84
|
this.localhost = HOST_LOCAL.has(hostname);
|
|
91
85
|
this.#streamSize = HOST_STREAM.get(address) || (this.localhost ? 65536 : 4096);
|
|
86
|
+
this.#altSvc = new altsvc_1(this, this.#versionData);
|
|
92
87
|
if (protocol !== 'file:' && !HOST_HTTP_1_1.includes(address = protocol + '//' + address)) {
|
|
93
88
|
if (secure) {
|
|
94
89
|
this.#version = HOST_ALPN_H2.includes(address) ? 2 : httpVersion;
|
|
@@ -101,7 +96,7 @@ class HttpHost {
|
|
|
101
96
|
}
|
|
102
97
|
this.#version = 1;
|
|
103
98
|
for (const version of this.#versionData) {
|
|
104
|
-
version
|
|
99
|
+
version.status = 0;
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
102
|
async hasProtocol(version) {
|
|
@@ -110,17 +105,17 @@ class HttpHost {
|
|
|
110
105
|
if (!data || !this.secure) {
|
|
111
106
|
return 0;
|
|
112
107
|
}
|
|
113
|
-
|
|
114
|
-
switch (status) {
|
|
108
|
+
switch (data.alpn) {
|
|
115
109
|
case 0:
|
|
116
110
|
case 1:
|
|
117
|
-
return
|
|
111
|
+
return data.alpn;
|
|
118
112
|
default:
|
|
119
113
|
return this._tlsConnect ||= new Promise(resolve => {
|
|
120
114
|
const alpn = 'h' + version;
|
|
121
115
|
const socket = tls.connect(+this.port, this.hostname, { ALPNProtocols: [alpn], requestCert: true, rejectUnauthorized: false }, () => {
|
|
122
116
|
this._tlsConnect = null;
|
|
123
|
-
|
|
117
|
+
data.alpn = alpn === socket.alpnProtocol ? 1 : 0;
|
|
118
|
+
resolve(data.alpn);
|
|
124
119
|
});
|
|
125
120
|
socket
|
|
126
121
|
.setNoDelay(false)
|
|
@@ -130,7 +125,8 @@ class HttpHost {
|
|
|
130
125
|
if (this._tlsConnect) {
|
|
131
126
|
this._tlsConnect = null;
|
|
132
127
|
if (this.error(version) >= 10) {
|
|
133
|
-
|
|
128
|
+
data.alpn = 0;
|
|
129
|
+
resolve(0);
|
|
134
130
|
}
|
|
135
131
|
else {
|
|
136
132
|
resolve(2);
|
|
@@ -140,7 +136,8 @@ class HttpHost {
|
|
|
140
136
|
.on('error', () => {
|
|
141
137
|
this.failed(version);
|
|
142
138
|
this._tlsConnect = null;
|
|
143
|
-
|
|
139
|
+
data.alpn = 0;
|
|
140
|
+
resolve(0);
|
|
144
141
|
})
|
|
145
142
|
.end();
|
|
146
143
|
});
|
|
@@ -150,179 +147,132 @@ class HttpHost {
|
|
|
150
147
|
}
|
|
151
148
|
success(version, status) {
|
|
152
149
|
const data = this.#versionData[version - 1];
|
|
153
|
-
return status ? data
|
|
150
|
+
return status ? data.success : ++data.success;
|
|
154
151
|
}
|
|
155
152
|
failed(version, status) {
|
|
156
153
|
const data = this.#versionData[version - 1];
|
|
157
154
|
if (status) {
|
|
158
|
-
return data
|
|
155
|
+
return data.failed;
|
|
159
156
|
}
|
|
160
|
-
this.
|
|
161
|
-
return ++data
|
|
157
|
+
this.altSvc.clear(version);
|
|
158
|
+
return ++data.failed;
|
|
162
159
|
}
|
|
163
160
|
error(version, status) {
|
|
164
161
|
const data = this.#versionData[version - 1];
|
|
165
162
|
if (status) {
|
|
166
|
-
return data
|
|
163
|
+
return data.errors;
|
|
167
164
|
}
|
|
168
|
-
if (data
|
|
169
|
-
this.
|
|
165
|
+
if (data.status !== 2) {
|
|
166
|
+
this.altSvc.close(true);
|
|
170
167
|
}
|
|
171
|
-
return ++data
|
|
168
|
+
return ++data.errors;
|
|
172
169
|
}
|
|
173
170
|
upgrade(version, altSvc) {
|
|
174
171
|
if (altSvc && this.secure) {
|
|
175
172
|
if (altSvc === 'clear') {
|
|
176
|
-
this.
|
|
173
|
+
this.altSvc.clear();
|
|
177
174
|
return;
|
|
178
175
|
}
|
|
179
176
|
const data = this.#versionData;
|
|
180
177
|
for (let i = data.length - 1; i >= version; --i) {
|
|
181
178
|
const host = data[i];
|
|
182
|
-
if (host
|
|
179
|
+
if (host.status === 0) {
|
|
183
180
|
continue;
|
|
184
181
|
}
|
|
182
|
+
const h = i + 1;
|
|
185
183
|
const increment = (flag) => {
|
|
186
|
-
host
|
|
187
|
-
if (this.#version <
|
|
188
|
-
this.#version =
|
|
184
|
+
host.status = flag;
|
|
185
|
+
if (this.#version < h) {
|
|
186
|
+
this.#version = h;
|
|
189
187
|
return true;
|
|
190
188
|
}
|
|
191
189
|
return false;
|
|
192
190
|
};
|
|
193
|
-
const
|
|
194
|
-
const time = Date.now();
|
|
191
|
+
const available = [];
|
|
195
192
|
const hostname = this.#hostname;
|
|
196
|
-
const
|
|
197
|
-
for (const match of altSvc.matchAll(new RegExp(`h${i + 1}(?:-\\d+)?="([^:]*):(\\d+)"([^,]*)`, 'g'))) {
|
|
193
|
+
for (const match of altSvc.matchAll(new RegExp(`h${h}(?:-\\d+)?="([^:]*):(\\d+)"([^,]*)`, 'g'))) {
|
|
198
194
|
const port = match[2];
|
|
199
195
|
if (!match[1] && port === this.port) {
|
|
200
196
|
increment(2);
|
|
201
|
-
|
|
197
|
+
available.length = 0;
|
|
202
198
|
break;
|
|
203
199
|
}
|
|
204
200
|
const address = match[1] || hostname;
|
|
205
201
|
const ma = +(/ma=(\d+)/.exec(match[3])?.[1] || 86400);
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
address,
|
|
202
|
+
if (this.altSvc.valid(address, port, h)) {
|
|
203
|
+
available.push({
|
|
204
|
+
hostname: address,
|
|
209
205
|
port,
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
match[3].includes('persist=1')
|
|
213
|
-
|
|
206
|
+
version: h,
|
|
207
|
+
expires: ma >= 2592000 ? NaN : Date.now() + Math.min(ma * 1000, 2147483647),
|
|
208
|
+
persist: match[3].includes('persist=1')
|
|
209
|
+
});
|
|
214
210
|
}
|
|
215
211
|
}
|
|
216
|
-
if (
|
|
217
|
-
this.
|
|
218
|
-
this
|
|
219
|
-
if (a
|
|
212
|
+
if (available.length > 0) {
|
|
213
|
+
this.altSvc.close();
|
|
214
|
+
this.altSvc.available = available.sort((a, b) => {
|
|
215
|
+
if (a.hostname === hostname) {
|
|
220
216
|
return -1;
|
|
221
217
|
}
|
|
222
|
-
if (b
|
|
218
|
+
if (b.hostname === hostname) {
|
|
223
219
|
return 1;
|
|
224
220
|
}
|
|
225
|
-
if (isNaN(a
|
|
221
|
+
if (isNaN(a.expires) || a.expires > b.expires) {
|
|
226
222
|
return -1;
|
|
227
223
|
}
|
|
228
|
-
if (isNaN(b
|
|
224
|
+
if (isNaN(b.expires) || a.expires < b.expires) {
|
|
229
225
|
return 1;
|
|
230
226
|
}
|
|
231
|
-
if (a[3] && !b[3]) {
|
|
232
|
-
return -1;
|
|
233
|
-
}
|
|
234
|
-
if (!a[3] && b[3]) {
|
|
235
|
-
return -1;
|
|
236
|
-
}
|
|
237
227
|
return 0;
|
|
238
228
|
});
|
|
239
229
|
if (increment(1)) {
|
|
240
|
-
this.
|
|
230
|
+
this.altSvc.next();
|
|
241
231
|
}
|
|
242
232
|
}
|
|
243
233
|
}
|
|
244
234
|
}
|
|
245
235
|
}
|
|
246
236
|
didAltSvc(version) {
|
|
247
|
-
return this.#versionData[version]
|
|
237
|
+
return this.#versionData[version].status !== -1;
|
|
248
238
|
}
|
|
249
239
|
nextAltSvc() {
|
|
250
|
-
|
|
251
|
-
if (queue) {
|
|
252
|
-
const [hostname, port, expires, version] = queue;
|
|
253
|
-
const timeout = expires - Date.now();
|
|
254
|
-
if (timeout < 0) {
|
|
255
|
-
return this.nextAltSvc();
|
|
256
|
-
}
|
|
257
|
-
let timer = null;
|
|
258
|
-
if (!isNaN(timeout)) {
|
|
259
|
-
timer = setTimeout(() => {
|
|
260
|
-
if (!this.nextAltSvc()) {
|
|
261
|
-
this.version = 1;
|
|
262
|
-
}
|
|
263
|
-
}, timeout);
|
|
264
|
-
}
|
|
265
|
-
this.#altSvc = [hostname, port, timer, version, this.protocol + '//' + hostname + ':' + port];
|
|
266
|
-
return true;
|
|
267
|
-
}
|
|
268
|
-
return false;
|
|
240
|
+
return this.altSvc.next();
|
|
269
241
|
}
|
|
270
242
|
closeAltSvc(error) {
|
|
271
|
-
|
|
272
|
-
if (hostname) {
|
|
273
|
-
this.#altSvc = [];
|
|
274
|
-
if (timeout) {
|
|
275
|
-
clearTimeout(timeout);
|
|
276
|
-
}
|
|
277
|
-
if (error) {
|
|
278
|
-
this.#altSvcError.push(`h${version}:${hostname}:${port}`);
|
|
279
|
-
return this.nextAltSvc();
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return false;
|
|
243
|
+
return this.altSvc.close(error);
|
|
283
244
|
}
|
|
284
245
|
clearAltSvc(version) {
|
|
285
|
-
|
|
286
|
-
if (this.#altSvcQueue.length === 0) {
|
|
287
|
-
this.flagAltSvc(version, 0);
|
|
288
|
-
}
|
|
289
|
-
else if (!this.closeAltSvc(true)) {
|
|
290
|
-
this.flagAltSvc(version, -1);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
this.closeAltSvc();
|
|
295
|
-
this.#altSvcQueue = [];
|
|
296
|
-
this.#altSvcError = [];
|
|
297
|
-
for (const item of this.#versionData) {
|
|
298
|
-
if (item[3]) {
|
|
299
|
-
item[4] = -1;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
246
|
+
this.altSvc.clear(version);
|
|
303
247
|
}
|
|
304
248
|
flagAltSvc(version, value) {
|
|
305
|
-
this
|
|
249
|
+
this.altSvc.flag(version, value);
|
|
306
250
|
}
|
|
307
251
|
reset() {
|
|
308
|
-
this.
|
|
252
|
+
this.altSvc.clear();
|
|
309
253
|
this.#versionData.forEach((item, index) => {
|
|
310
|
-
item
|
|
311
|
-
item
|
|
312
|
-
item
|
|
254
|
+
item.success = 0;
|
|
255
|
+
item.failed = 0;
|
|
256
|
+
item.errors = 0;
|
|
313
257
|
if (index > 0) {
|
|
314
|
-
item
|
|
258
|
+
item.alpn = -1;
|
|
315
259
|
}
|
|
316
260
|
});
|
|
317
261
|
}
|
|
262
|
+
v1() {
|
|
263
|
+
return this.#version === 1;
|
|
264
|
+
}
|
|
318
265
|
v2() {
|
|
319
266
|
return this.#version === 2;
|
|
320
267
|
}
|
|
268
|
+
get altSvc() {
|
|
269
|
+
return this.#altSvc;
|
|
270
|
+
}
|
|
321
271
|
set version(value) {
|
|
322
272
|
switch (value) {
|
|
323
273
|
case 1:
|
|
324
274
|
case 2:
|
|
325
|
-
this.
|
|
275
|
+
this.altSvc.flag(this.#version = value, -1);
|
|
326
276
|
break;
|
|
327
277
|
}
|
|
328
278
|
}
|
|
@@ -336,13 +286,13 @@ class HttpHost {
|
|
|
336
286
|
return this.#secure;
|
|
337
287
|
}
|
|
338
288
|
get hostname() {
|
|
339
|
-
return this
|
|
289
|
+
return this.altSvc.hostname || this.#hostname;
|
|
340
290
|
}
|
|
341
291
|
get port() {
|
|
342
|
-
return this
|
|
292
|
+
return this.altSvc.port || this.#port;
|
|
343
293
|
}
|
|
344
294
|
get origin() {
|
|
345
|
-
return this
|
|
295
|
+
return this.altSvc.origin || this.#origin;
|
|
346
296
|
}
|
|
347
297
|
get streamSize() {
|
|
348
298
|
return this.#streamSize;
|
package/index.js
CHANGED
|
@@ -28,13 +28,14 @@ const REGEXP_GLOBWITHIN = /\\\?|(?:(?<!\\)(?:\*|\[!?[^!\]]+\]|\{(?:[^,]+,)+[^}]+
|
|
|
28
28
|
const REGEXP_RCLONE = /^rclone:\?/i;
|
|
29
29
|
const HTTP = {
|
|
30
30
|
HOST: {},
|
|
31
|
-
HEADERS:
|
|
31
|
+
HEADERS: Object.create(null),
|
|
32
|
+
CACHE: new WeakMap(),
|
|
32
33
|
VERSION: 1,
|
|
33
34
|
PROXY: null
|
|
34
35
|
};
|
|
35
36
|
const TLS = {
|
|
36
|
-
TEXT:
|
|
37
|
-
FILE:
|
|
37
|
+
TEXT: Object.create(null),
|
|
38
|
+
FILE: Object.create(null)
|
|
38
39
|
};
|
|
39
40
|
const DNS = {
|
|
40
41
|
CACHE: Object.create(null),
|
|
@@ -61,7 +62,7 @@ const ARIA2 = {
|
|
|
61
62
|
LOWEST_SPEED_LIMIT: null,
|
|
62
63
|
ALWAYS_RESUME: false,
|
|
63
64
|
FILE_ALLOCATION: 'none',
|
|
64
|
-
PROXY:
|
|
65
|
+
PROXY: Object.create(null),
|
|
65
66
|
NO_PROXY: '',
|
|
66
67
|
CONF_PATH: ''
|
|
67
68
|
};
|
|
@@ -115,21 +116,6 @@ let READ_TIMEOUT = 0;
|
|
|
115
116
|
let AGENT_TIMEOUT = 0;
|
|
116
117
|
let LOG_HTTP = false;
|
|
117
118
|
let LOG_TIMEPROCESS = true;
|
|
118
|
-
function getBaseHeaders(uri, headers) {
|
|
119
|
-
let result;
|
|
120
|
-
uri = (0, util_1.trimPath)(uri);
|
|
121
|
-
for (const pathname in headers) {
|
|
122
|
-
if (pathname === uri || uri.startsWith(pathname + '/')) {
|
|
123
|
-
(result ||= []).push([pathname, headers[pathname]]);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (result) {
|
|
127
|
-
if (result.length > 1) {
|
|
128
|
-
result.sort((a, b) => b[0].length - a[0].length);
|
|
129
|
-
}
|
|
130
|
-
return result[0][1];
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
119
|
function setDnsCache(hostname, value, expires) {
|
|
134
120
|
expires ??= DNS.EXPIRES;
|
|
135
121
|
if (expires > 0 && !DNS.CACHE[hostname]) {
|
|
@@ -146,11 +132,6 @@ function setDnsCache(hostname, value, expires) {
|
|
|
146
132
|
}
|
|
147
133
|
}
|
|
148
134
|
}
|
|
149
|
-
function setOutgoingHeaders(output, headers) {
|
|
150
|
-
for (const href in headers) {
|
|
151
|
-
output[href] = (0, util_1.normalizeHeaders)(headers[href]);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
135
|
function getProxySettings(request, agentTimeout) {
|
|
155
136
|
const proxy = request.proxy;
|
|
156
137
|
if (proxy && (proxy.origin || proxy.address && proxy.port)) {
|
|
@@ -175,11 +156,9 @@ function getProxySettings(request, agentTimeout) {
|
|
|
175
156
|
return null;
|
|
176
157
|
}
|
|
177
158
|
function closeTorrent(pid) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
ARIA2.PID_QUEUE.splice(index, 1);
|
|
182
|
-
}
|
|
159
|
+
const index = ARIA2.PID_QUEUE.findIndex(value => value[0] === pid);
|
|
160
|
+
if (index !== -1) {
|
|
161
|
+
ARIA2.PID_QUEUE.splice(index, 1);
|
|
183
162
|
}
|
|
184
163
|
}
|
|
185
164
|
function clearDnsLookup() {
|
|
@@ -199,9 +178,9 @@ function resetHttpHost(version) {
|
|
|
199
178
|
case 2:
|
|
200
179
|
for (const origin in HTTP.HOST) {
|
|
201
180
|
const host = HTTP.HOST[origin];
|
|
202
|
-
if (host.secure && host.
|
|
181
|
+
if (host.secure && host.v1()) {
|
|
203
182
|
const failed = host.failed(2, true);
|
|
204
|
-
if (failed === 0 && host.
|
|
183
|
+
if (failed === 0 && host.error(2, true) < 10 || failed < 3 && host.success(2, true) > 0) {
|
|
205
184
|
host.version = version;
|
|
206
185
|
}
|
|
207
186
|
}
|
|
@@ -296,50 +275,16 @@ function copySearchParams(url, base) {
|
|
|
296
275
|
}
|
|
297
276
|
});
|
|
298
277
|
}
|
|
299
|
-
function checkEncoding(request,
|
|
278
|
+
function checkEncoding(request, statusCode, contentEncoding) {
|
|
300
279
|
switch (statusCode) {
|
|
301
280
|
case 206:
|
|
302
281
|
request.emit('error', (0, types_1.errorValue)("Aborted", 'Partial content'));
|
|
303
282
|
case 204:
|
|
304
283
|
case 205:
|
|
305
284
|
case 304:
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
if (!contentEncoding) {
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
contentEncoding = contentEncoding.trim().toLowerCase();
|
|
312
|
-
const chunkSize = outStream?.writableHighWaterMark;
|
|
313
|
-
let pipeTo;
|
|
314
|
-
if (!contentEncoding.includes(',')) {
|
|
315
|
-
pipeTo = decompressEncoding(contentEncoding, chunkSize);
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
for (const value of contentEncoding.split(/\s*,\s*/).reverse()) {
|
|
319
|
-
const next = decompressEncoding(value, chunkSize);
|
|
320
|
-
if (!next) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
pipeTo = pipeTo ? pipeTo.pipe(next) : next;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
if (pipeTo) {
|
|
327
|
-
if (outStream) {
|
|
328
|
-
stream.pipeline(response, pipeTo, outStream, err => {
|
|
329
|
-
if (err) {
|
|
330
|
-
response.emit('error', err);
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
stream.pipeline(response, pipeTo, err => {
|
|
336
|
-
if (err) {
|
|
337
|
-
response.emit('error', err);
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
return pipeTo;
|
|
285
|
+
return false;
|
|
342
286
|
}
|
|
287
|
+
return !!contentEncoding;
|
|
343
288
|
}
|
|
344
289
|
function sendBody(request, options) {
|
|
345
290
|
const postData = options.postData;
|
|
@@ -351,26 +296,11 @@ function sendBody(request, options) {
|
|
|
351
296
|
}
|
|
352
297
|
request.end();
|
|
353
298
|
}
|
|
354
|
-
function decompressEncoding(value, chunkSize) {
|
|
355
|
-
switch (value) {
|
|
356
|
-
case 'gzip':
|
|
357
|
-
return zlib.createGunzip({ chunkSize });
|
|
358
|
-
case 'br':
|
|
359
|
-
return zlib.createBrotliDecompress({ chunkSize });
|
|
360
|
-
case 'deflate':
|
|
361
|
-
return zlib.createInflate({ chunkSize });
|
|
362
|
-
case 'deflate-raw':
|
|
363
|
-
return zlib.createInflateRaw({ chunkSize });
|
|
364
|
-
case 'zstd':
|
|
365
|
-
if (SUPPORTED_ZSTD) {
|
|
366
|
-
return zlib.createZstdDecompress({ chunkSize });
|
|
367
|
-
}
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
299
|
function resetAria2() {
|
|
372
|
-
|
|
373
|
-
|
|
300
|
+
if (ARIA2.PID_TIMER) {
|
|
301
|
+
clearInterval(ARIA2.PID_TIMER);
|
|
302
|
+
ARIA2.PID_TIMER = null;
|
|
303
|
+
}
|
|
374
304
|
}
|
|
375
305
|
function escapeShellQuote(value) {
|
|
376
306
|
value = value.replace(/(?<!\\)"/g, '\\"');
|
|
@@ -464,32 +394,7 @@ function setBinHeaders(args, headers) {
|
|
|
464
394
|
args.push(...items.map(value => `--header="${name}: ${escapeShellQuote(value)}"`));
|
|
465
395
|
}
|
|
466
396
|
}
|
|
467
|
-
function
|
|
468
|
-
if (binOpts) {
|
|
469
|
-
for (const leading of binOpts) {
|
|
470
|
-
if (leading.startsWith('-')) {
|
|
471
|
-
const pattern = new RegExp(`^${leading}(?:=|$)`);
|
|
472
|
-
for (let i = 0; i < opts.length; ++i) {
|
|
473
|
-
if (pattern.test(opts[i])) {
|
|
474
|
-
opts.splice(i--, i);
|
|
475
|
-
break;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
args = binOpts.concat(args);
|
|
481
|
-
}
|
|
482
|
-
if (args.length > 0) {
|
|
483
|
-
if (module_1.hasLogType(32768)) {
|
|
484
|
-
instance.formatMessage(32768, name.toUpperCase(), [bin].concat(cmd).join(' '), args.join(' '), { ...module_1.LOG_STYLE_WARN });
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
instance.addLog(4, path.basename(bin) + ' ' + args.join(' '), name);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
return args;
|
|
491
|
-
}
|
|
492
|
-
function addAria2Proxy(args, protocol, host) {
|
|
397
|
+
function appendAria2Proxy(args, protocol, host) {
|
|
493
398
|
const { origin, username, password } = host;
|
|
494
399
|
args.push(`--${protocol}-proxy="${origin}"`);
|
|
495
400
|
if (username) {
|
|
@@ -716,7 +621,9 @@ class Request extends module_1 {
|
|
|
716
621
|
}
|
|
717
622
|
}
|
|
718
623
|
if ((0, types_1.isPlainObject)(headers)) {
|
|
719
|
-
|
|
624
|
+
for (const href in headers) {
|
|
625
|
+
HTTP.HEADERS[href] = (0, util_1.normalizeHeaders)(headers[href]);
|
|
626
|
+
}
|
|
720
627
|
}
|
|
721
628
|
if ((0, types_1.isPlainObject)(certs)) {
|
|
722
629
|
[TLS.TEXT, TLS.FILE] = validateCerts(certs);
|
|
@@ -827,9 +734,9 @@ class Request extends module_1 {
|
|
|
827
734
|
};
|
|
828
735
|
#singleton = false;
|
|
829
736
|
#httpVersion = null;
|
|
737
|
+
#headers = null;
|
|
830
738
|
#ipVersion;
|
|
831
739
|
#agentTimeout;
|
|
832
|
-
#headers = null;
|
|
833
740
|
#baseUrl = null;
|
|
834
741
|
#connectDns = Object.create(null);
|
|
835
742
|
#pendingDns = Object.create(null);
|
|
@@ -839,7 +746,7 @@ class Request extends module_1 {
|
|
|
839
746
|
#adapter = HTTP_ADAPTER;
|
|
840
747
|
#certs = null;
|
|
841
748
|
#downloading = new Set();
|
|
842
|
-
#hostInfo =
|
|
749
|
+
#hostInfo = Object.create(null);
|
|
843
750
|
#session = [Object.create(null)];
|
|
844
751
|
constructor(data) {
|
|
845
752
|
super();
|
|
@@ -850,9 +757,6 @@ class Request extends module_1 {
|
|
|
850
757
|
this.readTimeout = (value = (0, util_1.fromSeconds)(read_timeout)) >= 0 ? value : READ_TIMEOUT;
|
|
851
758
|
this.keepAlive = typeof (value = agent?.keep_alive) === 'boolean' ? value : KEEP_ALIVE;
|
|
852
759
|
this.acceptEncoding = typeof (value = use?.accept_encoding) === 'boolean' ? value : ACCEPT_ENCODING;
|
|
853
|
-
if ((value = (0, util_1.asInt)(use?.http_version)) === 1 || value === 2) {
|
|
854
|
-
this.#httpVersion = value;
|
|
855
|
-
}
|
|
856
760
|
this.#ipVersion = (value = (0, util_1.asInt)(data.dns?.family)) && (value === 4 || value === 6) ? value : 0;
|
|
857
761
|
if ((value = (0, util_1.fromSeconds)(agent?.timeout)) >= 0) {
|
|
858
762
|
this.#agentTimeout = value;
|
|
@@ -861,13 +765,14 @@ class Request extends module_1 {
|
|
|
861
765
|
this.#agentTimeout = AGENT_TIMEOUT;
|
|
862
766
|
value = undefined;
|
|
863
767
|
}
|
|
768
|
+
if ((value = (0, util_1.asInt)(use?.http_version)) === 1 || value === 2) {
|
|
769
|
+
this.#httpVersion = value;
|
|
770
|
+
}
|
|
864
771
|
const proxy = getProxySettings(data, value);
|
|
865
772
|
if (proxy) {
|
|
866
773
|
this.proxy = proxy;
|
|
867
774
|
}
|
|
868
|
-
|
|
869
|
-
setOutgoingHeaders(this.#headers = {}, headers);
|
|
870
|
-
}
|
|
775
|
+
this.parseHeaders(headers);
|
|
871
776
|
if ((0, types_1.isObject)(certs)) {
|
|
872
777
|
this.#certs = validateCerts(certs);
|
|
873
778
|
}
|
|
@@ -890,8 +795,8 @@ class Request extends module_1 {
|
|
|
890
795
|
this.readTimeout = READ_TIMEOUT;
|
|
891
796
|
this.keepAlive = KEEP_ALIVE;
|
|
892
797
|
this.acceptEncoding = ACCEPT_ENCODING;
|
|
893
|
-
this.#agentTimeout = AGENT_TIMEOUT;
|
|
894
798
|
this.#ipVersion = DNS.FAMILY;
|
|
799
|
+
this.#agentTimeout = AGENT_TIMEOUT;
|
|
895
800
|
}
|
|
896
801
|
this.module = data;
|
|
897
802
|
}
|
|
@@ -975,9 +880,7 @@ class Request extends module_1 {
|
|
|
975
880
|
init(config) {
|
|
976
881
|
if (config) {
|
|
977
882
|
const { headers, httpVersion, ipVersion, readTimeout } = config;
|
|
978
|
-
|
|
979
|
-
setOutgoingHeaders(this.#headers ||= {}, headers);
|
|
980
|
-
}
|
|
883
|
+
this.parseHeaders(headers);
|
|
981
884
|
if (httpVersion !== undefined) {
|
|
982
885
|
this.httpVersion = httpVersion;
|
|
983
886
|
}
|
|
@@ -1201,8 +1104,7 @@ class Request extends module_1 {
|
|
|
1201
1104
|
}
|
|
1202
1105
|
}
|
|
1203
1106
|
headersOf(uri) {
|
|
1204
|
-
|
|
1205
|
-
return headers && getBaseHeaders(uri, headers) || (this.host ? getBaseHeaders(uri, HTTP.HEADERS) : undefined);
|
|
1107
|
+
return this.findHeadersByUri(uri) || (this.host ? this.findHeadersByUri(uri, HTTP.HEADERS) : undefined);
|
|
1206
1108
|
}
|
|
1207
1109
|
async aria2c(uri, options = {}) {
|
|
1208
1110
|
if (!ARIA2.BIN) {
|
|
@@ -1220,7 +1122,7 @@ class Request extends module_1 {
|
|
|
1220
1122
|
({ pathname, headers, binOpts } = this.parseBinOpts(options, ['--daemon'], ['--input-file']));
|
|
1221
1123
|
}
|
|
1222
1124
|
try {
|
|
1223
|
-
if (
|
|
1125
|
+
if ((0, types_1.isString)(uri) && module_1.isURL(uri)) {
|
|
1224
1126
|
uri = new URL(uri);
|
|
1225
1127
|
}
|
|
1226
1128
|
pathname = checkBinTarget(this, "aria2", uri, pathname, 'aria2', binOpts);
|
|
@@ -1346,12 +1248,12 @@ class Request extends module_1 {
|
|
|
1346
1248
|
}
|
|
1347
1249
|
}
|
|
1348
1250
|
if (proxy) {
|
|
1349
|
-
|
|
1251
|
+
appendAria2Proxy(args, protocol, proxy.host);
|
|
1350
1252
|
}
|
|
1351
1253
|
else if (ARIA2.PROXY.all) {
|
|
1352
|
-
|
|
1254
|
+
appendAria2Proxy(opts, 'all', ARIA2.PROXY.all.host);
|
|
1353
1255
|
}
|
|
1354
|
-
args =
|
|
1256
|
+
args = this.mergeBinOpts(args, opts, binOpts, { name: "aria2", bin: ARIA2.BIN });
|
|
1355
1257
|
opts.push(`"${escapeShellQuote(uri)}"`);
|
|
1356
1258
|
args = args.concat(init, opts);
|
|
1357
1259
|
const startTime = Date.now();
|
|
@@ -1640,7 +1542,7 @@ class Request extends module_1 {
|
|
|
1640
1542
|
setBinHeaders(args, headers);
|
|
1641
1543
|
const cwd = module_1.isDir(pathname) ? pathname : path.dirname(pathname);
|
|
1642
1544
|
const cmd = [source, pathname];
|
|
1643
|
-
args =
|
|
1545
|
+
args = this.mergeBinOpts(args, opts, binOpts, { name: "rclone", bin: RCLONE.BIN, cmd }).concat(init, opts);
|
|
1644
1546
|
args.push(...cmd.map(value => (0, types_1.sanitizeCmd)(value)));
|
|
1645
1547
|
args.unshift(command);
|
|
1646
1548
|
const startTime = Date.now();
|
|
@@ -1739,7 +1641,7 @@ class Request extends module_1 {
|
|
|
1739
1641
|
return { ...options, host, url };
|
|
1740
1642
|
}
|
|
1741
1643
|
open(uri, options) {
|
|
1742
|
-
let { host, url, httpVersion, method = 'GET', search, encoding, format,
|
|
1644
|
+
let { host, url, httpVersion, method = 'GET', search, encoding, format, socketPath, expectContinue = false, timeout = this._config.connectTimeout, outStream } = options, headers = (0, util_1.parseOutgoingHeaders)(options.headers), getting = false, posting = false;
|
|
1743
1645
|
switch (method = method.toUpperCase()) {
|
|
1744
1646
|
case 'GET':
|
|
1745
1647
|
case 'DELETE':
|
|
@@ -1866,7 +1768,8 @@ class Request extends module_1 {
|
|
|
1866
1768
|
}
|
|
1867
1769
|
connected = true;
|
|
1868
1770
|
if (this.matchStatus(statusCode, url, response, request, options) && hasResponse(statusCode)) {
|
|
1869
|
-
|
|
1771
|
+
const contentEncoding = response['content-encoding'];
|
|
1772
|
+
if (checkEncoding(request, statusCode, contentEncoding) && (emitter = this.pipeline(request, contentEncoding, outStream))) {
|
|
1870
1773
|
for (const event in listenerMap) {
|
|
1871
1774
|
const [name, type] = event.split('-');
|
|
1872
1775
|
for (const listener of listenerMap[event]) {
|
|
@@ -1942,7 +1845,7 @@ class Request extends module_1 {
|
|
|
1942
1845
|
if (proxy) {
|
|
1943
1846
|
keepAlive ??= proxy.keepAlive;
|
|
1944
1847
|
agentTimeout ??= proxy.agentTimeout;
|
|
1945
|
-
const proxyHeaders = this
|
|
1848
|
+
const proxyHeaders = this.findHeadersByUri(proxy.host.href) || this.findHeadersByUri(proxy.host.href, HTTP.HEADERS);
|
|
1946
1849
|
const pkg = secure ? 'https-proxy-agent' : 'http-proxy-agent';
|
|
1947
1850
|
try {
|
|
1948
1851
|
agent = require(pkg)(proxy.host, keepAlive === true || keepAlive === false && agentTimeout !== 0 || agentTimeout > 0 ? { ...agentOptions, keepAlive: keepAlive ?? true, timeout: agentTimeout, headers: proxyHeaders } : { ...agentOptions, headers: proxyHeaders });
|
|
@@ -1993,8 +1896,9 @@ class Request extends module_1 {
|
|
|
1993
1896
|
const statusCode = response.statusCode;
|
|
1994
1897
|
const incoming = response.headers;
|
|
1995
1898
|
if (!expectContinue && this.matchStatus(statusCode, url, incoming, request, options) && (getting || posting) && hasResponse(statusCode)) {
|
|
1996
|
-
|
|
1997
|
-
|
|
1899
|
+
const contentEncoding = incoming['content-encoding'];
|
|
1900
|
+
let source;
|
|
1901
|
+
if (checkEncoding(request, statusCode, contentEncoding) && (source = this.pipeline(response, contentEncoding, outStream))) {
|
|
1998
1902
|
source.once('finish', () => {
|
|
1999
1903
|
request.emit('end');
|
|
2000
1904
|
});
|
|
@@ -2042,7 +1946,7 @@ class Request extends module_1 {
|
|
|
2042
1946
|
if (version === 2 && incoming.upgrade?.includes('h2')) {
|
|
2043
1947
|
host.version = 2;
|
|
2044
1948
|
}
|
|
2045
|
-
else if (!host.
|
|
1949
|
+
else if (!host.altSvc.did(1)) {
|
|
2046
1950
|
host.upgrade(1, incoming['alt-svc']);
|
|
2047
1951
|
}
|
|
2048
1952
|
}
|
|
@@ -2162,13 +2066,7 @@ class Request extends module_1 {
|
|
|
2162
2066
|
else {
|
|
2163
2067
|
options = {};
|
|
2164
2068
|
}
|
|
2165
|
-
const headers = (0, util_1.parseOutgoingHeaders)(options.headers) || {};
|
|
2166
|
-
for (const attr in headers) {
|
|
2167
|
-
const name = attr.toLowerCase();
|
|
2168
|
-
if (name === 'content-type' || name === 'content-length') {
|
|
2169
|
-
delete headers[attr];
|
|
2170
|
-
}
|
|
2171
|
-
}
|
|
2069
|
+
const headers = (0, util_1.parseOutgoingHeaders)(options.headers, 'content-type', 'content-length') || {};
|
|
2172
2070
|
if (!putting && (parts || contentType === "multipart/form-data" || contentType === 'form-data')) {
|
|
2173
2071
|
let valid = false;
|
|
2174
2072
|
if ((0, types_1.isArray)(parts)) {
|
|
@@ -2196,7 +2094,7 @@ class Request extends module_1 {
|
|
|
2196
2094
|
}
|
|
2197
2095
|
}
|
|
2198
2096
|
for (let { name, data: target, value, contentType: type, filename } of parts) {
|
|
2199
|
-
if (!
|
|
2097
|
+
if (!name) {
|
|
2200
2098
|
continue;
|
|
2201
2099
|
}
|
|
2202
2100
|
if (target) {
|
|
@@ -2282,10 +2180,9 @@ class Request extends module_1 {
|
|
|
2282
2180
|
}
|
|
2283
2181
|
const singleton = this.#singleton;
|
|
2284
2182
|
const verbose = !opts.silent && !singleton || opts.silent === false;
|
|
2285
|
-
const log = verbose && LOG_HTTP && LOG_TIMEPROCESS;
|
|
2286
2183
|
const state = Object.freeze({
|
|
2287
2184
|
verbose,
|
|
2288
|
-
log,
|
|
2185
|
+
log: verbose && LOG_HTTP && LOG_TIMEPROCESS,
|
|
2289
2186
|
singleton,
|
|
2290
2187
|
config: this._config
|
|
2291
2188
|
});
|
|
@@ -2302,10 +2199,11 @@ class Request extends module_1 {
|
|
|
2302
2199
|
this.#downloading.delete(ac);
|
|
2303
2200
|
adapter.abortController = null;
|
|
2304
2201
|
}
|
|
2305
|
-
return;
|
|
2306
2202
|
}
|
|
2307
|
-
|
|
2308
|
-
|
|
2203
|
+
else {
|
|
2204
|
+
this.#pendingDns = Object.create(null);
|
|
2205
|
+
this.#downloading.clear();
|
|
2206
|
+
}
|
|
2309
2207
|
}
|
|
2310
2208
|
close() {
|
|
2311
2209
|
const session = this.#session;
|
|
@@ -2317,6 +2215,57 @@ class Request extends module_1 {
|
|
|
2317
2215
|
});
|
|
2318
2216
|
this.#downloading.clear();
|
|
2319
2217
|
}
|
|
2218
|
+
pipeline(response, encoding, outStream) {
|
|
2219
|
+
const chunkSize = outStream?.writableHighWaterMark;
|
|
2220
|
+
let pipeTo;
|
|
2221
|
+
encoding = encoding.trim().toLowerCase();
|
|
2222
|
+
if (!encoding.includes(',')) {
|
|
2223
|
+
pipeTo = this.fromEncoding(encoding, { chunkSize });
|
|
2224
|
+
}
|
|
2225
|
+
else {
|
|
2226
|
+
for (const value of encoding.split(/\s*,\s*/).reverse()) {
|
|
2227
|
+
const next = this.fromEncoding(value, { chunkSize });
|
|
2228
|
+
if (!next) {
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
pipeTo = pipeTo ? pipeTo.pipe(next) : next;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
if (pipeTo) {
|
|
2235
|
+
if (outStream) {
|
|
2236
|
+
stream.pipeline(response, pipeTo, outStream, err => {
|
|
2237
|
+
if (err) {
|
|
2238
|
+
response.emit('error', err);
|
|
2239
|
+
}
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2242
|
+
else {
|
|
2243
|
+
stream.pipeline(response, pipeTo, err => {
|
|
2244
|
+
if (err) {
|
|
2245
|
+
response.emit('error', err);
|
|
2246
|
+
}
|
|
2247
|
+
});
|
|
2248
|
+
}
|
|
2249
|
+
return pipeTo;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
fromEncoding(value, options) {
|
|
2253
|
+
switch (value) {
|
|
2254
|
+
case 'gzip':
|
|
2255
|
+
return zlib.createGunzip(options);
|
|
2256
|
+
case 'br':
|
|
2257
|
+
return zlib.createBrotliDecompress(options);
|
|
2258
|
+
case 'deflate':
|
|
2259
|
+
return zlib.createInflate(options);
|
|
2260
|
+
case 'deflate-raw':
|
|
2261
|
+
return zlib.createInflateRaw(options);
|
|
2262
|
+
case 'zstd':
|
|
2263
|
+
if (SUPPORTED_ZSTD) {
|
|
2264
|
+
return zlib.createZstdDecompress(options);
|
|
2265
|
+
}
|
|
2266
|
+
break;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2320
2269
|
matchStatus(code, url, headers, request, options) {
|
|
2321
2270
|
const status = this.#statusOn?.get(code);
|
|
2322
2271
|
if (status) {
|
|
@@ -2395,7 +2344,7 @@ class Request extends module_1 {
|
|
|
2395
2344
|
}
|
|
2396
2345
|
if ((0, types_1.isArray)(options.binOpts)) {
|
|
2397
2346
|
let next = false;
|
|
2398
|
-
binOpts = options.binOpts.filter((opt) => !((0, types_1.isString)(opt) && /^-[a-z].*$/i.test(opt
|
|
2347
|
+
binOpts = options.binOpts.filter((opt) => !((0, types_1.isString)(opt) && /^-[a-z].*$/i.test(opt))).map((opt) => {
|
|
2399
2348
|
if (next) {
|
|
2400
2349
|
if (!module_1.asString(opt).startsWith('--')) {
|
|
2401
2350
|
return [];
|
|
@@ -2445,6 +2394,58 @@ class Request extends module_1 {
|
|
|
2445
2394
|
}
|
|
2446
2395
|
return { pathname, headers: (0, util_1.parseOutgoingHeaders)(options.headers), binOpts };
|
|
2447
2396
|
}
|
|
2397
|
+
mergeBinOpts(args, opts, binOpts, options) {
|
|
2398
|
+
if (binOpts) {
|
|
2399
|
+
for (const leading of binOpts) {
|
|
2400
|
+
if (leading.charAt(0) === '-') {
|
|
2401
|
+
const pattern = new RegExp(`^${leading}(?:=|$)`);
|
|
2402
|
+
for (let i = 0; i < opts.length; ++i) {
|
|
2403
|
+
if (pattern.test(opts[i])) {
|
|
2404
|
+
opts.splice(i--, i);
|
|
2405
|
+
break;
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
args = binOpts.concat(args);
|
|
2411
|
+
}
|
|
2412
|
+
if (options && args.length > 0) {
|
|
2413
|
+
const { name, bin, cmd = [] } = options;
|
|
2414
|
+
if (module_1.hasLogType(32768)) {
|
|
2415
|
+
this.formatMessage(32768, name.toUpperCase(), [bin].concat(cmd).join(' '), args.join(' '), { ...module_1.LOG_STYLE_WARN });
|
|
2416
|
+
}
|
|
2417
|
+
else {
|
|
2418
|
+
this.addLog(4, path.basename(bin) + ' ' + args.join(' '), name);
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
return args;
|
|
2422
|
+
}
|
|
2423
|
+
parseHeaders(outgoing) {
|
|
2424
|
+
if ((0, types_1.isPlainObject)(outgoing)) {
|
|
2425
|
+
Object.assign(this.#headers ||= {}, outgoing);
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
findHeadersByUri(uri, outgoing = this.#headers) {
|
|
2429
|
+
if (outgoing) {
|
|
2430
|
+
const data = [];
|
|
2431
|
+
uri = (0, util_1.trimPath)(uri);
|
|
2432
|
+
for (const pathname in outgoing) {
|
|
2433
|
+
if (pathname === uri || uri.startsWith(pathname + '/')) {
|
|
2434
|
+
data.push([pathname, outgoing[pathname]]);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
if (data.length > 0) {
|
|
2438
|
+
data.sort((a, b) => b[0].length - a[0].length);
|
|
2439
|
+
const headers = data[0][1];
|
|
2440
|
+
let result = HTTP.CACHE.get(headers);
|
|
2441
|
+
if (!result) {
|
|
2442
|
+
result = (0, util_1.normalizeHeaders)(headers);
|
|
2443
|
+
HTTP.CACHE.set(headers, result);
|
|
2444
|
+
}
|
|
2445
|
+
return result;
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2448
2449
|
set adapter(value) {
|
|
2449
2450
|
if (adapter_1.constructorOf(value)) {
|
|
2450
2451
|
this.#adapter = value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/request",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.7",
|
|
4
4
|
"description": "Request constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"license": "BSD-3-Clause",
|
|
20
20
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@e-mc/module": "0.13.
|
|
23
|
-
"@e-mc/types": "0.13.
|
|
22
|
+
"@e-mc/module": "0.13.7",
|
|
23
|
+
"@e-mc/types": "0.13.7",
|
|
24
24
|
"combined-stream": "^1.0.8",
|
|
25
25
|
"js-yaml": "^4.1.1",
|
|
26
26
|
"picomatch": "^4.0.3",
|
package/util.d.ts
CHANGED
|
@@ -6,15 +6,15 @@ import type { Readable, Writable } from 'node:stream';
|
|
|
6
6
|
|
|
7
7
|
declare namespace util {
|
|
8
8
|
function parseHeader<T = unknown>(headers: IncomingHttpHeaders, name: string): T | undefined;
|
|
9
|
-
function parseOutgoingHeaders(headers: OutgoingHttpHeaders | Headers | undefined): OutgoingHttpHeaders | undefined;
|
|
10
|
-
function normalizeHeaders(headers: OutgoingHttpHeaders): OutgoingHttpHeaders;
|
|
9
|
+
function parseOutgoingHeaders(headers: OutgoingHttpHeaders | Headers | undefined, ...ignore: string[]): OutgoingHttpHeaders | undefined;
|
|
10
|
+
function normalizeHeaders(headers: OutgoingHttpHeaders | Headers): OutgoingHttpHeaders;
|
|
11
11
|
function getBasicAuth(auth: AuthValue): string;
|
|
12
12
|
function getBasicAuth(username: unknown, password?: unknown): string;
|
|
13
13
|
function hasBasicAuth(value: string): boolean;
|
|
14
14
|
function checkRetryable(err: unknown): boolean;
|
|
15
15
|
function isRetryable(value: number, timeout?: boolean): boolean;
|
|
16
16
|
function parseHttpProxy(value?: string): HttpProxySettings | undefined;
|
|
17
|
-
function trimPath(value: string): string;
|
|
17
|
+
function trimPath(value: string, char?: string): string;
|
|
18
18
|
function asInt(value: unknown): number;
|
|
19
19
|
function asFloat(value: unknown): number;
|
|
20
20
|
function fromSeconds(value: unknown): number;
|
package/util.js
CHANGED
|
@@ -25,45 +25,63 @@ const node_util_1 = require("node:util");
|
|
|
25
25
|
const types_1 = require("@e-mc/types");
|
|
26
26
|
const module_1 = require("@e-mc/module");
|
|
27
27
|
const host_1 = require("@e-mc/request/http/host");
|
|
28
|
+
function setHeader(result, key, value) {
|
|
29
|
+
if (key === 'set-cookie') {
|
|
30
|
+
(result[key] ||= []).push(value);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
result[key] = value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
28
36
|
const safeInt = (value) => value >= 0 ? Math.min(value, Number.MAX_SAFE_INTEGER) : NaN;
|
|
29
37
|
function parseHeader(headers, name) {
|
|
30
38
|
const value = headers[name];
|
|
31
|
-
if (!value) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
39
|
switch (name.toLowerCase()) {
|
|
35
|
-
case 'content-disposition':
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
case 'content-disposition':
|
|
41
|
+
if ((0, types_1.isString)(value)) {
|
|
42
|
+
let result;
|
|
43
|
+
for (const match of value.matchAll(/\bfilename(?:\*\s*=\s*UTF-8''([^\s;]+)|\s*=\s*(?:"([^"]+)"|([^\s;]+)))/gi)) {
|
|
44
|
+
if (match[1]) {
|
|
45
|
+
return decodeURIComponent(match[1]).trim();
|
|
46
|
+
}
|
|
47
|
+
result = (match[2] || match[3]).trim();
|
|
40
48
|
}
|
|
41
|
-
result
|
|
49
|
+
return result;
|
|
42
50
|
}
|
|
43
|
-
|
|
44
|
-
}
|
|
51
|
+
break;
|
|
45
52
|
}
|
|
46
53
|
}
|
|
47
|
-
function parseOutgoingHeaders(headers) {
|
|
54
|
+
function parseOutgoingHeaders(headers, ...ignore) {
|
|
48
55
|
if (!headers) {
|
|
49
56
|
return;
|
|
50
57
|
}
|
|
51
58
|
if (headers instanceof Headers) {
|
|
52
|
-
const result =
|
|
59
|
+
const result = Object.create(null);
|
|
53
60
|
headers.forEach((value, key) => {
|
|
54
|
-
if (key
|
|
55
|
-
(result
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
result[key] = value;
|
|
61
|
+
if (!ignore.includes(key)) {
|
|
62
|
+
setHeader(result, key, value);
|
|
59
63
|
}
|
|
60
64
|
});
|
|
61
65
|
return result;
|
|
62
66
|
}
|
|
67
|
+
if (ignore.length > 0) {
|
|
68
|
+
const result = {};
|
|
69
|
+
for (const attr in headers) {
|
|
70
|
+
const name = attr.toLowerCase();
|
|
71
|
+
if (!ignore.includes(name)) {
|
|
72
|
+
result[name] = headers[attr];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
63
77
|
return { ...headers };
|
|
64
78
|
}
|
|
65
79
|
function normalizeHeaders(headers) {
|
|
66
80
|
const result = Object.create(null);
|
|
81
|
+
if (headers instanceof Headers) {
|
|
82
|
+
headers.forEach((value, key) => setHeader(result, key, value));
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
67
85
|
for (const name in headers) {
|
|
68
86
|
let value = headers[name];
|
|
69
87
|
switch (typeof value) {
|
|
@@ -182,9 +200,11 @@ function parseHttpProxy(value, ignoreEnv) {
|
|
|
182
200
|
}
|
|
183
201
|
}
|
|
184
202
|
}
|
|
185
|
-
function trimPath(value) {
|
|
186
|
-
|
|
187
|
-
|
|
203
|
+
function trimPath(value, char = '/') {
|
|
204
|
+
while (value.at(-1) === char) {
|
|
205
|
+
value = value.slice(0, -1);
|
|
206
|
+
}
|
|
207
|
+
return value;
|
|
188
208
|
}
|
|
189
209
|
function asInt(value) {
|
|
190
210
|
switch (typeof value) {
|