rekwest 7.2.7 → 8.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 +264 -260
- package/dist/ackn.cjs +9 -0
- package/dist/config.cjs +2 -1
- package/dist/cookies.cjs +1 -1
- package/dist/transfer.cjs +1 -5
- package/dist/utils.cjs +4 -0
- package/package.json +81 -76
- package/src/ackn.js +46 -33
- package/src/config.js +91 -90
- package/src/constants.js +11 -11
- package/src/cookies.js +121 -121
- package/src/errors.js +18 -18
- package/src/formdata.js +229 -229
- package/src/index.js +83 -83
- package/src/mediatypes.js +6 -6
- package/src/mixin.js +118 -118
- package/src/postflight.js +64 -64
- package/src/preflight.js +84 -84
- package/src/redirects.js +86 -86
- package/src/transfer.js +104 -106
- package/src/transform.js +112 -112
- package/src/utils.js +198 -193
- package/src/validation.js +33 -33
package/src/redirects.js
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import http2 from 'node:http2';
|
|
2
|
-
import { isReadable } from 'node:stream';
|
|
3
|
-
import {
|
|
4
|
-
requestCredentials,
|
|
5
|
-
requestRedirect,
|
|
6
|
-
} from './constants.js';
|
|
7
|
-
import { RequestError } from './errors.js';
|
|
8
|
-
import rekwest from './index.js';
|
|
9
|
-
import {
|
|
10
|
-
isPipeStream,
|
|
11
|
-
sameOrigin,
|
|
12
|
-
} from './utils.js';
|
|
13
|
-
|
|
14
|
-
const {
|
|
15
|
-
HTTP2_HEADER_LOCATION,
|
|
16
|
-
HTTP2_METHOD_GET,
|
|
17
|
-
HTTP2_METHOD_HEAD,
|
|
18
|
-
HTTP2_METHOD_POST,
|
|
19
|
-
HTTP_STATUS_FOUND,
|
|
20
|
-
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
21
|
-
HTTP_STATUS_PERMANENT_REDIRECT,
|
|
22
|
-
HTTP_STATUS_SEE_OTHER,
|
|
23
|
-
HTTP_STATUS_TEMPORARY_REDIRECT,
|
|
24
|
-
} = http2.constants;
|
|
25
|
-
|
|
26
|
-
export const redirects = (res, options) => {
|
|
27
|
-
const {
|
|
28
|
-
allowDowngrade,
|
|
29
|
-
credentials,
|
|
30
|
-
follow,
|
|
31
|
-
redirect,
|
|
32
|
-
url,
|
|
33
|
-
} = options;
|
|
34
|
-
|
|
35
|
-
if (follow && /3\d{2}/.test(res.statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
|
|
36
|
-
if (redirect === requestRedirect.error) {
|
|
37
|
-
throw new RequestError(`Unexpected redirect, redirect mode is set to: ${ redirect }`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (redirect === requestRedirect.follow) {
|
|
41
|
-
const loc = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
|
|
42
|
-
|
|
43
|
-
if (!/^https?:/i.test(loc.protocol)) {
|
|
44
|
-
throw new RequestError('URL scheme must be "http" or "https"');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (!allowDowngrade && loc.protocol === 'http:' && url.protocol === 'https:') {
|
|
48
|
-
throw new RequestError(
|
|
49
|
-
`Protocol downgrade detected, redirect from "${ url.protocol }" to "${ loc.protocol }": ${ loc }`,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!sameOrigin(loc, url)) {
|
|
54
|
-
if (credentials !== requestCredentials.include) {
|
|
55
|
-
options.credentials = requestCredentials.omit;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
options.h2 = false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if ([
|
|
62
|
-
HTTP_STATUS_PERMANENT_REDIRECT,
|
|
63
|
-
HTTP_STATUS_TEMPORARY_REDIRECT,
|
|
64
|
-
].includes(res.statusCode) && isPipeStream(options.body) && !isReadable(options.body)) {
|
|
65
|
-
throw new RequestError(`Unable to ${ redirect } redirect with streamable body`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (([
|
|
69
|
-
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
70
|
-
HTTP_STATUS_FOUND,
|
|
71
|
-
].includes(res.statusCode) && options.method === HTTP2_METHOD_POST)
|
|
72
|
-
|| (res.statusCode === HTTP_STATUS_SEE_OTHER && ![
|
|
73
|
-
HTTP2_METHOD_GET,
|
|
74
|
-
HTTP2_METHOD_HEAD,
|
|
75
|
-
].includes(options.method))) {
|
|
76
|
-
options.body = null;
|
|
77
|
-
options.method = HTTP2_METHOD_GET;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
options.follow--;
|
|
81
|
-
options.redirected = true;
|
|
82
|
-
|
|
83
|
-
return rekwest(loc, options);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
};
|
|
1
|
+
import http2 from 'node:http2';
|
|
2
|
+
import { isReadable } from 'node:stream';
|
|
3
|
+
import {
|
|
4
|
+
requestCredentials,
|
|
5
|
+
requestRedirect,
|
|
6
|
+
} from './constants.js';
|
|
7
|
+
import { RequestError } from './errors.js';
|
|
8
|
+
import rekwest from './index.js';
|
|
9
|
+
import {
|
|
10
|
+
isPipeStream,
|
|
11
|
+
sameOrigin,
|
|
12
|
+
} from './utils.js';
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
HTTP2_HEADER_LOCATION,
|
|
16
|
+
HTTP2_METHOD_GET,
|
|
17
|
+
HTTP2_METHOD_HEAD,
|
|
18
|
+
HTTP2_METHOD_POST,
|
|
19
|
+
HTTP_STATUS_FOUND,
|
|
20
|
+
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
21
|
+
HTTP_STATUS_PERMANENT_REDIRECT,
|
|
22
|
+
HTTP_STATUS_SEE_OTHER,
|
|
23
|
+
HTTP_STATUS_TEMPORARY_REDIRECT,
|
|
24
|
+
} = http2.constants;
|
|
25
|
+
|
|
26
|
+
export const redirects = (res, options) => {
|
|
27
|
+
const {
|
|
28
|
+
allowDowngrade,
|
|
29
|
+
credentials,
|
|
30
|
+
follow,
|
|
31
|
+
redirect,
|
|
32
|
+
url,
|
|
33
|
+
} = options;
|
|
34
|
+
|
|
35
|
+
if (follow && /3\d{2}/.test(res.statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
|
|
36
|
+
if (redirect === requestRedirect.error) {
|
|
37
|
+
throw new RequestError(`Unexpected redirect, redirect mode is set to: ${ redirect }`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (redirect === requestRedirect.follow) {
|
|
41
|
+
const loc = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
|
|
42
|
+
|
|
43
|
+
if (!/^https?:/i.test(loc.protocol)) {
|
|
44
|
+
throw new RequestError('URL scheme must be "http" or "https"');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!allowDowngrade && loc.protocol === 'http:' && url.protocol === 'https:') {
|
|
48
|
+
throw new RequestError(
|
|
49
|
+
`Protocol downgrade detected, redirect from "${ url.protocol }" to "${ loc.protocol }": ${ loc }`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!sameOrigin(loc, url)) {
|
|
54
|
+
if (credentials !== requestCredentials.include) {
|
|
55
|
+
options.credentials = requestCredentials.omit;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
options.h2 = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if ([
|
|
62
|
+
HTTP_STATUS_PERMANENT_REDIRECT,
|
|
63
|
+
HTTP_STATUS_TEMPORARY_REDIRECT,
|
|
64
|
+
].includes(res.statusCode) && isPipeStream(options.body) && !isReadable(options.body)) {
|
|
65
|
+
throw new RequestError(`Unable to ${ redirect } redirect with streamable body`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (([
|
|
69
|
+
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
70
|
+
HTTP_STATUS_FOUND,
|
|
71
|
+
].includes(res.statusCode) && options.method === HTTP2_METHOD_POST)
|
|
72
|
+
|| (res.statusCode === HTTP_STATUS_SEE_OTHER && ![
|
|
73
|
+
HTTP2_METHOD_GET,
|
|
74
|
+
HTTP2_METHOD_HEAD,
|
|
75
|
+
].includes(options.method))) {
|
|
76
|
+
options.body = null;
|
|
77
|
+
options.method = HTTP2_METHOD_GET;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
options.follow--;
|
|
81
|
+
options.redirected = true;
|
|
82
|
+
|
|
83
|
+
return rekwest(loc, options);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
package/src/transfer.js
CHANGED
|
@@ -1,106 +1,104 @@
|
|
|
1
|
-
import http from 'node:http';
|
|
2
|
-
import http2 from 'node:http2';
|
|
3
|
-
import https from 'node:https';
|
|
4
|
-
import { ackn } from './ackn.js';
|
|
5
|
-
import { RequestError } from './errors.js';
|
|
6
|
-
import { postflight } from './postflight.js';
|
|
7
|
-
import { preflight } from './preflight.js';
|
|
8
|
-
import { retries } from './retries.js';
|
|
9
|
-
import { transform } from './transform.js';
|
|
10
|
-
import {
|
|
11
|
-
deepMerge,
|
|
12
|
-
dispatch,
|
|
13
|
-
isLikelyH2cPrefaceError,
|
|
14
|
-
snoop,
|
|
15
|
-
} from './utils.js';
|
|
16
|
-
|
|
17
|
-
export const transfer = async (options) => {
|
|
18
|
-
const { digest, redirected, thenable, url } = options;
|
|
19
|
-
|
|
20
|
-
if (options.follow === 0) {
|
|
21
|
-
throw new RequestError(`Maximum redirect reached at: ${ url.href }`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (url.protocol === 'https:') {
|
|
25
|
-
options =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
options
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
};
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import http2 from 'node:http2';
|
|
3
|
+
import https from 'node:https';
|
|
4
|
+
import { ackn } from './ackn.js';
|
|
5
|
+
import { RequestError } from './errors.js';
|
|
6
|
+
import { postflight } from './postflight.js';
|
|
7
|
+
import { preflight } from './preflight.js';
|
|
8
|
+
import { retries } from './retries.js';
|
|
9
|
+
import { transform } from './transform.js';
|
|
10
|
+
import {
|
|
11
|
+
deepMerge,
|
|
12
|
+
dispatch,
|
|
13
|
+
isLikelyH2cPrefaceError,
|
|
14
|
+
snoop,
|
|
15
|
+
} from './utils.js';
|
|
16
|
+
|
|
17
|
+
export const transfer = async (options) => {
|
|
18
|
+
const { digest, redirected, thenable, url } = options;
|
|
19
|
+
|
|
20
|
+
if (options.follow === 0) {
|
|
21
|
+
throw new RequestError(`Maximum redirect reached at: ${ url.href }`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (url.protocol === 'https:') {
|
|
25
|
+
options = await ackn(options);
|
|
26
|
+
} else if (Reflect.has(options, 'alpnProtocol')) {
|
|
27
|
+
for (const it of [
|
|
28
|
+
'alpnProtocol',
|
|
29
|
+
'createConnection',
|
|
30
|
+
'h2',
|
|
31
|
+
'protocol',
|
|
32
|
+
]) { Reflect.deleteProperty(options, it); }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
options = await transform(preflight(options));
|
|
37
|
+
} catch (err) {
|
|
38
|
+
options.createConnection?.().destroy();
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const promise = new Promise((resolve, reject) => {
|
|
43
|
+
let client, req;
|
|
44
|
+
|
|
45
|
+
if (options.h2) {
|
|
46
|
+
client = http2.connect(url.origin, options);
|
|
47
|
+
req = client.request(options.headers, options);
|
|
48
|
+
} else {
|
|
49
|
+
const { request } = url.protocol === 'http:' ? http : https;
|
|
50
|
+
|
|
51
|
+
req = request(url, options);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
snoop(client, req, options, { reject });
|
|
55
|
+
|
|
56
|
+
req.once('response', (res) => postflight(req, res, options, {
|
|
57
|
+
reject, resolve,
|
|
58
|
+
}));
|
|
59
|
+
|
|
60
|
+
dispatch(req, options);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const res = await promise;
|
|
65
|
+
|
|
66
|
+
if (digest && !redirected) {
|
|
67
|
+
res.body = await res.body();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return res;
|
|
71
|
+
} catch (err) {
|
|
72
|
+
if (isLikelyH2cPrefaceError(err)) {
|
|
73
|
+
const { retry } = options;
|
|
74
|
+
|
|
75
|
+
options = deepMerge(options, {
|
|
76
|
+
h2: true,
|
|
77
|
+
retry: {
|
|
78
|
+
attempts: ++retry.attempts,
|
|
79
|
+
errorCodes: [
|
|
80
|
+
err.code,
|
|
81
|
+
...retry.errorCodes,
|
|
82
|
+
],
|
|
83
|
+
interval: 1,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const result = retries(err, options);
|
|
89
|
+
|
|
90
|
+
if (result) {
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (digest && !redirected && err.body) {
|
|
95
|
+
err.body = await err.body();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!thenable) {
|
|
99
|
+
throw err;
|
|
100
|
+
} else {
|
|
101
|
+
return err;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
package/src/transform.js
CHANGED
|
@@ -1,112 +1,112 @@
|
|
|
1
|
-
import http2 from 'node:http2';
|
|
2
|
-
import {
|
|
3
|
-
isReadable,
|
|
4
|
-
Readable,
|
|
5
|
-
} from 'node:stream';
|
|
6
|
-
import { buffer } from 'node:stream/consumers';
|
|
7
|
-
import { types } from 'node:util';
|
|
8
|
-
import { encode } from './codecs.js';
|
|
9
|
-
import {
|
|
10
|
-
fdToAsyncIterable,
|
|
11
|
-
isFormData,
|
|
12
|
-
} from './formdata.js';
|
|
13
|
-
import {
|
|
14
|
-
APPLICATION_FORM_URLENCODED,
|
|
15
|
-
APPLICATION_JSON,
|
|
16
|
-
APPLICATION_OCTET_STREAM,
|
|
17
|
-
} from './mediatypes.js';
|
|
18
|
-
import {
|
|
19
|
-
isBlobLike,
|
|
20
|
-
isReadableStream,
|
|
21
|
-
} from './utils.js';
|
|
22
|
-
|
|
23
|
-
const {
|
|
24
|
-
HTTP2_HEADER_CONTENT_ENCODING,
|
|
25
|
-
HTTP2_HEADER_CONTENT_LENGTH,
|
|
26
|
-
HTTP2_HEADER_CONTENT_TYPE,
|
|
27
|
-
} = http2.constants;
|
|
28
|
-
|
|
29
|
-
export const transform = async (options) => {
|
|
30
|
-
let { body, headers } = options;
|
|
31
|
-
|
|
32
|
-
if (!body) {
|
|
33
|
-
return options;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!Buffer.isBuffer(body)) {
|
|
37
|
-
switch (true) {
|
|
38
|
-
case isBlobLike(body): {
|
|
39
|
-
headers = {
|
|
40
|
-
[HTTP2_HEADER_CONTENT_LENGTH]: body.size,
|
|
41
|
-
[HTTP2_HEADER_CONTENT_TYPE]: body.type || APPLICATION_OCTET_STREAM,
|
|
42
|
-
};
|
|
43
|
-
body = body.stream();
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
case isFormData(body): {
|
|
48
|
-
body = fdToAsyncIterable(body);
|
|
49
|
-
headers = { [HTTP2_HEADER_CONTENT_TYPE]: body.contentType };
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
case types.isAnyArrayBuffer(body): {
|
|
54
|
-
body = Buffer.from(body);
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
case types.isArrayBufferView(body): {
|
|
59
|
-
body = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
case Object(body) === body && !Reflect.has(body, Symbol.asyncIterator): {
|
|
64
|
-
if (body.constructor === URLSearchParams) {
|
|
65
|
-
headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_FORM_URLENCODED };
|
|
66
|
-
body = body.toString();
|
|
67
|
-
} else if (!(!Array.isArray(body) && Reflect.has(body, Symbol.iterator))) {
|
|
68
|
-
headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_JSON };
|
|
69
|
-
body = JSON.stringify(body);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
default:
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const encodings = options.headers[HTTP2_HEADER_CONTENT_ENCODING];
|
|
81
|
-
|
|
82
|
-
if (Object(body) === body
|
|
83
|
-
&& (Reflect.has(body, Symbol.asyncIterator) || (!Array.isArray(body) && Reflect.has(body, Symbol.iterator)))) {
|
|
84
|
-
body = isReadable(body) ? (isReadableStream(body) ? Readable.fromWeb(body) : body) : Readable.from(body);
|
|
85
|
-
body = encodings ? encode(body, encodings, options) : body;
|
|
86
|
-
} else if (encodings) {
|
|
87
|
-
body = await buffer(encode(Readable.from(body), encodings, options));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (options.bufferBody && Object(body) === body) {
|
|
91
|
-
if (isReadable(body)) {
|
|
92
|
-
body = await buffer(body);
|
|
93
|
-
} else if (Reflect.has(body, Symbol.asyncIterator)) {
|
|
94
|
-
body = await buffer(body);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
Object.assign(options.headers, {
|
|
99
|
-
...headers,
|
|
100
|
-
...!body[Symbol.asyncIterator] && {
|
|
101
|
-
[HTTP2_HEADER_CONTENT_LENGTH]: Buffer.byteLength(body),
|
|
102
|
-
},
|
|
103
|
-
...options.headers[HTTP2_HEADER_CONTENT_TYPE] && {
|
|
104
|
-
[HTTP2_HEADER_CONTENT_TYPE]: options.headers[HTTP2_HEADER_CONTENT_TYPE],
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
...options,
|
|
110
|
-
body,
|
|
111
|
-
};
|
|
112
|
-
};
|
|
1
|
+
import http2 from 'node:http2';
|
|
2
|
+
import {
|
|
3
|
+
isReadable,
|
|
4
|
+
Readable,
|
|
5
|
+
} from 'node:stream';
|
|
6
|
+
import { buffer } from 'node:stream/consumers';
|
|
7
|
+
import { types } from 'node:util';
|
|
8
|
+
import { encode } from './codecs.js';
|
|
9
|
+
import {
|
|
10
|
+
fdToAsyncIterable,
|
|
11
|
+
isFormData,
|
|
12
|
+
} from './formdata.js';
|
|
13
|
+
import {
|
|
14
|
+
APPLICATION_FORM_URLENCODED,
|
|
15
|
+
APPLICATION_JSON,
|
|
16
|
+
APPLICATION_OCTET_STREAM,
|
|
17
|
+
} from './mediatypes.js';
|
|
18
|
+
import {
|
|
19
|
+
isBlobLike,
|
|
20
|
+
isReadableStream,
|
|
21
|
+
} from './utils.js';
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
HTTP2_HEADER_CONTENT_ENCODING,
|
|
25
|
+
HTTP2_HEADER_CONTENT_LENGTH,
|
|
26
|
+
HTTP2_HEADER_CONTENT_TYPE,
|
|
27
|
+
} = http2.constants;
|
|
28
|
+
|
|
29
|
+
export const transform = async (options) => {
|
|
30
|
+
let { body, headers } = options;
|
|
31
|
+
|
|
32
|
+
if (!body) {
|
|
33
|
+
return options;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!Buffer.isBuffer(body)) {
|
|
37
|
+
switch (true) {
|
|
38
|
+
case isBlobLike(body): {
|
|
39
|
+
headers = {
|
|
40
|
+
[HTTP2_HEADER_CONTENT_LENGTH]: body.size,
|
|
41
|
+
[HTTP2_HEADER_CONTENT_TYPE]: body.type || APPLICATION_OCTET_STREAM,
|
|
42
|
+
};
|
|
43
|
+
body = body.stream();
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
case isFormData(body): {
|
|
48
|
+
body = fdToAsyncIterable(body);
|
|
49
|
+
headers = { [HTTP2_HEADER_CONTENT_TYPE]: body.contentType };
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
case types.isAnyArrayBuffer(body): {
|
|
54
|
+
body = Buffer.from(body);
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
case types.isArrayBufferView(body): {
|
|
59
|
+
body = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
case Object(body) === body && !Reflect.has(body, Symbol.asyncIterator): {
|
|
64
|
+
if (body.constructor === URLSearchParams) {
|
|
65
|
+
headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_FORM_URLENCODED };
|
|
66
|
+
body = body.toString();
|
|
67
|
+
} else if (!(!Array.isArray(body) && Reflect.has(body, Symbol.iterator))) {
|
|
68
|
+
headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_JSON };
|
|
69
|
+
body = JSON.stringify(body);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
default:
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const encodings = options.headers[HTTP2_HEADER_CONTENT_ENCODING];
|
|
81
|
+
|
|
82
|
+
if (Object(body) === body
|
|
83
|
+
&& (Reflect.has(body, Symbol.asyncIterator) || (!Array.isArray(body) && Reflect.has(body, Symbol.iterator)))) {
|
|
84
|
+
body = isReadable(body) ? (isReadableStream(body) ? Readable.fromWeb(body) : body) : Readable.from(body);
|
|
85
|
+
body = encodings ? encode(body, encodings, options) : body;
|
|
86
|
+
} else if (encodings) {
|
|
87
|
+
body = await buffer(encode(Readable.from(body), encodings, options));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (options.bufferBody && Object(body) === body) {
|
|
91
|
+
if (isReadable(body)) {
|
|
92
|
+
body = await buffer(body);
|
|
93
|
+
} else if (Reflect.has(body, Symbol.asyncIterator)) {
|
|
94
|
+
body = await buffer(body);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
Object.assign(options.headers, {
|
|
99
|
+
...headers,
|
|
100
|
+
...!body[Symbol.asyncIterator] && {
|
|
101
|
+
[HTTP2_HEADER_CONTENT_LENGTH]: Buffer.byteLength(body),
|
|
102
|
+
},
|
|
103
|
+
...options.headers[HTTP2_HEADER_CONTENT_TYPE] && {
|
|
104
|
+
[HTTP2_HEADER_CONTENT_TYPE]: options.headers[HTTP2_HEADER_CONTENT_TYPE],
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
...options,
|
|
110
|
+
body,
|
|
111
|
+
};
|
|
112
|
+
};
|