@e-mc/request 0.10.14 → 0.10.16
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/index.js +37 -15
- package/package.json +5 -5
- package/http/adapter/index.js +0 -575
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.10.
|
|
12
|
+
* [View Source](https://www.unpkg.com/@e-mc/types@0.10.16/lib/index.d.ts)
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import type { IModule, ModuleConstructor } from "./index";
|
|
@@ -205,9 +205,9 @@ instance.get("http://hostname/path/config.yml", options).then(data => {
|
|
|
205
205
|
|
|
206
206
|
## References
|
|
207
207
|
|
|
208
|
-
- https://www.unpkg.com/@e-mc/types@0.10.
|
|
209
|
-
- https://www.unpkg.com/@e-mc/types@0.10.
|
|
210
|
-
- https://www.unpkg.com/@e-mc/types@0.10.
|
|
208
|
+
- https://www.unpkg.com/@e-mc/types@0.10.16/lib/http.d.ts
|
|
209
|
+
- https://www.unpkg.com/@e-mc/types@0.10.16/lib/request.d.ts
|
|
210
|
+
- https://www.unpkg.com/@e-mc/types@0.10.16/lib/settings.d.ts
|
|
211
211
|
|
|
212
212
|
* https://www.npmjs.com/package/@types/node
|
|
213
213
|
|
package/index.js
CHANGED
|
@@ -276,6 +276,8 @@ function checkEncoding(request, response, statusCode, outStream, contentEncoding
|
|
|
276
276
|
case 206:
|
|
277
277
|
request.emit('error', (0, types_1.errorValue)("Aborted", 'Partial content'));
|
|
278
278
|
case 204:
|
|
279
|
+
case 205:
|
|
280
|
+
case 304:
|
|
279
281
|
return;
|
|
280
282
|
}
|
|
281
283
|
if (!contentEncoding) {
|
|
@@ -375,6 +377,7 @@ function successDns(instance, value, pending, connected) {
|
|
|
375
377
|
}
|
|
376
378
|
pending.length = 0;
|
|
377
379
|
}
|
|
380
|
+
const hasResponse = (value) => value >= 200 && (value < 300 || value === 304);
|
|
378
381
|
const configureDns = (family, options) => family === 0 ? options : { family, hints: family === 6 ? dns.V4MAPPED : 0 };
|
|
379
382
|
const ignoreOpt = (opts, ...values) => !opts?.some(item => values.includes(item));
|
|
380
383
|
const escapeQuote = (value) => value.replace(/[\\"]/g, capture => '\\' + capture);
|
|
@@ -431,13 +434,21 @@ class Fetch {
|
|
|
431
434
|
return;
|
|
432
435
|
}
|
|
433
436
|
const statusCode = headers[':status'];
|
|
434
|
-
if (statusCode
|
|
435
|
-
this.acceptResponse(headers);
|
|
437
|
+
if (statusCode === 204 || statusCode === 304) {
|
|
438
|
+
this.acceptResponse(headers, true);
|
|
436
439
|
}
|
|
437
|
-
else if (statusCode <
|
|
440
|
+
else if (statusCode < 300) {
|
|
441
|
+
this.acceptResponse(headers, false);
|
|
442
|
+
}
|
|
443
|
+
else if (statusCode === 301 ||
|
|
444
|
+
statusCode === 302 ||
|
|
445
|
+
statusCode === 303 ||
|
|
446
|
+
statusCode === 307 ||
|
|
447
|
+
statusCode === 308) {
|
|
438
448
|
this.redirectResponse(statusCode, headers.location);
|
|
439
449
|
}
|
|
440
|
-
else if (statusCode ===
|
|
450
|
+
else if (statusCode === 305 ||
|
|
451
|
+
statusCode === 401 ||
|
|
441
452
|
statusCode === 402 ||
|
|
442
453
|
statusCode === 403 ||
|
|
443
454
|
statusCode === 404 ||
|
|
@@ -502,10 +513,17 @@ class Fetch {
|
|
|
502
513
|
return;
|
|
503
514
|
}
|
|
504
515
|
const statusCode = res.statusCode;
|
|
505
|
-
if (statusCode
|
|
506
|
-
this.acceptResponse(res.headers);
|
|
516
|
+
if (statusCode === 204 || statusCode === 304) {
|
|
517
|
+
this.acceptResponse(res.headers, true);
|
|
518
|
+
}
|
|
519
|
+
else if (statusCode < 300) {
|
|
520
|
+
this.acceptResponse(res.headers, false);
|
|
507
521
|
}
|
|
508
|
-
else if (statusCode
|
|
522
|
+
else if (statusCode === 301 ||
|
|
523
|
+
statusCode === 302 ||
|
|
524
|
+
statusCode === 303 ||
|
|
525
|
+
statusCode === 307 ||
|
|
526
|
+
statusCode === 308) {
|
|
509
527
|
this.redirectResponse(statusCode, res.headers.location);
|
|
510
528
|
}
|
|
511
529
|
else if (this.isRetry(statusCode)) {
|
|
@@ -586,7 +604,7 @@ class Fetch {
|
|
|
586
604
|
this.opts.httpVersion = 1;
|
|
587
605
|
this.init();
|
|
588
606
|
}
|
|
589
|
-
acceptResponse(headers) {
|
|
607
|
+
acceptResponse(headers, empty = false) {
|
|
590
608
|
const { instance, config, client, opts, pipeTo } = this;
|
|
591
609
|
const parent = this.instance.host;
|
|
592
610
|
const progressId = config.progressId;
|
|
@@ -629,7 +647,7 @@ class Fetch {
|
|
|
629
647
|
}
|
|
630
648
|
});
|
|
631
649
|
}
|
|
632
|
-
if (enabled) {
|
|
650
|
+
if (enabled && !empty) {
|
|
633
651
|
const encoding = opts.encoding;
|
|
634
652
|
client.on('data', (chunk) => {
|
|
635
653
|
if (buffer) {
|
|
@@ -726,7 +744,7 @@ class Fetch {
|
|
|
726
744
|
if (contentLength > 0) {
|
|
727
745
|
parent.updateProgress("request", progressId, 0, contentLength);
|
|
728
746
|
}
|
|
729
|
-
if (enabled && instance.readExpect === 'always') {
|
|
747
|
+
if (enabled && instance.readExpect === 'always' && !empty) {
|
|
730
748
|
this.terminate("No data received");
|
|
731
749
|
return;
|
|
732
750
|
}
|
|
@@ -1237,7 +1255,7 @@ class Request extends module_1 {
|
|
|
1237
1255
|
break;
|
|
1238
1256
|
}
|
|
1239
1257
|
if (expires !== undefined) {
|
|
1240
|
-
if (
|
|
1258
|
+
if ((0, types_1.isString)(expires)) {
|
|
1241
1259
|
expires = (0, types_1.parseExpires)(expires);
|
|
1242
1260
|
}
|
|
1243
1261
|
if (expires >= 0) {
|
|
@@ -1468,8 +1486,12 @@ class Request extends module_1 {
|
|
|
1468
1486
|
}
|
|
1469
1487
|
break;
|
|
1470
1488
|
case 'readExpect':
|
|
1471
|
-
|
|
1472
|
-
|
|
1489
|
+
switch (value) {
|
|
1490
|
+
case 'string':
|
|
1491
|
+
case 'always':
|
|
1492
|
+
case 'none':
|
|
1493
|
+
this[name] = value;
|
|
1494
|
+
break;
|
|
1473
1495
|
}
|
|
1474
1496
|
break;
|
|
1475
1497
|
}
|
|
@@ -2098,7 +2120,7 @@ class Request extends module_1 {
|
|
|
2098
2120
|
request.on('response', response => {
|
|
2099
2121
|
connected = true;
|
|
2100
2122
|
const statusCode = response[':status'];
|
|
2101
|
-
if (this.matchStatus(statusCode, url, response, request, options) && statusCode
|
|
2123
|
+
if (this.matchStatus(statusCode, url, response, request, options) && hasResponse(statusCode)) {
|
|
2102
2124
|
if (emitter = checkEncoding(request, request, statusCode, outStream, response['content-encoding'])) {
|
|
2103
2125
|
for (const event in listenerMap) {
|
|
2104
2126
|
const [name, type] = event.split('-');
|
|
@@ -2220,7 +2242,7 @@ class Request extends module_1 {
|
|
|
2220
2242
|
}, response => {
|
|
2221
2243
|
const statusCode = response.statusCode;
|
|
2222
2244
|
const incoming = response.headers;
|
|
2223
|
-
if (this.matchStatus(statusCode, url, incoming, request, options) && (getting || posting) && statusCode
|
|
2245
|
+
if (this.matchStatus(statusCode, url, incoming, request, options) && (getting || posting) && hasResponse(statusCode)) {
|
|
2224
2246
|
let source = checkEncoding(request, response, statusCode, outStream, incoming['content-encoding']);
|
|
2225
2247
|
if (source) {
|
|
2226
2248
|
source.once('finish', () => request.emit('end'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/request",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.16",
|
|
4
4
|
"description": "Request constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@e-mc/module": "0.10.
|
|
24
|
-
"@e-mc/types": "0.10.
|
|
23
|
+
"@e-mc/module": "0.10.16",
|
|
24
|
+
"@e-mc/types": "0.10.16",
|
|
25
25
|
"combined-stream": "^1.0.8",
|
|
26
|
-
"js-yaml": "^4.1.
|
|
27
|
-
"picomatch": "^4.0.
|
|
26
|
+
"js-yaml": "^4.1.1",
|
|
27
|
+
"picomatch": "^4.0.3",
|
|
28
28
|
"which": "^2.0.2"
|
|
29
29
|
}
|
|
30
30
|
}
|
package/http/adapter/index.js
DELETED
|
@@ -1,575 +0,0 @@
|
|
|
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 kHttpAdapter = Symbol.for('request:http:adapter:constructor');
|
|
9
|
-
let LOG_TIMEFORMAT = 'readable';
|
|
10
|
-
const isConstructor = (value) => typeof value === 'function' && !!value.prototype?.constructor.name;
|
|
11
|
-
class HttpAdapter {
|
|
12
|
-
instance;
|
|
13
|
-
state;
|
|
14
|
-
uri;
|
|
15
|
-
static [kHttpAdapter] = true;
|
|
16
|
-
static constructorOf(value) {
|
|
17
|
-
return isConstructor(value) && value[kHttpAdapter] === true;
|
|
18
|
-
}
|
|
19
|
-
static isUnsupported(value) {
|
|
20
|
-
return value === 421 || value === 505;
|
|
21
|
-
}
|
|
22
|
-
static isDowngrade(err) {
|
|
23
|
-
return (0, types_1.isErrorCode)(err, 'ERR_HTTP2_ERROR') || err instanceof Error && this.isUnsupported(Math.abs(err.errno));
|
|
24
|
-
}
|
|
25
|
-
static wasAborted(err) {
|
|
26
|
-
return err instanceof Error && err.message.startsWith("Aborted");
|
|
27
|
-
}
|
|
28
|
-
static isConnectionError(err) {
|
|
29
|
-
switch (err instanceof Error && err.code) {
|
|
30
|
-
case 'ETIMEDOUT':
|
|
31
|
-
case 'ECONNRESET':
|
|
32
|
-
return true;
|
|
33
|
-
default:
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
static defineHostConfig({ settings }) {
|
|
38
|
-
const time_format = settings?.time_format;
|
|
39
|
-
switch (time_format) {
|
|
40
|
-
case 'readable':
|
|
41
|
-
case 'relative':
|
|
42
|
-
case 'none':
|
|
43
|
-
LOG_TIMEFORMAT = time_format;
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
contentLength = 0;
|
|
48
|
-
retries = 0;
|
|
49
|
-
redirects = 0;
|
|
50
|
-
closed = false;
|
|
51
|
-
aborted = false;
|
|
52
|
-
timeout = null;
|
|
53
|
-
dataTime = null;
|
|
54
|
-
delayTime = undefined;
|
|
55
|
-
opts;
|
|
56
|
-
client;
|
|
57
|
-
resolve;
|
|
58
|
-
reject;
|
|
59
|
-
startTime;
|
|
60
|
-
#outStream = null;
|
|
61
|
-
#options;
|
|
62
|
-
constructor(instance, state, uri, options) {
|
|
63
|
-
this.instance = instance;
|
|
64
|
-
this.state = state;
|
|
65
|
-
this.uri = uri;
|
|
66
|
-
this.#options = options;
|
|
67
|
-
this.startTime = state.log ? process.hrtime.bigint() : BigInt(0);
|
|
68
|
-
this.setOpts();
|
|
69
|
-
}
|
|
70
|
-
async start() {
|
|
71
|
-
return new Promise((resolve, reject) => {
|
|
72
|
-
this.resolve = resolve;
|
|
73
|
-
this.reject = reject;
|
|
74
|
-
this.init();
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
init() {
|
|
78
|
-
this.aborted = false;
|
|
79
|
-
this.setWriteStream();
|
|
80
|
-
this.client = this.instance.open(this.uri, this.opts);
|
|
81
|
-
if (this.opts.httpVersion === 2) {
|
|
82
|
-
this.client
|
|
83
|
-
.on('response', (headers, flags) => {
|
|
84
|
-
if (this.destroyed) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const statusCode = headers[':status'];
|
|
88
|
-
if (statusCode < 300) {
|
|
89
|
-
this.acceptResponse(headers);
|
|
90
|
-
}
|
|
91
|
-
else if (statusCode < 400) {
|
|
92
|
-
this.redirectResponse(statusCode, headers.location);
|
|
93
|
-
}
|
|
94
|
-
else if (statusCode === 401 ||
|
|
95
|
-
statusCode === 402 ||
|
|
96
|
-
statusCode === 403 ||
|
|
97
|
-
statusCode === 404 ||
|
|
98
|
-
statusCode === 407 ||
|
|
99
|
-
statusCode === 410) {
|
|
100
|
-
this.terminate(this.formatStatus(statusCode));
|
|
101
|
-
}
|
|
102
|
-
else if (this.isRetry(statusCode)) {
|
|
103
|
-
this.retryResponse(statusCode, headers['retry-after']);
|
|
104
|
-
}
|
|
105
|
-
else if (HttpAdapter.isUnsupported(statusCode)) {
|
|
106
|
-
this.retryDownload(true, this.#formatNgFlags(http2.constants.NGHTTP2_PROTOCOL_ERROR, statusCode));
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
switch (flags) {
|
|
110
|
-
case http2.constants.NGHTTP2_PROTOCOL_ERROR:
|
|
111
|
-
case http2.constants.NGHTTP2_INADEQUATE_SECURITY:
|
|
112
|
-
case http2.constants.NGHTTP2_HTTP_1_1_REQUIRED:
|
|
113
|
-
this.retryDownload(true, this.#formatNgFlags(flags, statusCode, headers.location));
|
|
114
|
-
break;
|
|
115
|
-
default:
|
|
116
|
-
this.retryDownload(false, this.formatStatus(statusCode));
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
})
|
|
121
|
-
.on('unknownProtocol', () => {
|
|
122
|
-
if (this.aborted) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
this.retryDownload(true, 'Unknown protocol (HTTP/2)');
|
|
126
|
-
})
|
|
127
|
-
.on('aborted', () => {
|
|
128
|
-
this.aborted = true;
|
|
129
|
-
this.terminate((0, types_1.createAbortError)());
|
|
130
|
-
})
|
|
131
|
-
.on('error', async (err) => {
|
|
132
|
-
if (this.aborted) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (HttpAdapter.wasAborted(err)) {
|
|
136
|
-
this.errorResponse(err);
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
switch (!HttpAdapter.isDowngrade(err) && await this.host.hasProtocol(2)) {
|
|
140
|
-
case 1:
|
|
141
|
-
this.errorResponse(err);
|
|
142
|
-
break;
|
|
143
|
-
case 2:
|
|
144
|
-
this.retryDownload(false, err);
|
|
145
|
-
break;
|
|
146
|
-
default:
|
|
147
|
-
this.retryDownload(true, err);
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
this.client
|
|
155
|
-
.on('response', res => {
|
|
156
|
-
if (this.destroyed) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
const statusCode = res.statusCode;
|
|
160
|
-
if (statusCode < 300) {
|
|
161
|
-
this.acceptResponse(res.headers);
|
|
162
|
-
}
|
|
163
|
-
else if (statusCode < 400) {
|
|
164
|
-
this.redirectResponse(statusCode, res.headers.location);
|
|
165
|
-
}
|
|
166
|
-
else if (this.isRetry(statusCode)) {
|
|
167
|
-
this.retryResponse(statusCode, res.headers['retry-after']);
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
this.terminate(this.formatStatus(statusCode));
|
|
171
|
-
}
|
|
172
|
-
})
|
|
173
|
-
.on('abort', () => {
|
|
174
|
-
this.aborted = true;
|
|
175
|
-
this.terminate((0, types_1.createAbortError)());
|
|
176
|
-
})
|
|
177
|
-
.on('error', err => {
|
|
178
|
-
if (this.aborted) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
this.errorResponse(err);
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
this.client.on('timeout', () => {
|
|
185
|
-
if (this.aborted) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
if (++this.retries <= this.retryLimit) {
|
|
189
|
-
this.abortResponse();
|
|
190
|
-
this.retryTimeout();
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
this.terminate(this.formatStatus(408));
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
setOpts(uri) {
|
|
198
|
-
if (uri) {
|
|
199
|
-
this.uri = uri;
|
|
200
|
-
}
|
|
201
|
-
this.opts = this.instance.opts(this.uri, this.#options);
|
|
202
|
-
}
|
|
203
|
-
setWriteStream() {
|
|
204
|
-
const pipeTo = this.pipeTo;
|
|
205
|
-
if (typeof pipeTo === 'string') {
|
|
206
|
-
try {
|
|
207
|
-
this.outStream = fs.createWriteStream(pipeTo, { emitClose: false, highWaterMark: this.host.streamSize });
|
|
208
|
-
}
|
|
209
|
-
catch (err) {
|
|
210
|
-
this.terminate(err);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
else if (pipeTo) {
|
|
214
|
-
this.outStream = pipeTo;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
retryDownload(downgrade, message) {
|
|
218
|
-
if (this.aborted) {
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
this.abortResponse();
|
|
222
|
-
if (downgrade) {
|
|
223
|
-
const host = this.host;
|
|
224
|
-
host.failed(2);
|
|
225
|
-
if (host.version > 1) {
|
|
226
|
-
if (this.state.verbose) {
|
|
227
|
-
this.instance.formatMessage(1024, 'HTTP2', ["Unsupported protocol", host.origin], message, { failed: true });
|
|
228
|
-
}
|
|
229
|
-
host.version = 1;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
this.opts.httpVersion = 1;
|
|
233
|
-
this.init();
|
|
234
|
-
}
|
|
235
|
-
acceptResponse(headers) {
|
|
236
|
-
const opts = this.opts;
|
|
237
|
-
if ('outHeaders' in opts) {
|
|
238
|
-
opts.outHeaders = headers;
|
|
239
|
-
}
|
|
240
|
-
if ('outFilename' in opts) {
|
|
241
|
-
opts.outFilename = (0, util_1.parseHeader)(headers, 'content-disposition');
|
|
242
|
-
}
|
|
243
|
-
const pipeline = this.pipeTo ? !(0, types_1.isString)(this.pipeTo) : false;
|
|
244
|
-
const enabled = opts.connected?.call(this.client, headers) !== false && !pipeline;
|
|
245
|
-
const maxBufferSize = opts.maxBufferSize ? (0, types_1.alignSize)(opts.maxBufferSize) : 0;
|
|
246
|
-
this.contentLength = parseInt(headers['content-length'] || '0');
|
|
247
|
-
const updating = opts.progressId !== undefined && !!this.instance.host && this.contentLength > 0;
|
|
248
|
-
const readTimeout = this.instance.readTimeout;
|
|
249
|
-
let log = this.state.log, buffer = null, dataLength = 0;
|
|
250
|
-
this.client.once('readable', () => {
|
|
251
|
-
if (readTimeout > 0) {
|
|
252
|
-
this.timeout = setTimeout(() => {
|
|
253
|
-
this.terminate((0, types_1.errorValue)("Timeout was exceeded", this.uri.toString()));
|
|
254
|
-
}, readTimeout);
|
|
255
|
-
}
|
|
256
|
-
if (log) {
|
|
257
|
-
switch (this.instance.settings?.time_format || LOG_TIMEFORMAT) {
|
|
258
|
-
case 'readable':
|
|
259
|
-
this.delayTime = process.hrtime.bigint() - this.startTime;
|
|
260
|
-
break;
|
|
261
|
-
case 'relative':
|
|
262
|
-
this.delayTime = Date.now() - this.instance.startTime;
|
|
263
|
-
break;
|
|
264
|
-
case 'none':
|
|
265
|
-
if (!this.silent) {
|
|
266
|
-
log = false;
|
|
267
|
-
}
|
|
268
|
-
break;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
this.dataTime = process.hrtime.bigint();
|
|
272
|
-
if (updating) {
|
|
273
|
-
this.updateProgress(0, 0);
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
if (enabled) {
|
|
277
|
-
const encoding = opts.encoding;
|
|
278
|
-
this.client.on('data', (chunk) => {
|
|
279
|
-
if (buffer) {
|
|
280
|
-
if (typeof buffer === 'string') {
|
|
281
|
-
buffer += typeof chunk === 'string' ? chunk : chunk.toString(encoding);
|
|
282
|
-
}
|
|
283
|
-
else if (Array.isArray(buffer)) {
|
|
284
|
-
buffer.push(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk);
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
buffer = Buffer.concat([buffer, typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk]);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
buffer = typeof chunk === 'string' ? chunk : [chunk];
|
|
292
|
-
}
|
|
293
|
-
if (updating) {
|
|
294
|
-
dataLength += Buffer.byteLength(chunk, encoding);
|
|
295
|
-
this.updateProgress(dataLength, this.contentLength);
|
|
296
|
-
}
|
|
297
|
-
if (maxBufferSize > 0) {
|
|
298
|
-
if (!updating) {
|
|
299
|
-
dataLength += Buffer.byteLength(chunk, encoding);
|
|
300
|
-
}
|
|
301
|
-
if (dataLength > maxBufferSize) {
|
|
302
|
-
this.terminate((0, types_1.errorValue)("Size limit was exceeded", this.uri.toString()));
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
if (opts.trailers) {
|
|
308
|
-
this.client.once('trailers', (trailers) => {
|
|
309
|
-
opts.trailers.call(this.client, trailers);
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
this.client.once('end', () => {
|
|
313
|
-
if (this.closed || this.aborted) {
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
this.close();
|
|
317
|
-
const encoding = opts.encoding;
|
|
318
|
-
let result;
|
|
319
|
-
if (buffer) {
|
|
320
|
-
if (Array.isArray(buffer)) {
|
|
321
|
-
buffer = Buffer.concat(buffer);
|
|
322
|
-
if (encoding) {
|
|
323
|
-
buffer = buffer.toString(encoding);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
dataLength = Buffer.byteLength(buffer, encoding);
|
|
327
|
-
if (updating) {
|
|
328
|
-
this.updateProgress(dataLength, dataLength);
|
|
329
|
-
}
|
|
330
|
-
if (typeof buffer === 'string') {
|
|
331
|
-
if (buffer.startsWith('\uFEFF') && encoding !== 'utf16le' && encoding !== 'utf-16le') {
|
|
332
|
-
buffer = buffer.substring(1);
|
|
333
|
-
}
|
|
334
|
-
if (opts.outFormat) {
|
|
335
|
-
const { out: format, parser } = opts.outFormat;
|
|
336
|
-
let packageName;
|
|
337
|
-
try {
|
|
338
|
-
switch (format) {
|
|
339
|
-
case 'yaml':
|
|
340
|
-
result = yaml.load(buffer, parser);
|
|
341
|
-
break;
|
|
342
|
-
case 'json5':
|
|
343
|
-
result = require(packageName = 'json5').parse(buffer);
|
|
344
|
-
break;
|
|
345
|
-
case 'xml':
|
|
346
|
-
result = new (require(packageName = 'fast-xml-parser').XMLParser)(parser).parse(buffer);
|
|
347
|
-
break;
|
|
348
|
-
case 'toml':
|
|
349
|
-
result = require(packageName = 'toml').parse(buffer);
|
|
350
|
-
break;
|
|
351
|
-
default:
|
|
352
|
-
result = JSON.parse(buffer);
|
|
353
|
-
break;
|
|
354
|
-
}
|
|
355
|
-
if (!(0, types_1.isObject)(result)) {
|
|
356
|
-
result = null;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
catch (err) {
|
|
360
|
-
if (this.state.verbose && !(packageName && this.instance.checkPackage(err, packageName))) {
|
|
361
|
-
this.instance.writeFail(["Unable to parse URI response", format], err, 1024);
|
|
362
|
-
}
|
|
363
|
-
result = null;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
if (result === undefined) {
|
|
368
|
-
result = buffer;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
if (updating) {
|
|
373
|
-
this.updateProgress(0, this.contentLength);
|
|
374
|
-
}
|
|
375
|
-
if (enabled && this.instance.readExpect === 'always') {
|
|
376
|
-
this.terminate("No data received");
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
dataLength = this.contentLength || (typeof this.pipeTo === 'string' ? (0, util_1.getSize)(this.pipeTo) : 0);
|
|
380
|
-
result = encoding && !pipeline ? '' : null;
|
|
381
|
-
}
|
|
382
|
-
this.endResponse(result, dataLength, log);
|
|
383
|
-
});
|
|
384
|
-
this.host.success(this.httpVersion);
|
|
385
|
-
}
|
|
386
|
-
updateProgress(dataLength, contentLength) {
|
|
387
|
-
const { host, moduleName } = this.instance;
|
|
388
|
-
host.updateProgress(moduleName, this.opts.progressId, dataLength, contentLength, this.dataTime);
|
|
389
|
-
}
|
|
390
|
-
endResponse(result, dataLength = 0, logging = this.state.log) {
|
|
391
|
-
if (logging) {
|
|
392
|
-
this.instance.writeTimeProcess('HTTP' + this.httpVersion, this.opts.statusMessage || this.uri.toString(), this.startTime, {
|
|
393
|
-
type: 1024,
|
|
394
|
-
queue: !!this.instance.host,
|
|
395
|
-
titleBgColor: !result ? 'bgBlue' : undefined,
|
|
396
|
-
messageUnit: this.formatMibs(dataLength),
|
|
397
|
-
messageUnitMinWidth: 9,
|
|
398
|
-
delayTime: this.delayTime,
|
|
399
|
-
bypassLog: module_1.hasLogType(32768)
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
this.resolve(result);
|
|
403
|
-
}
|
|
404
|
-
redirectResponse(statusCode, location) {
|
|
405
|
-
if (location) {
|
|
406
|
-
if (this.opts.followRedirect === false) {
|
|
407
|
-
this.terminate(this.formatStatus(statusCode, "Follow redirect was disabled"));
|
|
408
|
-
}
|
|
409
|
-
else if (++this.redirects <= this.redirectLimit) {
|
|
410
|
-
this.abortResponse();
|
|
411
|
-
this.setOpts((0, util_1.fromURL)(this.opts.url, location));
|
|
412
|
-
this.init();
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
this.terminate(this.formatStatus(statusCode, "Exceeded redirect limit"));
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
else {
|
|
419
|
-
this.terminate(this.formatStatus(statusCode, "Missing redirect location"));
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
abortResponse() {
|
|
423
|
-
if (this.closed) {
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
this.aborted = true;
|
|
427
|
-
this.client.destroy();
|
|
428
|
-
this.instance.reset(this);
|
|
429
|
-
this.cleanup();
|
|
430
|
-
}
|
|
431
|
-
errorResponse(err) {
|
|
432
|
-
if (HttpAdapter.wasAborted(err)) {
|
|
433
|
-
this.terminate(err);
|
|
434
|
-
}
|
|
435
|
-
else if ((0, util_1.checkRetryable)(err) && ++this.retries <= this.retryLimit) {
|
|
436
|
-
this.abortResponse();
|
|
437
|
-
if (HttpAdapter.isConnectionError(err)) {
|
|
438
|
-
this.retryTimeout();
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
setTimeout(() => {
|
|
442
|
-
this.init();
|
|
443
|
-
}, this.retryWait);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
else {
|
|
447
|
-
this.host.error(this.httpVersion);
|
|
448
|
-
this.terminate(err);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
retryResponse(statusCode, retryAfter) {
|
|
452
|
-
this.abortResponse();
|
|
453
|
-
if (retryAfter && this.retryAfter > 0) {
|
|
454
|
-
let offset = +retryAfter || new Date(retryAfter);
|
|
455
|
-
if (offset instanceof Date) {
|
|
456
|
-
offset = Math.max(0, offset.getTime() - Date.now());
|
|
457
|
-
}
|
|
458
|
-
else {
|
|
459
|
-
offset *= 1000;
|
|
460
|
-
}
|
|
461
|
-
if (offset > 0) {
|
|
462
|
-
if (offset <= this.retryAfter) {
|
|
463
|
-
this.sendWarning(`Retry After (${retryAfter})`);
|
|
464
|
-
setTimeout(() => {
|
|
465
|
-
this.init();
|
|
466
|
-
}, offset);
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
this.terminate(this.formatStatus(statusCode));
|
|
470
|
-
}
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
this.sendWarning(this.#formatRetry((0, util_1.fromStatusCode)(statusCode)));
|
|
475
|
-
if ((0, util_1.isRetryable)(statusCode, true)) {
|
|
476
|
-
setImmediate(this.init.bind(this));
|
|
477
|
-
}
|
|
478
|
-
else {
|
|
479
|
-
setTimeout(() => {
|
|
480
|
-
this.init();
|
|
481
|
-
}, this.retryWait);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
isRetry(value) {
|
|
485
|
-
return (0, util_1.isRetryable)(value) && ++this.retries <= this.retryLimit;
|
|
486
|
-
}
|
|
487
|
-
retryTimeout() {
|
|
488
|
-
this.sendWarning(this.#formatRetry("HTTP connection timeout"));
|
|
489
|
-
this.init();
|
|
490
|
-
}
|
|
491
|
-
terminate(err) {
|
|
492
|
-
if (this.closed) {
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
this.cleanup();
|
|
496
|
-
this.close();
|
|
497
|
-
this.reject(typeof err === 'string' ? new Error(err) : err);
|
|
498
|
-
}
|
|
499
|
-
sendWarning(message) {
|
|
500
|
-
if (this.state.verbose) {
|
|
501
|
-
const { host, url } = this.opts;
|
|
502
|
-
this.instance.formatMessage(1024, 'HTTP' + this.httpVersion, [message, host.origin], url.toString(), { ...module_1.LOG_STYLE_WARN });
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
formatStatus(value, hint) {
|
|
506
|
-
return value + ': ' + (hint || (0, util_1.fromStatusCode)(value)) + ` (${this.uri.toString()})`;
|
|
507
|
-
}
|
|
508
|
-
formatMibs(dataLength) {
|
|
509
|
-
if (dataLength > 0 && this.dataTime) {
|
|
510
|
-
return (0, util_1.getTransferRate)(dataLength, Math.max(1, (0, types_1.convertTime)(process.hrtime.bigint() - this.dataTime, false) * 1000));
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
close() {
|
|
514
|
-
this.closed = true;
|
|
515
|
-
this.instance.reset(this);
|
|
516
|
-
if (this.aborted && !this.client.aborted) {
|
|
517
|
-
this.abortController?.abort();
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
cleanup() {
|
|
521
|
-
if ((0, types_1.isString)(this.pipeTo) && this.outStream) {
|
|
522
|
-
(0, util_1.cleanupStream)(this.outStream, this.pipeTo);
|
|
523
|
-
this.outStream = null;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
#formatNgFlags(value, statusCode, location) {
|
|
527
|
-
return location ? `Using HTTP 1.1 for URL redirect (${location})` : this.formatStatus(statusCode, value ? 'NGHTTP2 Error ' + value : '');
|
|
528
|
-
}
|
|
529
|
-
#formatRetry(message) {
|
|
530
|
-
return `${message} (${this.retries} / ${this.retryLimit})`;
|
|
531
|
-
}
|
|
532
|
-
set abortController(value) {
|
|
533
|
-
this.opts.outAbort = value;
|
|
534
|
-
}
|
|
535
|
-
get abortController() {
|
|
536
|
-
return this.opts.outAbort || null;
|
|
537
|
-
}
|
|
538
|
-
set outStream(value) {
|
|
539
|
-
this.#outStream = value;
|
|
540
|
-
if (value) {
|
|
541
|
-
this.opts.outStream = value;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
get outStream() {
|
|
545
|
-
return this.#outStream;
|
|
546
|
-
}
|
|
547
|
-
get destroyed() {
|
|
548
|
-
return this.client.destroyed || this.httpVersion === 2 && this.client.aborted;
|
|
549
|
-
}
|
|
550
|
-
get host() {
|
|
551
|
-
return this.opts.host;
|
|
552
|
-
}
|
|
553
|
-
get httpVersion() {
|
|
554
|
-
return this.opts.httpVersion;
|
|
555
|
-
}
|
|
556
|
-
get pipeTo() {
|
|
557
|
-
return this.opts.pipeTo;
|
|
558
|
-
}
|
|
559
|
-
get silent() {
|
|
560
|
-
return this.opts.silent === false;
|
|
561
|
-
}
|
|
562
|
-
get retryLimit() {
|
|
563
|
-
return this.state.config.retryLimit;
|
|
564
|
-
}
|
|
565
|
-
get retryWait() {
|
|
566
|
-
return this.state.config.retryWait;
|
|
567
|
-
}
|
|
568
|
-
get retryAfter() {
|
|
569
|
-
return this.state.config.retryAfter;
|
|
570
|
-
}
|
|
571
|
-
get redirectLimit() {
|
|
572
|
-
return this.state.config.redirectLimit;
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
module.exports = HttpAdapter;
|