rekwest 2.3.6 → 3.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 +30 -20
- package/dist/errors.js +8 -4
- package/dist/helpers.js +124 -64
- package/dist/index.js +122 -66
- package/package.json +9 -8
- package/src/ackn.mjs +33 -33
- package/src/cookies.mjs +24 -24
- package/src/errors.mjs +4 -2
- package/src/file.mjs +40 -40
- package/src/formdata.mjs +224 -224
- package/src/helpers.mjs +116 -58
- package/src/index.mjs +110 -67
package/src/helpers.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from 'util';
|
|
11
11
|
import zlib from 'zlib';
|
|
12
12
|
import { Cookies } from './cookies.mjs';
|
|
13
|
+
import { TimeoutError } from './errors.mjs';
|
|
13
14
|
import { File } from './file.mjs';
|
|
14
15
|
import { FormData } from './formdata.mjs';
|
|
15
16
|
import {
|
|
@@ -31,6 +32,7 @@ const {
|
|
|
31
32
|
HTTP2_HEADER_METHOD,
|
|
32
33
|
HTTP2_HEADER_PATH,
|
|
33
34
|
HTTP2_HEADER_SCHEME,
|
|
35
|
+
HTTP2_HEADER_STATUS,
|
|
34
36
|
HTTP2_METHOD_GET,
|
|
35
37
|
HTTP2_METHOD_HEAD,
|
|
36
38
|
} = http2.constants;
|
|
@@ -42,6 +44,48 @@ const gunzip = promisify(zlib.gunzip);
|
|
|
42
44
|
const deflate = promisify(zlib.deflate);
|
|
43
45
|
const inflate = promisify(zlib.inflate);
|
|
44
46
|
|
|
47
|
+
export const admix = (res, headers, options) => {
|
|
48
|
+
const { h2 } = options;
|
|
49
|
+
|
|
50
|
+
if (h2) {
|
|
51
|
+
Reflect.defineProperty(res, 'headers', {
|
|
52
|
+
enumerable: true,
|
|
53
|
+
value: headers,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
Reflect.defineProperty(res, 'httpVersion', {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
value: `${ h2 + 1 }.0`,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
Reflect.defineProperty(res, 'statusCode', {
|
|
62
|
+
enumerable: true,
|
|
63
|
+
value: headers[HTTP2_HEADER_STATUS],
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Reflect.defineProperty(res, 'ok', {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
value: /^2\d{2}$/.test(res.statusCode),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
Reflect.defineProperty(res, 'redirected', {
|
|
73
|
+
enumerable: true,
|
|
74
|
+
value: !!options.redirected,
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const affix = (client, req, options) => {
|
|
79
|
+
req.once('end', () => client?.close());
|
|
80
|
+
req.once('timeout', () => req.destroy(new TimeoutError(`Timed out after ${ options.timeout } ms.`)));
|
|
81
|
+
req.once('trailers', (trailers) => {
|
|
82
|
+
Reflect.defineProperty(req, 'trailers', {
|
|
83
|
+
enumerable: true,
|
|
84
|
+
value: trailers,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
45
89
|
export const compress = (buf, encoding, { async = false } = {}) => {
|
|
46
90
|
encoding &&= encoding.match(/(?<encoding>\bbr\b|\bdeflate\b|\bgzip\b)/i)?.groups.encoding.toLowerCase();
|
|
47
91
|
const compressor = {
|
|
@@ -118,63 +162,7 @@ export const merge = (target = {}, ...rest) => {
|
|
|
118
162
|
return target;
|
|
119
163
|
};
|
|
120
164
|
|
|
121
|
-
export const
|
|
122
|
-
const url = options.url = new URL(options.url);
|
|
123
|
-
const { cookies, h2 = false, method = HTTP2_METHOD_GET, headers, redirected } = options;
|
|
124
|
-
|
|
125
|
-
if (h2) {
|
|
126
|
-
options.endStream = [
|
|
127
|
-
HTTP2_METHOD_GET,
|
|
128
|
-
HTTP2_METHOD_HEAD,
|
|
129
|
-
].includes(method);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (cookies !== false) {
|
|
133
|
-
let cookie = Cookies.jar.get(url.origin);
|
|
134
|
-
|
|
135
|
-
if (cookies === Object(cookies) && !redirected) {
|
|
136
|
-
if (cookie) {
|
|
137
|
-
new Cookies(cookies).forEach(function (val, key) {
|
|
138
|
-
this.set(key, val);
|
|
139
|
-
}, cookie);
|
|
140
|
-
} else {
|
|
141
|
-
cookie = new Cookies(cookies);
|
|
142
|
-
Cookies.jar.set(url.origin, cookie);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
options.headers = {
|
|
147
|
-
...cookie && { [HTTP2_HEADER_COOKIE]: cookie },
|
|
148
|
-
...headers,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
options.digest ??= true;
|
|
153
|
-
options.follow ??= 20;
|
|
154
|
-
options.h2 ??= h2;
|
|
155
|
-
options.headers = {
|
|
156
|
-
[HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
|
|
157
|
-
[HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, gzip, identity',
|
|
158
|
-
...Object.entries(options.headers ?? {})
|
|
159
|
-
.reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
|
|
160
|
-
...h2 && {
|
|
161
|
-
[HTTP2_HEADER_AUTHORITY]: url.host,
|
|
162
|
-
[HTTP2_HEADER_METHOD]: method,
|
|
163
|
-
[HTTP2_HEADER_PATH]: `${ url.pathname }${ url.search }`,
|
|
164
|
-
[HTTP2_HEADER_SCHEME]: url.protocol.replace(/\p{Punctuation}/gu, ''),
|
|
165
|
-
},
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
options.method ??= method;
|
|
169
|
-
options.parse ??= true;
|
|
170
|
-
options.redirect ??= 'follow';
|
|
171
|
-
options.redirected ??= false;
|
|
172
|
-
options.thenable ??= false;
|
|
173
|
-
|
|
174
|
-
return options;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
export const premix = (res, { digest = false, parse = false } = {}) => {
|
|
165
|
+
export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
178
166
|
if (!digest) {
|
|
179
167
|
Object.defineProperties(res, {
|
|
180
168
|
arrayBuffer: {
|
|
@@ -214,7 +202,7 @@ export const premix = (res, { digest = false, parse = false } = {}) => {
|
|
|
214
202
|
enumerable: true,
|
|
215
203
|
value: async function () {
|
|
216
204
|
if (this.bodyUsed) {
|
|
217
|
-
throw new TypeError('Response stream already read');
|
|
205
|
+
throw new TypeError('Response stream already read.');
|
|
218
206
|
}
|
|
219
207
|
|
|
220
208
|
let spool = [];
|
|
@@ -262,6 +250,76 @@ export const premix = (res, { digest = false, parse = false } = {}) => {
|
|
|
262
250
|
});
|
|
263
251
|
};
|
|
264
252
|
|
|
253
|
+
export const preflight = (options) => {
|
|
254
|
+
const url = options.url = new URL(options.url);
|
|
255
|
+
const { cookies, h2 = false, method = HTTP2_METHOD_GET, headers, redirected } = options;
|
|
256
|
+
|
|
257
|
+
if (h2) {
|
|
258
|
+
options.endStream = [
|
|
259
|
+
HTTP2_METHOD_GET,
|
|
260
|
+
HTTP2_METHOD_HEAD,
|
|
261
|
+
].includes(method);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (cookies !== false) {
|
|
265
|
+
let cookie = Cookies.jar.get(url.origin);
|
|
266
|
+
|
|
267
|
+
if (cookies === Object(cookies) && !redirected) {
|
|
268
|
+
if (cookie) {
|
|
269
|
+
new Cookies(cookies).forEach(function (val, key) {
|
|
270
|
+
this.set(key, val);
|
|
271
|
+
}, cookie);
|
|
272
|
+
} else {
|
|
273
|
+
cookie = new Cookies(cookies);
|
|
274
|
+
Cookies.jar.set(url.origin, cookie);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
options.headers = {
|
|
279
|
+
...cookie && { [HTTP2_HEADER_COOKIE]: cookie },
|
|
280
|
+
...headers,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
options.digest ??= true;
|
|
285
|
+
options.follow ??= 20;
|
|
286
|
+
options.h2 ??= h2;
|
|
287
|
+
options.headers = {
|
|
288
|
+
[HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
|
|
289
|
+
[HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, gzip, identity',
|
|
290
|
+
...Object.entries(options.headers ?? {})
|
|
291
|
+
.reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
|
|
292
|
+
...h2 && {
|
|
293
|
+
[HTTP2_HEADER_AUTHORITY]: url.host,
|
|
294
|
+
[HTTP2_HEADER_METHOD]: method,
|
|
295
|
+
[HTTP2_HEADER_PATH]: `${ url.pathname }${ url.search }`,
|
|
296
|
+
[HTTP2_HEADER_SCHEME]: url.protocol.replace(/\p{Punctuation}/gu, ''),
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
options.method ??= method;
|
|
301
|
+
options.parse ??= true;
|
|
302
|
+
options.redirect ??= redirects.follow;
|
|
303
|
+
|
|
304
|
+
if (!Object.values(redirects).includes(options.redirect)) {
|
|
305
|
+
options.createConnection?.().destroy();
|
|
306
|
+
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
|
|
307
|
+
options.redirect
|
|
308
|
+
}' is not a valid enum value.`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
options.redirected ??= false;
|
|
312
|
+
options.thenable ??= false;
|
|
313
|
+
|
|
314
|
+
return options;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
export const redirects = {
|
|
318
|
+
error: 'error',
|
|
319
|
+
follow: 'follow',
|
|
320
|
+
manual: 'manual',
|
|
321
|
+
};
|
|
322
|
+
|
|
265
323
|
export async function* tap(value) {
|
|
266
324
|
if (Reflect.has(value, Symbol.asyncIterator)) {
|
|
267
325
|
yield* value;
|
package/src/index.mjs
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import http2 from 'http2';
|
|
3
3
|
import https from 'https';
|
|
4
|
+
import { setTimeout as setTimeoutPromise } from 'timers/promises';
|
|
4
5
|
import { ackn } from './ackn.mjs';
|
|
5
6
|
import { Cookies } from './cookies.mjs';
|
|
6
7
|
import { RequestError } from './errors.mjs';
|
|
7
8
|
import {
|
|
9
|
+
admix,
|
|
10
|
+
affix,
|
|
8
11
|
dispatch,
|
|
9
12
|
merge,
|
|
13
|
+
mixin,
|
|
10
14
|
preflight,
|
|
11
|
-
|
|
15
|
+
redirects,
|
|
12
16
|
transform,
|
|
13
17
|
} from './helpers.mjs';
|
|
14
18
|
import { APPLICATION_OCTET_STREAM } from './mediatypes.mjs';
|
|
@@ -26,28 +30,58 @@ const {
|
|
|
26
30
|
HTTP2_HEADER_CONTENT_LENGTH,
|
|
27
31
|
HTTP2_HEADER_CONTENT_TYPE,
|
|
28
32
|
HTTP2_HEADER_LOCATION,
|
|
33
|
+
HTTP2_HEADER_RETRY_AFTER,
|
|
29
34
|
HTTP2_HEADER_SET_COOKIE,
|
|
30
|
-
HTTP2_HEADER_STATUS,
|
|
31
35
|
HTTP2_METHOD_GET,
|
|
32
36
|
HTTP2_METHOD_HEAD,
|
|
33
37
|
HTTP_STATUS_BAD_REQUEST,
|
|
38
|
+
HTTP_STATUS_MOVED_PERMANENTLY,
|
|
34
39
|
HTTP_STATUS_SEE_OTHER,
|
|
40
|
+
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
|
41
|
+
HTTP_STATUS_TOO_MANY_REQUESTS,
|
|
35
42
|
} = http2.constants;
|
|
36
43
|
|
|
44
|
+
const maxRetryAfter = Symbol('maxRetryAfter');
|
|
45
|
+
const maxRetryAfterError = (
|
|
46
|
+
interval,
|
|
47
|
+
options,
|
|
48
|
+
) => new RequestError(`Maximum '${ HTTP2_HEADER_RETRY_AFTER }' limit exceeded: ${ interval } ms.`, options);
|
|
49
|
+
let defaults = {
|
|
50
|
+
follow: 20,
|
|
51
|
+
get maxRetryAfter() {
|
|
52
|
+
return this[maxRetryAfter] ?? this.timeout;
|
|
53
|
+
},
|
|
54
|
+
set maxRetryAfter(value) {
|
|
55
|
+
this[maxRetryAfter] = value;
|
|
56
|
+
},
|
|
57
|
+
method: HTTP2_METHOD_GET,
|
|
58
|
+
retry: {
|
|
59
|
+
attempts: 0,
|
|
60
|
+
backoffStrategy: 'interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)',
|
|
61
|
+
interval: 1e3,
|
|
62
|
+
retryAfter: true,
|
|
63
|
+
statusCodes: [
|
|
64
|
+
HTTP_STATUS_TOO_MANY_REQUESTS,
|
|
65
|
+
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
timeout: 3e5,
|
|
69
|
+
};
|
|
70
|
+
|
|
37
71
|
export default async function rekwest(url, options = {}) {
|
|
38
72
|
url = options.url = new URL(url);
|
|
39
73
|
if (!options.redirected) {
|
|
40
|
-
options = merge(rekwest.defaults,
|
|
74
|
+
options = merge(rekwest.defaults, options);
|
|
41
75
|
}
|
|
42
76
|
|
|
43
77
|
if (options.body && [
|
|
44
78
|
HTTP2_METHOD_GET,
|
|
45
79
|
HTTP2_METHOD_HEAD,
|
|
46
80
|
].includes(options.method)) {
|
|
47
|
-
throw new TypeError(`Request with ${ HTTP2_METHOD_GET }/${ HTTP2_METHOD_HEAD } method cannot have body
|
|
81
|
+
throw new TypeError(`Request with ${ HTTP2_METHOD_GET }/${ HTTP2_METHOD_HEAD } method cannot have body.`);
|
|
48
82
|
}
|
|
49
83
|
|
|
50
|
-
if (
|
|
84
|
+
if (options.follow === 0) {
|
|
51
85
|
throw new RequestError(`Maximum redirect reached at: ${ url.href }`);
|
|
52
86
|
}
|
|
53
87
|
|
|
@@ -80,30 +114,22 @@ export default async function rekwest(url, options = {}) {
|
|
|
80
114
|
req = request(url, options);
|
|
81
115
|
}
|
|
82
116
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
117
|
+
affix(client, req, options);
|
|
118
|
+
req.once('error', reject);
|
|
119
|
+
req.once('frameError', reject);
|
|
120
|
+
req.once('goaway', reject);
|
|
121
|
+
req.once('response', (res) => {
|
|
122
|
+
let headers;
|
|
86
123
|
|
|
124
|
+
if (h2) {
|
|
125
|
+
headers = res;
|
|
87
126
|
res = req;
|
|
88
|
-
|
|
89
|
-
Reflect.defineProperty(res, 'headers', {
|
|
90
|
-
enumerable: true,
|
|
91
|
-
value: headers,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
Reflect.defineProperty(res, 'httpVersion', {
|
|
95
|
-
enumerable: true,
|
|
96
|
-
value: `${ h2 + 1 }.0`,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
Reflect.defineProperty(res, 'statusCode', {
|
|
100
|
-
enumerable: true,
|
|
101
|
-
value: headers[HTTP2_HEADER_STATUS],
|
|
102
|
-
});
|
|
103
127
|
} else {
|
|
104
|
-
res.
|
|
128
|
+
res.once('error', reject);
|
|
105
129
|
}
|
|
106
130
|
|
|
131
|
+
admix(res, headers, options);
|
|
132
|
+
|
|
107
133
|
if (cookies !== false && res.headers[HTTP2_HEADER_SET_COOKIE]) {
|
|
108
134
|
if (Cookies.jar.has(url.origin)) {
|
|
109
135
|
new Cookies(res.headers[HTTP2_HEADER_SET_COOKIE]).forEach(function (val, key) {
|
|
@@ -122,16 +148,16 @@ export default async function rekwest(url, options = {}) {
|
|
|
122
148
|
});
|
|
123
149
|
|
|
124
150
|
if (follow && /^3\d{2}$/.test(res.statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
|
|
125
|
-
if (redirect ===
|
|
126
|
-
res.emit('error', new RequestError(`Unexpected redirect, redirect mode is set to '${ redirect }'
|
|
151
|
+
if (redirect === redirects.error) {
|
|
152
|
+
res.emit('error', new RequestError(`Unexpected redirect, redirect mode is set to '${ redirect }'.`));
|
|
127
153
|
}
|
|
128
154
|
|
|
129
|
-
if (redirect ===
|
|
155
|
+
if (redirect === redirects.follow) {
|
|
130
156
|
options.url = new URL(res.headers[HTTP2_HEADER_LOCATION], url).href;
|
|
131
157
|
|
|
132
158
|
if (res.statusCode !== HTTP_STATUS_SEE_OTHER
|
|
133
159
|
&& body === Object(body) && body.pipe?.constructor === Function) {
|
|
134
|
-
res.emit('error', new RequestError(`Unable to ${ redirect } redirect with body as readable stream
|
|
160
|
+
res.emit('error', new RequestError(`Unable to ${ redirect } redirect with body as readable stream.`));
|
|
135
161
|
}
|
|
136
162
|
|
|
137
163
|
options.follow--;
|
|
@@ -144,39 +170,27 @@ export default async function rekwest(url, options = {}) {
|
|
|
144
170
|
|
|
145
171
|
Reflect.set(options, 'redirected', true);
|
|
146
172
|
|
|
173
|
+
if (res.statusCode === HTTP_STATUS_MOVED_PERMANENTLY && res.headers[HTTP2_HEADER_RETRY_AFTER]) {
|
|
174
|
+
let interval = res.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
175
|
+
|
|
176
|
+
interval = Number(interval) * 1000 || new Date(interval) - Date.now();
|
|
177
|
+
|
|
178
|
+
if (interval > options.maxRetryAfter) {
|
|
179
|
+
res.emit('error', maxRetryAfterError(interval, { cause: mixin(res, options) }));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return setTimeoutPromise(interval).then(() => rekwest(options.url, options).then(resolve, reject));
|
|
183
|
+
}
|
|
184
|
+
|
|
147
185
|
return rekwest(options.url, options).then(resolve, reject);
|
|
148
186
|
}
|
|
149
187
|
}
|
|
150
188
|
|
|
151
|
-
Reflect.defineProperty(res, 'ok', {
|
|
152
|
-
enumerable: true,
|
|
153
|
-
value: /^2\d{2}$/.test(res.statusCode),
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
Reflect.defineProperty(res, 'redirected', {
|
|
157
|
-
enumerable: true,
|
|
158
|
-
value: options.redirected,
|
|
159
|
-
});
|
|
160
|
-
|
|
161
189
|
if (res.statusCode >= HTTP_STATUS_BAD_REQUEST) {
|
|
162
|
-
return reject(
|
|
190
|
+
return reject(mixin(res, options));
|
|
163
191
|
}
|
|
164
192
|
|
|
165
|
-
resolve(
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
req.on('end', () => {
|
|
169
|
-
client?.close();
|
|
170
|
-
});
|
|
171
|
-
req.on('error', reject);
|
|
172
|
-
req.on('frameError', reject);
|
|
173
|
-
req.on('goaway', reject);
|
|
174
|
-
req.on('timeout', req.destroy);
|
|
175
|
-
req.on('trailers', (trailers) => {
|
|
176
|
-
Reflect.defineProperty(req, 'trailers', {
|
|
177
|
-
enumerable: true,
|
|
178
|
-
value: trailers,
|
|
179
|
-
});
|
|
193
|
+
resolve(mixin(res, options));
|
|
180
194
|
});
|
|
181
195
|
|
|
182
196
|
dispatch(req, { ...options, body });
|
|
@@ -191,6 +205,25 @@ export default async function rekwest(url, options = {}) {
|
|
|
191
205
|
|
|
192
206
|
return res;
|
|
193
207
|
} catch (ex) {
|
|
208
|
+
if (options.retry?.attempts && options.retry?.statusCodes.includes(ex.statusCode)) {
|
|
209
|
+
let { interval } = options.retry;
|
|
210
|
+
|
|
211
|
+
if (options.retry.retryAfter && ex.headers[HTTP2_HEADER_RETRY_AFTER]) {
|
|
212
|
+
interval = ex.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
213
|
+
interval = Number(interval) * 1000 || new Date(interval) - Date.now();
|
|
214
|
+
if (interval > options.maxRetryAfter) {
|
|
215
|
+
throw maxRetryAfterError(interval, { cause: ex });
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
interval = new Function('interval', `return Math.ceil(${ options.retry.backoffStrategy });`)(interval);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
options.retry.attempts--;
|
|
222
|
+
options.retry.interval = interval;
|
|
223
|
+
|
|
224
|
+
return setTimeoutPromise(interval).then(() => rekwest(url, options));
|
|
225
|
+
}
|
|
226
|
+
|
|
194
227
|
if (digest && !redirected && ex.body) {
|
|
195
228
|
ex.body = await ex.body();
|
|
196
229
|
}
|
|
@@ -211,28 +244,38 @@ Reflect.defineProperty(rekwest, 'stream', {
|
|
|
211
244
|
...merge(rekwest.defaults, {
|
|
212
245
|
headers: { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_OCTET_STREAM },
|
|
213
246
|
}, options),
|
|
247
|
+
redirect: redirects.manual,
|
|
214
248
|
});
|
|
215
249
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
req.on('end', () => {
|
|
221
|
-
client.close();
|
|
222
|
-
});
|
|
250
|
+
const { h2, url: { protocol } } = options;
|
|
251
|
+
const { request } = (protocol === 'http:' ? http : https);
|
|
252
|
+
let client, req;
|
|
223
253
|
|
|
224
|
-
|
|
254
|
+
if (h2) {
|
|
255
|
+
client = http2.connect(url.origin, options);
|
|
256
|
+
req = client.request(options.headers, options);
|
|
257
|
+
} else {
|
|
258
|
+
req = request(options.url, options);
|
|
225
259
|
}
|
|
226
260
|
|
|
227
|
-
|
|
228
|
-
|
|
261
|
+
affix(client, req, options);
|
|
262
|
+
req.once('response', (res) => {
|
|
263
|
+
let headers;
|
|
264
|
+
|
|
265
|
+
if (h2) {
|
|
266
|
+
headers = res;
|
|
267
|
+
res = req;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
admix(res, headers, options);
|
|
271
|
+
});
|
|
229
272
|
|
|
230
|
-
return
|
|
273
|
+
return req;
|
|
231
274
|
},
|
|
232
275
|
});
|
|
233
276
|
|
|
234
277
|
Reflect.defineProperty(rekwest, 'defaults', {
|
|
235
278
|
enumerable: true,
|
|
236
|
-
|
|
237
|
-
|
|
279
|
+
get() { return defaults; },
|
|
280
|
+
set(value) { defaults = merge(defaults, value); },
|
|
238
281
|
});
|