rekwest 6.2.1 → 7.0.1
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 +11 -10
- package/dist/codecs.cjs +55 -0
- package/dist/{config.js → config.cjs} +15 -19
- package/dist/{cookies.js → cookies.cjs} +2 -2
- package/dist/{formdata.js → formdata.cjs} +8 -11
- package/dist/{index.js → index.cjs} +27 -15
- package/dist/{mixin.js → mixin.cjs} +22 -17
- package/dist/postflight.cjs +60 -0
- package/dist/{preflight.js → preflight.cjs} +13 -23
- package/dist/redirects.cjs +63 -0
- package/dist/retries.cjs +57 -0
- package/dist/{transfer.js → transfer.cjs} +13 -40
- package/dist/transform.cjs +105 -0
- package/dist/{utils.js → utils.cjs} +57 -80
- package/dist/{validation.js → validation.cjs} +1 -1
- package/package.json +14 -13
- package/src/{ackn.mjs → ackn.js} +33 -33
- package/src/codecs.js +55 -0
- package/src/{config.mjs → config.js} +88 -93
- package/src/{constants.mjs → constants.js} +29 -29
- package/src/{cookies.mjs → cookies.js} +100 -100
- package/src/{formdata.mjs → formdata.js} +8 -14
- package/src/{index.mjs → index.js} +22 -22
- package/src/{mediatypes.mjs → mediatypes.js} +6 -6
- package/src/{mixin.mjs → mixin.js} +25 -26
- package/src/postflight.js +56 -0
- package/src/{preflight.mjs → preflight.js} +84 -91
- package/src/redirects.js +79 -0
- package/src/retries.js +51 -0
- package/src/transfer.js +92 -0
- package/src/transform.js +109 -0
- package/src/utils.js +187 -0
- package/src/{validation.mjs → validation.js} +33 -33
- package/dist/postflight.js +0 -117
- package/dist/transform.js +0 -79
- package/src/postflight.mjs +0 -136
- package/src/transfer.mjs +0 -121
- package/src/transform.mjs +0 -82
- package/src/utils.mjs +0 -205
- /package/dist/{ackn.js → ackn.cjs} +0 -0
- /package/dist/{constants.js → constants.cjs} +0 -0
- /package/dist/{errors.js → errors.cjs} +0 -0
- /package/dist/{mediatypes.js → mediatypes.cjs} +0 -0
- /package/src/{errors.mjs → errors.js} +0 -0
package/src/utils.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Blob,
|
|
3
|
+
File,
|
|
4
|
+
} from 'node:buffer';
|
|
5
|
+
import http2 from 'node:http2';
|
|
6
|
+
import {
|
|
7
|
+
isReadable,
|
|
8
|
+
Readable,
|
|
9
|
+
} from 'node:stream';
|
|
10
|
+
import config, { isZstdSupported } from './config.js';
|
|
11
|
+
import { TimeoutError } from './errors.js';
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
HTTP2_HEADER_ACCEPT_ENCODING,
|
|
15
|
+
HTTP2_HEADER_STATUS,
|
|
16
|
+
} = http2.constants;
|
|
17
|
+
|
|
18
|
+
export const augment = (res, headers, options) => {
|
|
19
|
+
const { h2 } = options;
|
|
20
|
+
|
|
21
|
+
if (h2) {
|
|
22
|
+
Reflect.defineProperty(res, 'headers', {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
value: headers,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
Reflect.defineProperty(res, 'httpVersion', {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
value: `${ h2 + 1 }.0`,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
Reflect.defineProperty(res, 'statusCode', {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
value: headers[HTTP2_HEADER_STATUS],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Reflect.defineProperty(res, 'ok', {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
value: /^2\d{2}$/.test(res.statusCode),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
Reflect.defineProperty(res, 'redirected', {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
value: !!options.redirected,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const brandCheck = (value, ctor) => {
|
|
50
|
+
if (!(value instanceof ctor)) {
|
|
51
|
+
throw new TypeError('Illegal invocation.');
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const copyWithMerge = (target, ...rest) => {
|
|
56
|
+
target = structuredClone(target);
|
|
57
|
+
if (!rest.length) {
|
|
58
|
+
return target;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return merge(target, ...rest);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const dispatch = (req, { body }) => {
|
|
65
|
+
if (isReadable(body)) {
|
|
66
|
+
body.pipe(req);
|
|
67
|
+
} else {
|
|
68
|
+
req.end(body);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const isFileLike = (value) => {
|
|
73
|
+
return [
|
|
74
|
+
Blob,
|
|
75
|
+
File,
|
|
76
|
+
].some((it) => value instanceof it);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const isPipeStream = (value) => {
|
|
80
|
+
return value instanceof Readable;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const isReadableStream = (value) => {
|
|
84
|
+
return value instanceof ReadableStream;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const merge = (target, ...rest) => {
|
|
88
|
+
rest = rest.filter((it) => Object(it) === it);
|
|
89
|
+
for (const source of rest) {
|
|
90
|
+
for (const key of Object.getOwnPropertyNames(source)) {
|
|
91
|
+
const sv = source[key];
|
|
92
|
+
const tv = target[key];
|
|
93
|
+
|
|
94
|
+
if (Object(sv) === sv && Object(tv) === tv) {
|
|
95
|
+
target[key] = merge(tv, sv);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
target[key] = source[key];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return target;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const normalize = (url, options = {}) => {
|
|
107
|
+
if (!options.redirected) {
|
|
108
|
+
options = copyWithMerge(config.defaults, options);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (options.trimTrailingSlashes) {
|
|
112
|
+
url = `${ url }`.replace(/(?<!:)\/+/g, '/');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (options.stripTrailingSlash) {
|
|
116
|
+
url = `${ url }`.replace(/\/$|\/(?=#)|\/(?=\?)/g, '');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return Object.assign(options, {
|
|
120
|
+
headers: normalizeHeaders(options.headers),
|
|
121
|
+
method: options.method.toUpperCase(),
|
|
122
|
+
url: new URL(url, options.baseURL),
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const normalizeHeaders = (headers) => {
|
|
127
|
+
const collector = {};
|
|
128
|
+
|
|
129
|
+
for (const [key, value] of Object.entries(headers ?? {})) {
|
|
130
|
+
const name = key.toLowerCase();
|
|
131
|
+
|
|
132
|
+
collector[key] = value;
|
|
133
|
+
|
|
134
|
+
if (key === HTTP2_HEADER_ACCEPT_ENCODING && !isZstdSupported) {
|
|
135
|
+
const stripped = value.replace(/\s?zstd,?/gi, '').trim();
|
|
136
|
+
|
|
137
|
+
if (stripped) {
|
|
138
|
+
collector[key] = stripped;
|
|
139
|
+
} else {
|
|
140
|
+
Reflect.deleteProperty(collector, name);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return collector;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const sameOrigin = (a, b) => a.protocol === b.protocol && a.hostname === b.hostname && a.port === b.port;
|
|
149
|
+
|
|
150
|
+
export const snoop = (client, req, options) => {
|
|
151
|
+
req.once('close', () => client?.close());
|
|
152
|
+
req.once('end', () => client?.close());
|
|
153
|
+
req.once('timeout', () => req.destroy(new TimeoutError(`Timed out after ${ options.timeout } ms.`)));
|
|
154
|
+
req.once('trailers', (trailers) => {
|
|
155
|
+
Reflect.defineProperty(req, 'trailers', {
|
|
156
|
+
enumerable: true,
|
|
157
|
+
value: trailers,
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export const stripHeaders = (headers = {}, names = []) => {
|
|
163
|
+
names = new Set(names);
|
|
164
|
+
|
|
165
|
+
return Object.fromEntries(
|
|
166
|
+
Object.entries(headers).filter(
|
|
167
|
+
([key]) => !names.has(key.toLowerCase()),
|
|
168
|
+
),
|
|
169
|
+
);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export async function* tap(value) {
|
|
173
|
+
if (Reflect.has(value, Symbol.asyncIterator)) {
|
|
174
|
+
yield* value;
|
|
175
|
+
} else if (value.stream) {
|
|
176
|
+
yield* value.stream();
|
|
177
|
+
} else {
|
|
178
|
+
yield await value.arrayBuffer();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export const toCamelCase = (str) => str?.toLowerCase().replace(
|
|
183
|
+
/\p{Punctuation}.|\p{White_Space}./gu,
|
|
184
|
+
(val) => val.replace(/\p{Punctuation}+|\p{White_Space}+/gu, '').toUpperCase(),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
export const unwind = (encodings) => encodings.split(',').map((it) => it.toLowerCase().trim());
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import http2 from 'node:http2';
|
|
2
|
-
import {
|
|
3
|
-
requestCredentials,
|
|
4
|
-
requestRedirect,
|
|
5
|
-
} from './constants.
|
|
6
|
-
|
|
7
|
-
const {
|
|
8
|
-
HTTP2_METHOD_GET,
|
|
9
|
-
HTTP2_METHOD_HEAD,
|
|
10
|
-
} = http2.constants;
|
|
11
|
-
|
|
12
|
-
export const validation = (options = {}) => {
|
|
13
|
-
if (options.body && [
|
|
14
|
-
HTTP2_METHOD_GET,
|
|
15
|
-
HTTP2_METHOD_HEAD,
|
|
16
|
-
].includes(options.method)) {
|
|
17
|
-
throw new TypeError(`Request with ${ HTTP2_METHOD_GET }/${ HTTP2_METHOD_HEAD } method cannot have body.`);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (!Object.values(requestCredentials).includes(options.credentials)) {
|
|
21
|
-
throw new TypeError(`Failed to read the 'credentials' property from 'options': The provided value '${
|
|
22
|
-
options.credentials
|
|
23
|
-
}' is not a valid enum value.`);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!Reflect.has(requestRedirect, options.redirect)) {
|
|
27
|
-
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
|
|
28
|
-
options.redirect
|
|
29
|
-
}' is not a valid enum value.`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return options;
|
|
33
|
-
};
|
|
1
|
+
import http2 from 'node:http2';
|
|
2
|
+
import {
|
|
3
|
+
requestCredentials,
|
|
4
|
+
requestRedirect,
|
|
5
|
+
} from './constants.js';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
HTTP2_METHOD_GET,
|
|
9
|
+
HTTP2_METHOD_HEAD,
|
|
10
|
+
} = http2.constants;
|
|
11
|
+
|
|
12
|
+
export const validation = (options = {}) => {
|
|
13
|
+
if (options.body && [
|
|
14
|
+
HTTP2_METHOD_GET,
|
|
15
|
+
HTTP2_METHOD_HEAD,
|
|
16
|
+
].includes(options.method)) {
|
|
17
|
+
throw new TypeError(`Request with ${ HTTP2_METHOD_GET }/${ HTTP2_METHOD_HEAD } method cannot have body.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!Object.values(requestCredentials).includes(options.credentials)) {
|
|
21
|
+
throw new TypeError(`Failed to read the 'credentials' property from 'options': The provided value '${
|
|
22
|
+
options.credentials
|
|
23
|
+
}' is not a valid enum value.`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!Reflect.has(requestRedirect, options.redirect)) {
|
|
27
|
+
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
|
|
28
|
+
options.redirect
|
|
29
|
+
}' is not a valid enum value.`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return options;
|
|
33
|
+
};
|
package/dist/postflight.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.postflight = void 0;
|
|
7
|
-
var _nodeHttp = _interopRequireDefault(require("node:http2"));
|
|
8
|
-
var _promises = require("node:timers/promises");
|
|
9
|
-
var _constants = require("./constants");
|
|
10
|
-
var _cookies = require("./cookies");
|
|
11
|
-
var _errors = require("./errors");
|
|
12
|
-
var _index = _interopRequireDefault(require("./index"));
|
|
13
|
-
var _mixin = require("./mixin");
|
|
14
|
-
var _utils = require("./utils");
|
|
15
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
|
-
const {
|
|
17
|
-
HTTP2_HEADER_LOCATION,
|
|
18
|
-
HTTP2_HEADER_RETRY_AFTER,
|
|
19
|
-
HTTP2_HEADER_SET_COOKIE,
|
|
20
|
-
HTTP2_METHOD_GET,
|
|
21
|
-
HTTP2_METHOD_HEAD,
|
|
22
|
-
HTTP2_METHOD_POST,
|
|
23
|
-
HTTP_STATUS_BAD_REQUEST,
|
|
24
|
-
HTTP_STATUS_FOUND,
|
|
25
|
-
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
26
|
-
HTTP_STATUS_SEE_OTHER
|
|
27
|
-
} = _nodeHttp.default.constants;
|
|
28
|
-
const postflight = (req, res, options, {
|
|
29
|
-
reject,
|
|
30
|
-
resolve
|
|
31
|
-
}) => {
|
|
32
|
-
const {
|
|
33
|
-
cookies,
|
|
34
|
-
credentials,
|
|
35
|
-
follow,
|
|
36
|
-
h2,
|
|
37
|
-
redirect,
|
|
38
|
-
url
|
|
39
|
-
} = options;
|
|
40
|
-
let headers;
|
|
41
|
-
if (h2) {
|
|
42
|
-
headers = res;
|
|
43
|
-
res = req;
|
|
44
|
-
} else {
|
|
45
|
-
res.once('error', reject);
|
|
46
|
-
}
|
|
47
|
-
(0, _utils.admix)(res, headers, options);
|
|
48
|
-
if (cookies !== false && res.headers[HTTP2_HEADER_SET_COOKIE]) {
|
|
49
|
-
if (_cookies.Cookies.jar.has(url.origin)) {
|
|
50
|
-
const cookie = new _cookies.Cookies(res.headers[HTTP2_HEADER_SET_COOKIE], options);
|
|
51
|
-
_cookies.Cookies.jar.get(url.origin).forEach((val, key) => {
|
|
52
|
-
if (!cookie.has(key)) {
|
|
53
|
-
cookie.set(key, val);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
_cookies.Cookies.jar.set(url.origin, cookie);
|
|
57
|
-
} else {
|
|
58
|
-
_cookies.Cookies.jar.set(url.origin, new _cookies.Cookies(res.headers[HTTP2_HEADER_SET_COOKIE], options));
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
Reflect.defineProperty(res, 'cookies', {
|
|
62
|
-
enumerable: true,
|
|
63
|
-
value: cookies !== false && _cookies.Cookies.jar.has(url.origin) ? _cookies.Cookies.jar.get(url.origin) : void 0
|
|
64
|
-
});
|
|
65
|
-
const {
|
|
66
|
-
statusCode
|
|
67
|
-
} = res;
|
|
68
|
-
if (follow && /3\d{2}/.test(statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
|
|
69
|
-
if (!_constants.requestRedirectCodes.includes(statusCode)) {
|
|
70
|
-
return res.emit('error', new RangeError(`Invalid status code: ${statusCode}`));
|
|
71
|
-
}
|
|
72
|
-
if (redirect === _constants.requestRedirect.error) {
|
|
73
|
-
return res.emit('error', new _errors.RequestError(`Unexpected redirect, redirect mode is set to '${redirect}'.`));
|
|
74
|
-
}
|
|
75
|
-
if (redirect === _constants.requestRedirect.follow) {
|
|
76
|
-
const location = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
|
|
77
|
-
if (!/^https?:/i.test(location.protocol)) {
|
|
78
|
-
return res.emit('error', new _errors.RequestError('URL scheme must be "http" or "https".'));
|
|
79
|
-
}
|
|
80
|
-
if (!(0, _utils.sameOrigin)(location, url)) {
|
|
81
|
-
if (credentials !== _constants.requestCredentials.include) {
|
|
82
|
-
options.credentials = _constants.requestCredentials.omit;
|
|
83
|
-
}
|
|
84
|
-
options.h2 = false;
|
|
85
|
-
}
|
|
86
|
-
if (statusCode !== HTTP_STATUS_SEE_OTHER && options.body?.pipe?.constructor === Function) {
|
|
87
|
-
return res.emit('error', new _errors.RequestError(`Unable to ${redirect} redirect with streamable body.`));
|
|
88
|
-
}
|
|
89
|
-
if ([HTTP_STATUS_MOVED_PERMANENTLY, HTTP_STATUS_FOUND].includes(statusCode) && options.method === HTTP2_METHOD_POST || statusCode === HTTP_STATUS_SEE_OTHER && ![HTTP2_METHOD_GET, HTTP2_METHOD_HEAD].includes(options.method)) {
|
|
90
|
-
for (const it of Object.keys(options.headers).filter(val => /^content-/i.test(val))) {
|
|
91
|
-
Reflect.deleteProperty(options.headers, it);
|
|
92
|
-
}
|
|
93
|
-
options.body = null;
|
|
94
|
-
options.method = HTTP2_METHOD_GET;
|
|
95
|
-
}
|
|
96
|
-
options.follow--;
|
|
97
|
-
options.redirected = true;
|
|
98
|
-
options.url = location;
|
|
99
|
-
if (statusCode === HTTP_STATUS_MOVED_PERMANENTLY && res.headers[HTTP2_HEADER_RETRY_AFTER]) {
|
|
100
|
-
let interval = res.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
101
|
-
interval = Number(interval) * 1e3 || new Date(interval) - Date.now();
|
|
102
|
-
if (interval > options.maxRetryAfter) {
|
|
103
|
-
return res.emit('error', (0, _utils.maxRetryAfterError)(interval, {
|
|
104
|
-
cause: (0, _mixin.mixin)(res, options)
|
|
105
|
-
}));
|
|
106
|
-
}
|
|
107
|
-
return (0, _promises.setTimeout)(interval).then(() => (0, _index.default)(options.url, options).then(resolve, reject));
|
|
108
|
-
}
|
|
109
|
-
return (0, _index.default)(options.url, options).then(resolve, reject);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (statusCode >= HTTP_STATUS_BAD_REQUEST) {
|
|
113
|
-
return reject((0, _mixin.mixin)(res, options));
|
|
114
|
-
}
|
|
115
|
-
resolve((0, _mixin.mixin)(res, options));
|
|
116
|
-
};
|
|
117
|
-
exports.postflight = postflight;
|
package/dist/transform.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.transform = void 0;
|
|
7
|
-
var _nodeHttp = _interopRequireDefault(require("node:http2"));
|
|
8
|
-
var _nodeStream = require("node:stream");
|
|
9
|
-
var _consumers = require("node:stream/consumers");
|
|
10
|
-
var _nodeUtil = require("node:util");
|
|
11
|
-
var _formdata = require("./formdata");
|
|
12
|
-
var _mediatypes = require("./mediatypes");
|
|
13
|
-
var _utils = require("./utils");
|
|
14
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
-
const {
|
|
16
|
-
HTTP2_HEADER_CONTENT_ENCODING,
|
|
17
|
-
HTTP2_HEADER_CONTENT_LENGTH,
|
|
18
|
-
HTTP2_HEADER_CONTENT_TYPE
|
|
19
|
-
} = _nodeHttp.default.constants;
|
|
20
|
-
const transform = async options => {
|
|
21
|
-
let {
|
|
22
|
-
body,
|
|
23
|
-
headers
|
|
24
|
-
} = options;
|
|
25
|
-
if (!body) {
|
|
26
|
-
return options;
|
|
27
|
-
}
|
|
28
|
-
if ((0, _utils.isFileLike)(body)) {
|
|
29
|
-
headers = {
|
|
30
|
-
[HTTP2_HEADER_CONTENT_LENGTH]: body.size,
|
|
31
|
-
[HTTP2_HEADER_CONTENT_TYPE]: body.type || _mediatypes.APPLICATION_OCTET_STREAM
|
|
32
|
-
};
|
|
33
|
-
body = body.stream();
|
|
34
|
-
} else if (_formdata.FormData.alike(body)) {
|
|
35
|
-
body = _formdata.FormData.actuate(body);
|
|
36
|
-
headers = {
|
|
37
|
-
[HTTP2_HEADER_CONTENT_TYPE]: body.contentType
|
|
38
|
-
};
|
|
39
|
-
} else if (!Buffer.isBuffer(body)) {
|
|
40
|
-
if (_nodeUtil.types.isAnyArrayBuffer(body)) {
|
|
41
|
-
body = Buffer.from(body);
|
|
42
|
-
} else if (_nodeUtil.types.isArrayBufferView(body)) {
|
|
43
|
-
body = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
44
|
-
} else if (body === Object(body) && !Reflect.has(body, Symbol.asyncIterator)) {
|
|
45
|
-
if (body.constructor === URLSearchParams) {
|
|
46
|
-
headers = {
|
|
47
|
-
[HTTP2_HEADER_CONTENT_TYPE]: _mediatypes.APPLICATION_FORM_URLENCODED
|
|
48
|
-
};
|
|
49
|
-
body = body.toString();
|
|
50
|
-
} else if (!(!Array.isArray(body) && Reflect.has(body, Symbol.iterator))) {
|
|
51
|
-
headers = {
|
|
52
|
-
[HTTP2_HEADER_CONTENT_TYPE]: _mediatypes.APPLICATION_JSON
|
|
53
|
-
};
|
|
54
|
-
body = JSON.stringify(body);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const encodings = options.headers[HTTP2_HEADER_CONTENT_ENCODING];
|
|
59
|
-
if (body === Object(body) && (Reflect.has(body, Symbol.asyncIterator) || !Array.isArray(body) && Reflect.has(body, Symbol.iterator))) {
|
|
60
|
-
body = (0, _nodeStream.isReadable)(body) ? (0, _utils.isReadableStream)(body) ? _nodeStream.Readable.fromWeb(body) : body : _nodeStream.Readable.from(body);
|
|
61
|
-
body = encodings ? (0, _utils.compress)(body, encodings, options) : body;
|
|
62
|
-
} else if (encodings) {
|
|
63
|
-
body = await (0, _consumers.buffer)((0, _utils.compress)(_nodeStream.Readable.from(body), encodings, options));
|
|
64
|
-
}
|
|
65
|
-
Object.assign(options.headers, {
|
|
66
|
-
...headers,
|
|
67
|
-
...(!body[Symbol.asyncIterator] && {
|
|
68
|
-
[HTTP2_HEADER_CONTENT_LENGTH]: Buffer.byteLength(body)
|
|
69
|
-
}),
|
|
70
|
-
...(options.headers[HTTP2_HEADER_CONTENT_TYPE] && {
|
|
71
|
-
[HTTP2_HEADER_CONTENT_TYPE]: options.headers[HTTP2_HEADER_CONTENT_TYPE]
|
|
72
|
-
})
|
|
73
|
-
});
|
|
74
|
-
return {
|
|
75
|
-
...options,
|
|
76
|
-
body
|
|
77
|
-
};
|
|
78
|
-
};
|
|
79
|
-
exports.transform = transform;
|
package/src/postflight.mjs
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import http2 from 'node:http2';
|
|
2
|
-
import { setTimeout as setTimeoutPromise } from 'node:timers/promises';
|
|
3
|
-
import {
|
|
4
|
-
requestCredentials,
|
|
5
|
-
requestRedirect,
|
|
6
|
-
requestRedirectCodes,
|
|
7
|
-
} from './constants.mjs';
|
|
8
|
-
import { Cookies } from './cookies.mjs';
|
|
9
|
-
import { RequestError } from './errors.mjs';
|
|
10
|
-
import rekwest from './index.mjs';
|
|
11
|
-
import { mixin } from './mixin.mjs';
|
|
12
|
-
import {
|
|
13
|
-
admix,
|
|
14
|
-
maxRetryAfterError,
|
|
15
|
-
sameOrigin,
|
|
16
|
-
} from './utils.mjs';
|
|
17
|
-
|
|
18
|
-
const {
|
|
19
|
-
HTTP2_HEADER_LOCATION,
|
|
20
|
-
HTTP2_HEADER_RETRY_AFTER,
|
|
21
|
-
HTTP2_HEADER_SET_COOKIE,
|
|
22
|
-
HTTP2_METHOD_GET,
|
|
23
|
-
HTTP2_METHOD_HEAD,
|
|
24
|
-
HTTP2_METHOD_POST,
|
|
25
|
-
HTTP_STATUS_BAD_REQUEST,
|
|
26
|
-
HTTP_STATUS_FOUND,
|
|
27
|
-
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
28
|
-
HTTP_STATUS_SEE_OTHER,
|
|
29
|
-
} = http2.constants;
|
|
30
|
-
|
|
31
|
-
export const postflight = (req, res, options, { reject, resolve }) => {
|
|
32
|
-
const { cookies, credentials, follow, h2, redirect, url } = options;
|
|
33
|
-
let headers;
|
|
34
|
-
|
|
35
|
-
if (h2) {
|
|
36
|
-
headers = res;
|
|
37
|
-
res = req;
|
|
38
|
-
} else {
|
|
39
|
-
res.once('error', reject);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
admix(res, headers, options);
|
|
43
|
-
|
|
44
|
-
if (cookies !== false && res.headers[HTTP2_HEADER_SET_COOKIE]) {
|
|
45
|
-
if (Cookies.jar.has(url.origin)) {
|
|
46
|
-
const cookie = new Cookies(res.headers[HTTP2_HEADER_SET_COOKIE], options);
|
|
47
|
-
|
|
48
|
-
Cookies.jar.get(url.origin).forEach((val, key) => {
|
|
49
|
-
if (!cookie.has(key)) {
|
|
50
|
-
cookie.set(key, val);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
Cookies.jar.set(url.origin, cookie);
|
|
54
|
-
} else {
|
|
55
|
-
Cookies.jar.set(url.origin, new Cookies(res.headers[HTTP2_HEADER_SET_COOKIE], options));
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
Reflect.defineProperty(res, 'cookies', {
|
|
60
|
-
enumerable: true,
|
|
61
|
-
value: cookies !== false && Cookies.jar.has(url.origin)
|
|
62
|
-
? Cookies.jar.get(url.origin)
|
|
63
|
-
: void 0,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const { statusCode } = res;
|
|
67
|
-
|
|
68
|
-
if (follow && /3\d{2}/.test(statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
|
|
69
|
-
if (!requestRedirectCodes.includes(statusCode)) {
|
|
70
|
-
return res.emit('error', new RangeError(`Invalid status code: ${ statusCode }`));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (redirect === requestRedirect.error) {
|
|
74
|
-
return res.emit('error', new RequestError(`Unexpected redirect, redirect mode is set to '${ redirect }'.`));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (redirect === requestRedirect.follow) {
|
|
78
|
-
const location = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
|
|
79
|
-
|
|
80
|
-
if (!/^https?:/i.test(location.protocol)) {
|
|
81
|
-
return res.emit('error', new RequestError('URL scheme must be "http" or "https".'));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!sameOrigin(location, url)) {
|
|
85
|
-
if (credentials !== requestCredentials.include) {
|
|
86
|
-
options.credentials = requestCredentials.omit;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
options.h2 = false;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (statusCode !== HTTP_STATUS_SEE_OTHER && options.body?.pipe?.constructor === Function) {
|
|
93
|
-
return res.emit('error', new RequestError(`Unable to ${ redirect } redirect with streamable body.`));
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (([
|
|
97
|
-
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
98
|
-
HTTP_STATUS_FOUND,
|
|
99
|
-
].includes(statusCode) && options.method === HTTP2_METHOD_POST) || (statusCode === HTTP_STATUS_SEE_OTHER && ![
|
|
100
|
-
HTTP2_METHOD_GET,
|
|
101
|
-
HTTP2_METHOD_HEAD,
|
|
102
|
-
].includes(options.method))) {
|
|
103
|
-
for (const it of Object.keys(options.headers).filter((val) => /^content-/i.test(val))) {
|
|
104
|
-
Reflect.deleteProperty(options.headers, it);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
options.body = null;
|
|
108
|
-
options.method = HTTP2_METHOD_GET;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
options.follow--;
|
|
112
|
-
options.redirected = true;
|
|
113
|
-
options.url = location;
|
|
114
|
-
|
|
115
|
-
if (statusCode === HTTP_STATUS_MOVED_PERMANENTLY && res.headers[HTTP2_HEADER_RETRY_AFTER]) {
|
|
116
|
-
let interval = res.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
117
|
-
|
|
118
|
-
interval = Number(interval) * 1e3 || new Date(interval) - Date.now();
|
|
119
|
-
|
|
120
|
-
if (interval > options.maxRetryAfter) {
|
|
121
|
-
return res.emit('error', maxRetryAfterError(interval, { cause: mixin(res, options) }));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return setTimeoutPromise(interval).then(() => rekwest(options.url, options).then(resolve, reject));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return rekwest(options.url, options).then(resolve, reject);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (statusCode >= HTTP_STATUS_BAD_REQUEST) {
|
|
132
|
-
return reject(mixin(res, options));
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
resolve(mixin(res, options));
|
|
136
|
-
};
|
package/src/transfer.mjs
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import http from 'node:http';
|
|
2
|
-
import http2 from 'node:http2';
|
|
3
|
-
import https from 'node:https';
|
|
4
|
-
import { setTimeout as setTimeoutPromise } from 'node:timers/promises';
|
|
5
|
-
import { ackn } from './ackn.mjs';
|
|
6
|
-
import { RequestError } from './errors.mjs';
|
|
7
|
-
import { postflight } from './postflight.mjs';
|
|
8
|
-
import { preflight } from './preflight.mjs';
|
|
9
|
-
import { transform } from './transform.mjs';
|
|
10
|
-
import {
|
|
11
|
-
affix,
|
|
12
|
-
dispatch,
|
|
13
|
-
maxRetryAfterError,
|
|
14
|
-
} from './utils.mjs';
|
|
15
|
-
|
|
16
|
-
const {
|
|
17
|
-
HTTP2_HEADER_RETRY_AFTER,
|
|
18
|
-
} = http2.constants;
|
|
19
|
-
|
|
20
|
-
export const transfer = async (options, overact) => {
|
|
21
|
-
const { digest, redirected, thenable, url } = options;
|
|
22
|
-
|
|
23
|
-
if (options.follow === 0) {
|
|
24
|
-
throw new RequestError(`Maximum redirect reached at: ${ url.href }`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (url.protocol === 'https:') {
|
|
28
|
-
options = !options.h2 ? await ackn(options) : {
|
|
29
|
-
...options,
|
|
30
|
-
createConnection: null,
|
|
31
|
-
protocol: url.protocol,
|
|
32
|
-
};
|
|
33
|
-
} else if (Reflect.has(options, 'alpnProtocol')) {
|
|
34
|
-
for (const it of [
|
|
35
|
-
'alpnProtocol',
|
|
36
|
-
'createConnection',
|
|
37
|
-
'h2',
|
|
38
|
-
'protocol',
|
|
39
|
-
]) { Reflect.deleteProperty(options, it); }
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
options = await transform(preflight(options));
|
|
44
|
-
} catch (ex) {
|
|
45
|
-
options.createConnection?.().destroy();
|
|
46
|
-
throw ex;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const promise = new Promise((resolve, reject) => {
|
|
50
|
-
let client, req;
|
|
51
|
-
|
|
52
|
-
if (options.h2) {
|
|
53
|
-
client = http2.connect(url.origin, options);
|
|
54
|
-
req = client.request(options.headers, options);
|
|
55
|
-
} else {
|
|
56
|
-
const { request } = url.protocol === 'http:' ? http : https;
|
|
57
|
-
|
|
58
|
-
req = request(url, options);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
affix(client, req, options);
|
|
62
|
-
|
|
63
|
-
req.once('aborted', reject);
|
|
64
|
-
req.once('error', reject);
|
|
65
|
-
req.once('frameError', reject);
|
|
66
|
-
req.once('goaway', reject);
|
|
67
|
-
req.once('response', (res) => postflight(req, res, options, {
|
|
68
|
-
reject,
|
|
69
|
-
resolve,
|
|
70
|
-
}));
|
|
71
|
-
|
|
72
|
-
dispatch(options, req);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const res = await promise;
|
|
77
|
-
|
|
78
|
-
if (digest && !redirected) {
|
|
79
|
-
res.body = await res.body();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return res;
|
|
83
|
-
} catch (ex) {
|
|
84
|
-
const { maxRetryAfter, retry } = options;
|
|
85
|
-
|
|
86
|
-
if (retry?.attempts > 0) {
|
|
87
|
-
if (retry.errorCodes?.includes(ex.code) || retry.statusCodes?.includes(ex.statusCode)) {
|
|
88
|
-
let { interval } = retry;
|
|
89
|
-
|
|
90
|
-
if (retry.retryAfter && ex.headers?.[HTTP2_HEADER_RETRY_AFTER]) {
|
|
91
|
-
interval = ex.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
92
|
-
interval = Number(interval) * 1e3 || new Date(interval) - Date.now();
|
|
93
|
-
if (interval > maxRetryAfter) {
|
|
94
|
-
throw maxRetryAfterError(interval, { cause: ex });
|
|
95
|
-
}
|
|
96
|
-
} else {
|
|
97
|
-
interval = new Function('interval', `return Math.ceil(${ retry.backoffStrategy });`)(interval);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (interval < 0) {
|
|
101
|
-
interval = 0;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
retry.attempts--;
|
|
105
|
-
retry.interval = interval;
|
|
106
|
-
|
|
107
|
-
return setTimeoutPromise(interval).then(() => overact(url, options));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (digest && !redirected && ex.body) {
|
|
112
|
-
ex.body = await ex.body();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (!thenable) {
|
|
116
|
-
throw ex;
|
|
117
|
-
} else {
|
|
118
|
-
return ex;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
};
|