rekwest 3.3.4 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -186
- package/dist/ackn.js +4 -7
- package/dist/constants.js +21 -0
- package/dist/cookies.js +3 -11
- package/dist/errors.js +0 -7
- package/dist/file.js +9 -14
- package/dist/formdata.js +18 -65
- package/dist/index.js +54 -114
- package/dist/utils.js +117 -177
- package/package.json +13 -12
- package/src/constants.mjs +23 -0
- package/src/cookies.mjs +28 -28
- package/src/file.mjs +49 -40
- package/src/formdata.mjs +243 -239
- package/src/index.mjs +55 -27
- package/src/utils.mjs +104 -96
package/src/index.mjs
CHANGED
|
@@ -3,6 +3,10 @@ import http2 from 'node:http2';
|
|
|
3
3
|
import https from 'node:https';
|
|
4
4
|
import { setTimeout as setTimeoutPromise } from 'node:timers/promises';
|
|
5
5
|
import { ackn } from './ackn.mjs';
|
|
6
|
+
import {
|
|
7
|
+
redirectModes,
|
|
8
|
+
redirectStatusCodes,
|
|
9
|
+
} from './constants.mjs';
|
|
6
10
|
import { Cookies } from './cookies.mjs';
|
|
7
11
|
import { RequestError } from './errors.mjs';
|
|
8
12
|
import { APPLICATION_OCTET_STREAM } from './mediatypes.mjs';
|
|
@@ -13,14 +17,15 @@ import {
|
|
|
13
17
|
merge,
|
|
14
18
|
mixin,
|
|
15
19
|
preflight,
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
sameOrigin,
|
|
21
|
+
sanitize,
|
|
18
22
|
transform,
|
|
19
23
|
} from './utils.mjs';
|
|
20
24
|
|
|
21
25
|
export { constants } from 'node:http2';
|
|
22
26
|
|
|
23
27
|
export * from './ackn.mjs';
|
|
28
|
+
export * from './constants.mjs';
|
|
24
29
|
export * from './cookies.mjs';
|
|
25
30
|
export * from './errors.mjs';
|
|
26
31
|
export * from './file.mjs';
|
|
@@ -29,14 +34,16 @@ export * as mediatypes from './mediatypes.mjs';
|
|
|
29
34
|
export * from './utils.mjs';
|
|
30
35
|
|
|
31
36
|
const {
|
|
32
|
-
|
|
37
|
+
HTTP2_HEADER_AUTHORIZATION,
|
|
33
38
|
HTTP2_HEADER_CONTENT_TYPE,
|
|
34
39
|
HTTP2_HEADER_LOCATION,
|
|
35
40
|
HTTP2_HEADER_RETRY_AFTER,
|
|
36
41
|
HTTP2_HEADER_SET_COOKIE,
|
|
37
42
|
HTTP2_METHOD_GET,
|
|
38
43
|
HTTP2_METHOD_HEAD,
|
|
44
|
+
HTTP2_METHOD_POST,
|
|
39
45
|
HTTP_STATUS_BAD_REQUEST,
|
|
46
|
+
HTTP_STATUS_FOUND,
|
|
40
47
|
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
41
48
|
HTTP_STATUS_SEE_OTHER,
|
|
42
49
|
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
|
@@ -70,8 +77,10 @@ let defaults = {
|
|
|
70
77
|
timeout: 3e5,
|
|
71
78
|
};
|
|
72
79
|
|
|
73
|
-
export default async function rekwest(
|
|
74
|
-
|
|
80
|
+
export default async function rekwest(...args) {
|
|
81
|
+
let options = sanitize(...args);
|
|
82
|
+
const { url } = options;
|
|
83
|
+
|
|
75
84
|
if (!options.redirected) {
|
|
76
85
|
options = merge(rekwest.defaults, options);
|
|
77
86
|
}
|
|
@@ -98,17 +107,14 @@ export default async function rekwest(url, options = {}) {
|
|
|
98
107
|
].forEach((it) => Reflect.deleteProperty(options, it));
|
|
99
108
|
}
|
|
100
109
|
|
|
101
|
-
options = preflight(options);
|
|
110
|
+
options = await transform(preflight(options));
|
|
102
111
|
|
|
103
112
|
const { cookies, digest, follow, h2, redirect, redirected, thenable } = options;
|
|
104
113
|
const { request } = (url.protocol === 'http:' ? http : https);
|
|
105
|
-
let { body } = options;
|
|
106
114
|
|
|
107
115
|
const promise = new Promise((resolve, reject) => {
|
|
108
116
|
let client, req;
|
|
109
117
|
|
|
110
|
-
body &&= transform(body, options);
|
|
111
|
-
|
|
112
118
|
if (h2) {
|
|
113
119
|
client = http2.connect(url.origin, options);
|
|
114
120
|
req = client.request(options.headers, options);
|
|
@@ -149,30 +155,53 @@ export default async function rekwest(url, options = {}) {
|
|
|
149
155
|
: void 0,
|
|
150
156
|
});
|
|
151
157
|
|
|
152
|
-
|
|
153
|
-
|
|
158
|
+
const { statusCode } = res;
|
|
159
|
+
|
|
160
|
+
if (follow && /3\d{2}/.test(statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
|
|
161
|
+
if (!redirectStatusCodes.includes(statusCode)) {
|
|
162
|
+
return res.emit('error', new RangeError(`Invalid status code: ${ statusCode }`));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (redirect === redirectModes.error) {
|
|
154
166
|
return res.emit('error', new RequestError(`Unexpected redirect, redirect mode is set to '${ redirect }'.`));
|
|
155
167
|
}
|
|
156
168
|
|
|
157
|
-
if (redirect ===
|
|
158
|
-
|
|
169
|
+
if (redirect === redirectModes.follow) {
|
|
170
|
+
const location = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
|
|
159
171
|
|
|
160
|
-
if (
|
|
161
|
-
|
|
172
|
+
if (!/^https?:/.test(location.protocol)) {
|
|
173
|
+
return res.emit('error', new RequestError('URL scheme must be "http" or "https".'));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!sameOrigin(location, url)) {
|
|
177
|
+
Reflect.deleteProperty(options.headers, HTTP2_HEADER_AUTHORIZATION);
|
|
178
|
+
location.password = location.username = '';
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
options.url = location;
|
|
182
|
+
|
|
183
|
+
if (statusCode !== HTTP_STATUS_SEE_OTHER && options?.body?.pipe?.constructor === Function) {
|
|
162
184
|
return res.emit('error', new RequestError(`Unable to ${ redirect } redirect with streamable body.`));
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
options.follow--;
|
|
166
188
|
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
189
|
+
if (([
|
|
190
|
+
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
191
|
+
HTTP_STATUS_FOUND,
|
|
192
|
+
].includes(statusCode) && request.method === HTTP2_METHOD_POST) || (statusCode === HTTP_STATUS_SEE_OTHER && ![
|
|
193
|
+
HTTP2_METHOD_GET,
|
|
194
|
+
HTTP2_METHOD_HEAD,
|
|
195
|
+
].includes(options.method))) {
|
|
196
|
+
Object.keys(options.headers).filter((it) => /^content-/i.test(it))
|
|
197
|
+
.forEach((it) => Reflect.deleteProperty(options.headers, it));
|
|
170
198
|
options.body = null;
|
|
199
|
+
options.method = HTTP2_METHOD_GET;
|
|
171
200
|
}
|
|
172
201
|
|
|
173
202
|
Reflect.set(options, 'redirected', true);
|
|
174
203
|
|
|
175
|
-
if (
|
|
204
|
+
if (statusCode === HTTP_STATUS_MOVED_PERMANENTLY && res.headers[HTTP2_HEADER_RETRY_AFTER]) {
|
|
176
205
|
let interval = res.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
177
206
|
|
|
178
207
|
interval = Number(interval) * 1000 || new Date(interval) - Date.now();
|
|
@@ -188,14 +217,14 @@ export default async function rekwest(url, options = {}) {
|
|
|
188
217
|
}
|
|
189
218
|
}
|
|
190
219
|
|
|
191
|
-
if (
|
|
220
|
+
if (statusCode >= HTTP_STATUS_BAD_REQUEST) {
|
|
192
221
|
return reject(mixin(res, options));
|
|
193
222
|
}
|
|
194
223
|
|
|
195
224
|
resolve(mixin(res, options));
|
|
196
225
|
});
|
|
197
226
|
|
|
198
|
-
dispatch(
|
|
227
|
+
dispatch(options, req);
|
|
199
228
|
});
|
|
200
229
|
|
|
201
230
|
try {
|
|
@@ -242,16 +271,15 @@ export default async function rekwest(url, options = {}) {
|
|
|
242
271
|
|
|
243
272
|
Reflect.defineProperty(rekwest, 'stream', {
|
|
244
273
|
enumerable: true,
|
|
245
|
-
value(
|
|
246
|
-
|
|
247
|
-
options = preflight({
|
|
274
|
+
value(...args) {
|
|
275
|
+
const options = preflight({
|
|
248
276
|
...merge(rekwest.defaults, {
|
|
249
277
|
headers: { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_OCTET_STREAM },
|
|
250
|
-
},
|
|
251
|
-
redirect:
|
|
278
|
+
}, sanitize(...args)),
|
|
279
|
+
redirect: redirectModes.manual,
|
|
252
280
|
});
|
|
253
281
|
|
|
254
|
-
const { h2 } = options;
|
|
282
|
+
const { h2, url } = options;
|
|
255
283
|
const { request } = (url.protocol === 'http:' ? http : https);
|
|
256
284
|
let client, req;
|
|
257
285
|
|
package/src/utils.mjs
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Blob } from 'node:buffer';
|
|
2
2
|
import http2 from 'node:http2';
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
pipeline,
|
|
5
5
|
Readable,
|
|
6
6
|
} from 'node:stream';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
types,
|
|
10
|
-
} from 'node:util';
|
|
7
|
+
import { buffer } from 'node:stream/consumers';
|
|
8
|
+
import { types } from 'node:util';
|
|
11
9
|
import zlib from 'node:zlib';
|
|
10
|
+
import { redirectModes } from './constants.mjs';
|
|
12
11
|
import { Cookies } from './cookies.mjs';
|
|
13
12
|
import { TimeoutError } from './errors.mjs';
|
|
14
13
|
import { File } from './file.mjs';
|
|
@@ -37,12 +36,7 @@ const {
|
|
|
37
36
|
HTTP2_METHOD_HEAD,
|
|
38
37
|
} = http2.constants;
|
|
39
38
|
|
|
40
|
-
const
|
|
41
|
-
const brotliDecompress = promisify(zlib.brotliDecompress);
|
|
42
|
-
const gzip = promisify(zlib.gzip);
|
|
43
|
-
const gunzip = promisify(zlib.gunzip);
|
|
44
|
-
const deflate = promisify(zlib.deflate);
|
|
45
|
-
const inflate = promisify(zlib.inflate);
|
|
39
|
+
const unwind = (encodings) => encodings.split(',').map((it) => it.trim());
|
|
46
40
|
|
|
47
41
|
export const admix = (res, headers, options) => {
|
|
48
42
|
const { h2 } = options;
|
|
@@ -86,48 +80,59 @@ export const affix = (client, req, options) => {
|
|
|
86
80
|
});
|
|
87
81
|
};
|
|
88
82
|
|
|
89
|
-
export const
|
|
90
|
-
if (
|
|
83
|
+
export const brandCheck = (value, ctor) => {
|
|
84
|
+
if (!(value instanceof ctor)) {
|
|
91
85
|
throw new TypeError('Illegal invocation');
|
|
92
86
|
}
|
|
93
87
|
};
|
|
94
88
|
|
|
95
|
-
export const compress = (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
89
|
+
export const compress = (readable, encodings = '') => {
|
|
90
|
+
const encoders = [];
|
|
91
|
+
|
|
92
|
+
encodings = unwind(encodings);
|
|
93
|
+
|
|
94
|
+
for (const encoding of encodings) {
|
|
95
|
+
if (/\bbr\b/i.test(encoding)) {
|
|
96
|
+
encoders.push(zlib.createBrotliCompress());
|
|
97
|
+
} else if (/\bdeflate(?!-(?:\w+)?)\b/i.test(encoding)) {
|
|
98
|
+
encoders.push(zlib.createDeflate());
|
|
99
|
+
} else if (/\bdeflate-raw\b/i.test(encoding)) {
|
|
100
|
+
encoders.push(zlib.createDeflateRaw());
|
|
101
|
+
} else if (/\bgzip\b/i.test(encoding)) {
|
|
102
|
+
encoders.push(zlib.createGzip());
|
|
103
|
+
} else {
|
|
104
|
+
return readable;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
113
107
|
|
|
114
|
-
return
|
|
108
|
+
return pipeline(readable, ...encoders, () => void 0);
|
|
115
109
|
};
|
|
116
110
|
|
|
117
|
-
export const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
111
|
+
export const decompress = (readable, encodings = '') => {
|
|
112
|
+
const decoders = [];
|
|
113
|
+
|
|
114
|
+
encodings = unwind(encodings);
|
|
115
|
+
|
|
116
|
+
for (const encoding of encodings) {
|
|
117
|
+
if (/\bbr\b/i.test(encoding)) {
|
|
118
|
+
decoders.push(zlib.createBrotliDecompress());
|
|
119
|
+
} else if (/\bdeflate(?!-(?:\w+)?)\b/i.test(encoding)) {
|
|
120
|
+
decoders.push(zlib.createInflate());
|
|
121
|
+
} else if (/\bdeflate-raw\b/i.test(encoding)) {
|
|
122
|
+
decoders.push(zlib.createInflateRaw());
|
|
123
|
+
} else if (/\bgzip\b/i.test(encoding)) {
|
|
124
|
+
decoders.push(zlib.createGunzip());
|
|
125
|
+
} else {
|
|
126
|
+
return readable;
|
|
122
127
|
}
|
|
128
|
+
}
|
|
123
129
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
deflate: zlib.createDeflate,
|
|
127
|
-
gzip: zlib.createGzip,
|
|
128
|
-
}[headers[HTTP2_HEADER_CONTENT_ENCODING]] ?? PassThrough;
|
|
130
|
+
return pipeline(readable, ...decoders, () => void 0);
|
|
131
|
+
};
|
|
129
132
|
|
|
130
|
-
|
|
133
|
+
export const dispatch = ({ body }, req) => {
|
|
134
|
+
if (body?.pipe?.constructor === Function) {
|
|
135
|
+
body.pipe(req);
|
|
131
136
|
} else {
|
|
132
137
|
req.end(body);
|
|
133
138
|
}
|
|
@@ -170,7 +175,7 @@ export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
|
170
175
|
arrayBuffer: {
|
|
171
176
|
enumerable: true,
|
|
172
177
|
value: async function () {
|
|
173
|
-
|
|
178
|
+
brandCheck(this, res?.constructor);
|
|
174
179
|
parse &&= false;
|
|
175
180
|
const { buffer, byteLength, byteOffset } = await this.body();
|
|
176
181
|
|
|
@@ -180,7 +185,7 @@ export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
|
180
185
|
blob: {
|
|
181
186
|
enumerable: true,
|
|
182
187
|
value: async function () {
|
|
183
|
-
|
|
188
|
+
brandCheck(this, res?.constructor);
|
|
184
189
|
const val = await this.arrayBuffer();
|
|
185
190
|
|
|
186
191
|
return new Blob([val]);
|
|
@@ -189,7 +194,7 @@ export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
|
189
194
|
json: {
|
|
190
195
|
enumerable: true,
|
|
191
196
|
value: async function () {
|
|
192
|
-
|
|
197
|
+
brandCheck(this, res?.constructor);
|
|
193
198
|
const val = await this.text();
|
|
194
199
|
|
|
195
200
|
return JSON.parse(val);
|
|
@@ -198,7 +203,7 @@ export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
|
198
203
|
text: {
|
|
199
204
|
enumerable: true,
|
|
200
205
|
value: async function () {
|
|
201
|
-
|
|
206
|
+
brandCheck(this, res?.constructor);
|
|
202
207
|
const blob = await this.blob();
|
|
203
208
|
|
|
204
209
|
return blob.text();
|
|
@@ -211,25 +216,25 @@ export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
|
211
216
|
body: {
|
|
212
217
|
enumerable: true,
|
|
213
218
|
value: async function () {
|
|
214
|
-
|
|
219
|
+
brandCheck(this, res?.constructor);
|
|
215
220
|
|
|
216
221
|
if (this.bodyUsed) {
|
|
217
222
|
throw new TypeError('Response stream already read');
|
|
218
223
|
}
|
|
219
224
|
|
|
220
|
-
let
|
|
225
|
+
let body = [];
|
|
221
226
|
|
|
222
|
-
for await (const chunk of this) {
|
|
223
|
-
|
|
227
|
+
for await (const chunk of decompress(this, this.headers[HTTP2_HEADER_CONTENT_ENCODING])) {
|
|
228
|
+
body.push(chunk);
|
|
224
229
|
}
|
|
225
230
|
|
|
226
|
-
|
|
231
|
+
body = Buffer.concat(body);
|
|
227
232
|
|
|
228
|
-
if (
|
|
229
|
-
|
|
233
|
+
if (!body.length && parse) {
|
|
234
|
+
return null;
|
|
230
235
|
}
|
|
231
236
|
|
|
232
|
-
if (
|
|
237
|
+
if (body.length && parse) {
|
|
233
238
|
const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
|
|
234
239
|
const charset = contentType.split(';')
|
|
235
240
|
.find((it) => /charset=/i.test(it))
|
|
@@ -239,17 +244,17 @@ export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
|
239
244
|
.trim() || 'utf-8';
|
|
240
245
|
|
|
241
246
|
if (/\bjson\b/i.test(contentType)) {
|
|
242
|
-
|
|
243
|
-
} else if (/\b(text|xml)\b/i.test(contentType)) {
|
|
244
|
-
if (/\b(latin1|ucs-2|utf-(8|16le))\b/.test(charset)) {
|
|
245
|
-
|
|
247
|
+
body = JSON.parse(body.toString(charset));
|
|
248
|
+
} else if (/\b(?:text|xml)\b/i.test(contentType)) {
|
|
249
|
+
if (/\b(?:latin1|ucs-2|utf-(?:8|16le))\b/.test(charset)) {
|
|
250
|
+
body = body.toString(charset);
|
|
246
251
|
} else {
|
|
247
|
-
|
|
252
|
+
body = new TextDecoder(charset).decode(body);
|
|
248
253
|
}
|
|
249
254
|
}
|
|
250
255
|
}
|
|
251
256
|
|
|
252
|
-
return
|
|
257
|
+
return body;
|
|
253
258
|
},
|
|
254
259
|
writable: true,
|
|
255
260
|
},
|
|
@@ -297,7 +302,7 @@ export const preflight = (options) => {
|
|
|
297
302
|
options.h2 ??= h2;
|
|
298
303
|
options.headers = {
|
|
299
304
|
[HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
|
|
300
|
-
[HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, gzip, identity',
|
|
305
|
+
[HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, deflate-raw, gzip, identity',
|
|
301
306
|
...Object.entries(options.headers ?? {})
|
|
302
307
|
.reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
|
|
303
308
|
...h2 && {
|
|
@@ -310,9 +315,9 @@ export const preflight = (options) => {
|
|
|
310
315
|
|
|
311
316
|
options.method ??= method;
|
|
312
317
|
options.parse ??= true;
|
|
313
|
-
options.redirect ??=
|
|
318
|
+
options.redirect ??= redirectModes.follow;
|
|
314
319
|
|
|
315
|
-
if (!
|
|
320
|
+
if (!Reflect.has(redirectModes, options.redirect)) {
|
|
316
321
|
options.createConnection?.().destroy();
|
|
317
322
|
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
|
|
318
323
|
options.redirect
|
|
@@ -325,13 +330,7 @@ export const preflight = (options) => {
|
|
|
325
330
|
return options;
|
|
326
331
|
};
|
|
327
332
|
|
|
328
|
-
export const
|
|
329
|
-
error: 'error',
|
|
330
|
-
follow: 'follow',
|
|
331
|
-
manual: 'manual',
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
export const revise = ({ url, options }) => {
|
|
333
|
+
export const sanitize = (url, options = {}) => {
|
|
335
334
|
if (options.trimTrailingSlashes) {
|
|
336
335
|
url = `${ url }`.replace(/(?<!:)\/+/gi, '/');
|
|
337
336
|
}
|
|
@@ -341,6 +340,8 @@ export const revise = ({ url, options }) => {
|
|
|
341
340
|
return Object.assign(options, { url });
|
|
342
341
|
};
|
|
343
342
|
|
|
343
|
+
export const sameOrigin = (a, b) => a.protocol === b.protocol && a.hostname === b.hostname && a.port === b.port;
|
|
344
|
+
|
|
344
345
|
export async function* tap(value) {
|
|
345
346
|
if (Reflect.has(value, Symbol.asyncIterator)) {
|
|
346
347
|
yield* value;
|
|
@@ -351,13 +352,11 @@ export async function* tap(value) {
|
|
|
351
352
|
}
|
|
352
353
|
}
|
|
353
354
|
|
|
354
|
-
export const transform = (
|
|
355
|
-
let headers =
|
|
355
|
+
export const transform = async (options) => {
|
|
356
|
+
let { body, headers } = options;
|
|
356
357
|
|
|
357
|
-
if (
|
|
358
|
-
|
|
359
|
-
} else if (types.isArrayBufferView(body) && !Buffer.isBuffer(body)) {
|
|
360
|
-
body = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
358
|
+
if (!body) {
|
|
359
|
+
return options;
|
|
361
360
|
}
|
|
362
361
|
|
|
363
362
|
if (File.alike(body)) {
|
|
@@ -365,38 +364,47 @@ export const transform = (body, options) => {
|
|
|
365
364
|
[HTTP2_HEADER_CONTENT_LENGTH]: body.size,
|
|
366
365
|
[HTTP2_HEADER_CONTENT_TYPE]: body.type || APPLICATION_OCTET_STREAM,
|
|
367
366
|
};
|
|
368
|
-
body = body.stream
|
|
367
|
+
body = body.stream();
|
|
369
368
|
} else if (FormData.alike(body)) {
|
|
370
369
|
body = FormData.actuate(body);
|
|
371
370
|
headers = { [HTTP2_HEADER_CONTENT_TYPE]: body.contentType };
|
|
372
|
-
} else if (
|
|
373
|
-
if (body
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
371
|
+
} else if (!Buffer.isBuffer(body)) {
|
|
372
|
+
if (types.isAnyArrayBuffer(body)) {
|
|
373
|
+
body = Buffer.from(body);
|
|
374
|
+
} else if (types.isArrayBufferView(body)) {
|
|
375
|
+
body = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
376
|
+
} else if (body === Object(body) && !Reflect.has(body, Symbol.asyncIterator)) {
|
|
377
|
+
if (body.constructor === URLSearchParams) {
|
|
378
|
+
headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_FORM_URLENCODED };
|
|
379
|
+
body = body.toString();
|
|
380
|
+
} else if (!(!Array.isArray(body) && Reflect.has(body, Symbol.iterator))) {
|
|
381
|
+
headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_JSON };
|
|
382
|
+
body = JSON.stringify(body);
|
|
383
|
+
}
|
|
380
384
|
}
|
|
385
|
+
}
|
|
381
386
|
|
|
382
|
-
|
|
383
|
-
if (options.headers[HTTP2_HEADER_CONTENT_ENCODING]) {
|
|
384
|
-
body = compress(body, options.headers[HTTP2_HEADER_CONTENT_ENCODING]);
|
|
385
|
-
}
|
|
387
|
+
const encodings = options.headers[HTTP2_HEADER_CONTENT_ENCODING];
|
|
386
388
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
389
|
+
if (body === Object(body)
|
|
390
|
+
&& (Reflect.has(body, Symbol.asyncIterator) || (!Array.isArray(body) && Reflect.has(body, Symbol.iterator)))) {
|
|
391
|
+
body = encodings ? compress(Readable.from(body), encodings) : Readable.from(body);
|
|
392
|
+
} else if (encodings) {
|
|
393
|
+
body = await buffer(compress(Readable.from(body), encodings));
|
|
392
394
|
}
|
|
393
395
|
|
|
394
396
|
Object.assign(options.headers, {
|
|
395
397
|
...headers,
|
|
398
|
+
...!body[Symbol.asyncIterator] && {
|
|
399
|
+
[HTTP2_HEADER_CONTENT_LENGTH]: Buffer.byteLength(body),
|
|
400
|
+
},
|
|
396
401
|
...options.headers[HTTP2_HEADER_CONTENT_TYPE] && {
|
|
397
402
|
[HTTP2_HEADER_CONTENT_TYPE]: options.headers[HTTP2_HEADER_CONTENT_TYPE],
|
|
398
403
|
},
|
|
399
404
|
});
|
|
400
405
|
|
|
401
|
-
return
|
|
406
|
+
return {
|
|
407
|
+
...options,
|
|
408
|
+
body,
|
|
409
|
+
};
|
|
402
410
|
};
|