got 11.0.0-beta.1 → 11.0.3
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/dist/source/as-promise/core.d.ts +4 -5
- package/dist/source/as-promise/core.js +28 -27
- package/dist/source/as-promise/index.js +40 -20
- package/dist/source/as-promise/types.d.ts +4 -3
- package/dist/source/as-promise/types.js +3 -2
- package/dist/source/core/index.d.ts +29 -10
- package/dist/source/core/index.js +198 -148
- package/dist/source/core/utils/get-body-size.d.ts +3 -6
- package/dist/source/core/utils/get-body-size.js +1 -2
- package/dist/source/core/utils/options-to-url.js +1 -1
- package/dist/source/core/utils/timed-out.js +4 -6
- package/dist/source/core/utils/weakable-map.d.ts +8 -0
- package/dist/source/core/utils/weakable-map.js +29 -0
- package/dist/source/create.js +8 -6
- package/dist/source/index.js +2 -1
- package/dist/source/types.d.ts +23 -20
- package/package.json +9 -17
- package/readme.md +74 -12
|
@@ -22,6 +22,7 @@ const proxy_events_1 = require("./utils/proxy-events");
|
|
|
22
22
|
const timed_out_1 = require("./utils/timed-out");
|
|
23
23
|
const url_to_options_1 = require("./utils/url-to-options");
|
|
24
24
|
const options_to_url_1 = require("./utils/options-to-url");
|
|
25
|
+
const weakable_map_1 = require("./utils/weakable-map");
|
|
25
26
|
const kRequest = Symbol('request');
|
|
26
27
|
const kResponse = Symbol('response');
|
|
27
28
|
const kResponseSize = Symbol('responseSize');
|
|
@@ -33,6 +34,10 @@ const kUnproxyEvents = Symbol('unproxyEvents');
|
|
|
33
34
|
const kIsFromCache = Symbol('isFromCache');
|
|
34
35
|
const kCancelTimeouts = Symbol('cancelTimeouts');
|
|
35
36
|
const kStartedReading = Symbol('startedReading');
|
|
37
|
+
const kStopReading = Symbol('stopReading');
|
|
38
|
+
const kTriggerRead = Symbol('triggerRead');
|
|
39
|
+
const kBody = Symbol('body');
|
|
40
|
+
const kJobs = Symbol('jobs');
|
|
36
41
|
exports.kIsNormalizedAlready = Symbol('isNormalizedAlready');
|
|
37
42
|
const supportsBrotli = is_1.default.string(process.versions.brotli);
|
|
38
43
|
exports.withoutBody = new Set(['GET', 'HEAD']);
|
|
@@ -49,26 +54,7 @@ function validateSearchParameters(searchParameters) {
|
|
|
49
54
|
function isClientRequest(clientRequest) {
|
|
50
55
|
return is_1.default.object(clientRequest) && !('statusCode' in clientRequest);
|
|
51
56
|
}
|
|
52
|
-
const
|
|
53
|
-
// TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed
|
|
54
|
-
Object.assign(options, url_to_options_1.default(url));
|
|
55
|
-
// `http-cache-semantics` checks this
|
|
56
|
-
delete options.url;
|
|
57
|
-
// TODO: `cacheable-request` is incorrectly typed
|
|
58
|
-
const cacheRequest = options.cacheableRequest(options, resolve);
|
|
59
|
-
// Restore options
|
|
60
|
-
options.url = url;
|
|
61
|
-
cacheRequest.once('error', (error) => {
|
|
62
|
-
if (error instanceof CacheableRequest.RequestError) {
|
|
63
|
-
// TODO: `options` should be `normalizedOptions`
|
|
64
|
-
reject(new RequestError(error.message, error, options));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
// TODO: `options` should be `normalizedOptions`
|
|
68
|
-
reject(new CacheError(error, options));
|
|
69
|
-
});
|
|
70
|
-
cacheRequest.once('request', resolve);
|
|
71
|
-
});
|
|
57
|
+
const cacheableStore = new weakable_map_1.default();
|
|
72
58
|
const waitForOpenFile = async (file) => new Promise((resolve, reject) => {
|
|
73
59
|
const onError = (error) => {
|
|
74
60
|
reject(error);
|
|
@@ -109,36 +95,34 @@ const setNonEnumerableProperties = (sources, to) => {
|
|
|
109
95
|
Object.defineProperties(to, properties);
|
|
110
96
|
};
|
|
111
97
|
class RequestError extends Error {
|
|
112
|
-
constructor(message, error,
|
|
98
|
+
constructor(message, error, self) {
|
|
113
99
|
var _a;
|
|
114
100
|
super(message);
|
|
115
101
|
Error.captureStackTrace(this, this.constructor);
|
|
116
102
|
this.name = 'RequestError';
|
|
117
103
|
this.code = error.code;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// Ref: https://github.com/microsoft/TypeScript/issues/34972
|
|
121
|
-
enumerable: false,
|
|
122
|
-
value: options
|
|
123
|
-
});
|
|
124
|
-
if (requestOrResponse instanceof http_1.IncomingMessage) {
|
|
125
|
-
Object.defineProperty(this, 'response', {
|
|
104
|
+
if (self instanceof Request) {
|
|
105
|
+
Object.defineProperty(this, 'request', {
|
|
126
106
|
enumerable: false,
|
|
127
|
-
value:
|
|
107
|
+
value: self
|
|
128
108
|
});
|
|
129
|
-
Object.defineProperty(this, '
|
|
109
|
+
Object.defineProperty(this, 'response', {
|
|
130
110
|
enumerable: false,
|
|
131
|
-
value:
|
|
111
|
+
value: self[kResponse]
|
|
132
112
|
});
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
113
|
+
Object.defineProperty(this, 'options', {
|
|
114
|
+
// This fails because of TS 3.7.2 useDefineForClassFields
|
|
115
|
+
// Ref: https://github.com/microsoft/TypeScript/issues/34972
|
|
136
116
|
enumerable: false,
|
|
137
|
-
value:
|
|
117
|
+
value: self.options
|
|
138
118
|
});
|
|
139
|
-
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
Object.defineProperty(this, 'options', {
|
|
122
|
+
// This fails because of TS 3.7.2 useDefineForClassFields
|
|
123
|
+
// Ref: https://github.com/microsoft/TypeScript/issues/34972
|
|
140
124
|
enumerable: false,
|
|
141
|
-
value:
|
|
125
|
+
value: self
|
|
142
126
|
});
|
|
143
127
|
}
|
|
144
128
|
this.timings = (_a = this.request) === null || _a === void 0 ? void 0 : _a.timings;
|
|
@@ -157,44 +141,36 @@ class RequestError extends Error {
|
|
|
157
141
|
}
|
|
158
142
|
exports.RequestError = RequestError;
|
|
159
143
|
class MaxRedirectsError extends RequestError {
|
|
160
|
-
constructor(
|
|
161
|
-
super(`Redirected ${maxRedirects} times. Aborting.`, {},
|
|
144
|
+
constructor(request) {
|
|
145
|
+
super(`Redirected ${request.options.maxRedirects} times. Aborting.`, {}, request);
|
|
162
146
|
this.name = 'MaxRedirectsError';
|
|
163
|
-
Object.defineProperty(this, 'response', {
|
|
164
|
-
enumerable: false,
|
|
165
|
-
value: response
|
|
166
|
-
});
|
|
167
147
|
}
|
|
168
148
|
}
|
|
169
149
|
exports.MaxRedirectsError = MaxRedirectsError;
|
|
170
150
|
class HTTPError extends RequestError {
|
|
171
|
-
constructor(response
|
|
172
|
-
super(`Response code ${response.statusCode} (${response.statusMessage})`, {},
|
|
151
|
+
constructor(response) {
|
|
152
|
+
super(`Response code ${response.statusCode} (${response.statusMessage})`, {}, response.request);
|
|
173
153
|
this.name = 'HTTPError';
|
|
174
|
-
Object.defineProperty(this, 'response', {
|
|
175
|
-
enumerable: false,
|
|
176
|
-
value: response
|
|
177
|
-
});
|
|
178
154
|
}
|
|
179
155
|
}
|
|
180
156
|
exports.HTTPError = HTTPError;
|
|
181
157
|
class CacheError extends RequestError {
|
|
182
|
-
constructor(error,
|
|
183
|
-
super(error.message, error,
|
|
158
|
+
constructor(error, request) {
|
|
159
|
+
super(error.message, error, request);
|
|
184
160
|
this.name = 'CacheError';
|
|
185
161
|
}
|
|
186
162
|
}
|
|
187
163
|
exports.CacheError = CacheError;
|
|
188
164
|
class UploadError extends RequestError {
|
|
189
|
-
constructor(error,
|
|
190
|
-
super(error.message, error,
|
|
165
|
+
constructor(error, request) {
|
|
166
|
+
super(error.message, error, request);
|
|
191
167
|
this.name = 'UploadError';
|
|
192
168
|
}
|
|
193
169
|
}
|
|
194
170
|
exports.UploadError = UploadError;
|
|
195
171
|
class TimeoutError extends RequestError {
|
|
196
|
-
constructor(error, timings,
|
|
197
|
-
super(error.message, error,
|
|
172
|
+
constructor(error, timings, request) {
|
|
173
|
+
super(error.message, error, request);
|
|
198
174
|
this.name = 'TimeoutError';
|
|
199
175
|
this.event = error.event;
|
|
200
176
|
this.timings = timings;
|
|
@@ -202,8 +178,8 @@ class TimeoutError extends RequestError {
|
|
|
202
178
|
}
|
|
203
179
|
exports.TimeoutError = TimeoutError;
|
|
204
180
|
class ReadError extends RequestError {
|
|
205
|
-
constructor(error,
|
|
206
|
-
super(error.message, error,
|
|
181
|
+
constructor(error, request) {
|
|
182
|
+
super(error.message, error, request);
|
|
207
183
|
this.name = 'ReadError';
|
|
208
184
|
}
|
|
209
185
|
}
|
|
@@ -232,10 +208,12 @@ class Request extends stream_1.Duplex {
|
|
|
232
208
|
});
|
|
233
209
|
this[kDownloadedSize] = 0;
|
|
234
210
|
this[kUploadedSize] = 0;
|
|
235
|
-
this.
|
|
211
|
+
this.requestInitialized = false;
|
|
236
212
|
this[kServerResponsesPiped] = new Set();
|
|
237
213
|
this.redirects = [];
|
|
238
|
-
this
|
|
214
|
+
this[kStopReading] = false;
|
|
215
|
+
this[kTriggerRead] = false;
|
|
216
|
+
this[kJobs] = [];
|
|
239
217
|
// TODO: Remove this when targeting Node.js >= 12
|
|
240
218
|
this._progressCallbacks = [];
|
|
241
219
|
const unlockWrite = () => this._unlockWrite();
|
|
@@ -265,6 +243,7 @@ class Request extends stream_1.Duplex {
|
|
|
265
243
|
this._lockWrite();
|
|
266
244
|
}
|
|
267
245
|
(async (nonNormalizedOptions) => {
|
|
246
|
+
var _a;
|
|
268
247
|
try {
|
|
269
248
|
if (nonNormalizedOptions.body instanceof fs_1.ReadStream) {
|
|
270
249
|
await waitForOpenFile(nonNormalizedOptions.body);
|
|
@@ -284,8 +263,15 @@ class Request extends stream_1.Duplex {
|
|
|
284
263
|
decodeURI(this.requestUrl);
|
|
285
264
|
await this._finalizeBody();
|
|
286
265
|
await this._makeRequest();
|
|
287
|
-
this.
|
|
288
|
-
|
|
266
|
+
if (this.destroyed) {
|
|
267
|
+
(_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.abort();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// Queued writes etc.
|
|
271
|
+
for (const job of this[kJobs]) {
|
|
272
|
+
job();
|
|
273
|
+
}
|
|
274
|
+
this.requestInitialized = true;
|
|
289
275
|
}
|
|
290
276
|
catch (error) {
|
|
291
277
|
if (error instanceof RequestError) {
|
|
@@ -299,6 +285,8 @@ class Request extends stream_1.Duplex {
|
|
|
299
285
|
static normalizeArguments(url, options, defaults) {
|
|
300
286
|
var _a, _b, _c, _d;
|
|
301
287
|
const rawOptions = options;
|
|
288
|
+
const searchParameters = options === null || options === void 0 ? void 0 : options.searchParams;
|
|
289
|
+
const hooks = options === null || options === void 0 ? void 0 : options.hooks;
|
|
302
290
|
if (is_1.default.object(url) && !is_1.default.urlInstance(url)) {
|
|
303
291
|
options = { ...defaults, ...url, ...options };
|
|
304
292
|
}
|
|
@@ -311,6 +299,20 @@ class Request extends stream_1.Duplex {
|
|
|
311
299
|
options.url = url;
|
|
312
300
|
}
|
|
313
301
|
}
|
|
302
|
+
// Prevent duplicating default search params & hooks
|
|
303
|
+
if (searchParameters === undefined) {
|
|
304
|
+
delete options.searchParams;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
options.searchParams = searchParameters;
|
|
308
|
+
}
|
|
309
|
+
if (hooks === undefined) {
|
|
310
|
+
delete options.hooks;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
options.hooks = hooks;
|
|
314
|
+
}
|
|
315
|
+
// Setting options to `undefined` turns off its functionalities
|
|
314
316
|
if (rawOptions && defaults) {
|
|
315
317
|
for (const key in rawOptions) {
|
|
316
318
|
// @ts-ignore Dear TypeScript, all object keys are strings (or symbols which are NOT enumerable).
|
|
@@ -354,8 +356,11 @@ class Request extends stream_1.Duplex {
|
|
|
354
356
|
if (is_1.default.undefined(options.headers)) {
|
|
355
357
|
options.headers = {};
|
|
356
358
|
}
|
|
359
|
+
else if (options.headers === (defaults === null || defaults === void 0 ? void 0 : defaults.headers)) {
|
|
360
|
+
options.headers = { ...options.headers };
|
|
361
|
+
}
|
|
357
362
|
else {
|
|
358
|
-
options.headers = lowercaseKeys({ ...(
|
|
363
|
+
options.headers = lowercaseKeys({ ...(defaults === null || defaults === void 0 ? void 0 : defaults.headers), ...options.headers });
|
|
359
364
|
}
|
|
360
365
|
// Disallow legacy `url.Url`
|
|
361
366
|
if ('slashes' in options) {
|
|
@@ -365,6 +370,23 @@ class Request extends stream_1.Duplex {
|
|
|
365
370
|
if ('auth' in options) {
|
|
366
371
|
throw new TypeError('Parameter `auth` is deprecated. Use `username` / `password` instead.');
|
|
367
372
|
}
|
|
373
|
+
// `options.searchParams`
|
|
374
|
+
if (options.searchParams) {
|
|
375
|
+
if (!is_1.default.string(options.searchParams) && !(options.searchParams instanceof url_1.URLSearchParams)) {
|
|
376
|
+
validateSearchParameters(options.searchParams);
|
|
377
|
+
}
|
|
378
|
+
options.searchParams = new url_1.URLSearchParams(options.searchParams);
|
|
379
|
+
// `normalizeArguments()` is also used to merge options
|
|
380
|
+
(_a = defaults === null || defaults === void 0 ? void 0 : defaults.searchParams) === null || _a === void 0 ? void 0 : _a.forEach((value, key) => {
|
|
381
|
+
options.searchParams.append(key, value);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
options.searchParams = defaults === null || defaults === void 0 ? void 0 : defaults.searchParams;
|
|
386
|
+
}
|
|
387
|
+
// `options.username` & `options.password`
|
|
388
|
+
options.username = (_b = options.username) !== null && _b !== void 0 ? _b : '';
|
|
389
|
+
options.password = (_c = options.password) !== null && _c !== void 0 ? _c : '';
|
|
368
390
|
// `options.prefixUrl` & `options.url`
|
|
369
391
|
if (options.prefixUrl) {
|
|
370
392
|
options.prefixUrl = options.prefixUrl.toString();
|
|
@@ -398,65 +420,52 @@ class Request extends stream_1.Duplex {
|
|
|
398
420
|
},
|
|
399
421
|
get: () => prefixUrl
|
|
400
422
|
});
|
|
401
|
-
//
|
|
423
|
+
// Support UNIX sockets
|
|
402
424
|
let { protocol } = options.url;
|
|
403
425
|
if (protocol === 'unix:') {
|
|
404
426
|
protocol = 'http:';
|
|
405
427
|
options.url = new url_1.URL(`http://unix${options.url.pathname}${options.url.search}`);
|
|
406
428
|
}
|
|
429
|
+
// Set search params
|
|
430
|
+
if (options.searchParams) {
|
|
431
|
+
options.url.search = options.searchParams.toString();
|
|
432
|
+
}
|
|
433
|
+
// Trigger search params normalization
|
|
407
434
|
if (options.url.search) {
|
|
408
435
|
const triggerSearchParameters = '_GOT_INTERNAL_TRIGGER_NORMALIZATION';
|
|
409
436
|
options.url.searchParams.append(triggerSearchParameters, '');
|
|
410
437
|
options.url.searchParams.delete(triggerSearchParameters);
|
|
411
438
|
}
|
|
439
|
+
// Protocol check
|
|
412
440
|
if (protocol !== 'http:' && protocol !== 'https:') {
|
|
413
441
|
throw new UnsupportedProtocolError(options);
|
|
414
442
|
}
|
|
415
|
-
|
|
416
|
-
// `options.username` & `options.password`
|
|
417
|
-
options.username = (_b = options.username, (_b !== null && _b !== void 0 ? _b : ''));
|
|
418
|
-
options.password = (_c = options.password, (_c !== null && _c !== void 0 ? _c : ''));
|
|
419
|
-
if (options.url) {
|
|
443
|
+
// Update `username` & `password`
|
|
420
444
|
options.url.username = options.username;
|
|
421
445
|
options.url.password = options.password;
|
|
422
446
|
}
|
|
423
447
|
// `options.cookieJar`
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
448
|
+
const { cookieJar } = options;
|
|
449
|
+
if (cookieJar) {
|
|
450
|
+
let { setCookie, getCookieString } = cookieJar;
|
|
451
|
+
is_1.assert.function_(setCookie);
|
|
452
|
+
is_1.assert.function_(getCookieString);
|
|
453
|
+
/* istanbul ignore next: Horrible `tough-cookie` v3 check */
|
|
427
454
|
if (setCookie.length === 4 && getCookieString.length === 0) {
|
|
428
455
|
setCookie = util_1.promisify(setCookie.bind(options.cookieJar));
|
|
429
456
|
getCookieString = util_1.promisify(getCookieString.bind(options.cookieJar));
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
else if (getCookieString.length !== 1) {
|
|
435
|
-
throw new TypeError('`options.cookieJar.getCookieString` needs to be an async function with 1 argument');
|
|
436
|
-
}
|
|
437
|
-
options.cookieJar = { setCookie, getCookieString };
|
|
438
|
-
}
|
|
439
|
-
// `options.searchParams`
|
|
440
|
-
if (options.searchParams) {
|
|
441
|
-
if (!is_1.default.string(options.searchParams) && !(options.searchParams instanceof url_1.URLSearchParams)) {
|
|
442
|
-
validateSearchParameters(options.searchParams);
|
|
443
|
-
}
|
|
444
|
-
options.searchParams = new url_1.URLSearchParams(options.searchParams);
|
|
445
|
-
// `normalizeArguments()` is also used to merge options
|
|
446
|
-
const defaultsAsOptions = defaults;
|
|
447
|
-
if (defaultsAsOptions && defaultsAsOptions.searchParams instanceof url_1.URLSearchParams) {
|
|
448
|
-
defaultsAsOptions.searchParams.forEach((value, key) => {
|
|
449
|
-
options.searchParams.append(key, value);
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
if (options.url) {
|
|
453
|
-
options.url.search = options.searchParams.toString();
|
|
457
|
+
options.cookieJar = {
|
|
458
|
+
setCookie,
|
|
459
|
+
getCookieString
|
|
460
|
+
};
|
|
454
461
|
}
|
|
455
462
|
}
|
|
456
463
|
// `options.cache`
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
464
|
+
const { cache } = options;
|
|
465
|
+
if (cache) {
|
|
466
|
+
if (!cacheableStore.has(cache)) {
|
|
467
|
+
cacheableStore.set(cache, new CacheableRequest(((requestOptions, handler) => requestOptions[kRequest](requestOptions, handler)), cache));
|
|
468
|
+
}
|
|
460
469
|
}
|
|
461
470
|
// `options.dnsCache`
|
|
462
471
|
if (options.dnsCache === true) {
|
|
@@ -469,7 +478,7 @@ class Request extends stream_1.Duplex {
|
|
|
469
478
|
if (is_1.default.number(options.timeout)) {
|
|
470
479
|
options.timeout = { request: options.timeout };
|
|
471
480
|
}
|
|
472
|
-
else if (defaults) {
|
|
481
|
+
else if (defaults && options.timeout !== defaults.timeout) {
|
|
473
482
|
options.timeout = {
|
|
474
483
|
...defaults.timeout,
|
|
475
484
|
...options.timeout
|
|
@@ -521,7 +530,7 @@ class Request extends stream_1.Duplex {
|
|
|
521
530
|
}
|
|
522
531
|
}
|
|
523
532
|
}
|
|
524
|
-
options.maxRedirects = (_d = options.maxRedirects
|
|
533
|
+
options.maxRedirects = (_d = options.maxRedirects) !== null && _d !== void 0 ? _d : 0;
|
|
525
534
|
// Set non-enumerable properties
|
|
526
535
|
setNonEnumerableProperties([defaults, options], options);
|
|
527
536
|
return options;
|
|
@@ -571,20 +580,21 @@ class Request extends stream_1.Duplex {
|
|
|
571
580
|
if (is_form_data_1.default(options.body) && noContentType) {
|
|
572
581
|
headers['content-type'] = `multipart/form-data; boundary=${options.body.getBoundary()}`;
|
|
573
582
|
}
|
|
583
|
+
this[kBody] = options.body;
|
|
574
584
|
}
|
|
575
585
|
else if (isForm) {
|
|
576
586
|
if (noContentType) {
|
|
577
587
|
headers['content-type'] = 'application/x-www-form-urlencoded';
|
|
578
588
|
}
|
|
579
|
-
|
|
589
|
+
this[kBody] = (new url_1.URLSearchParams(options.form)).toString();
|
|
580
590
|
}
|
|
581
591
|
else {
|
|
582
592
|
if (noContentType) {
|
|
583
593
|
headers['content-type'] = 'application/json';
|
|
584
594
|
}
|
|
585
|
-
|
|
595
|
+
this[kBody] = JSON.stringify(options.json);
|
|
586
596
|
}
|
|
587
|
-
const uploadBodySize = await get_body_size_1.default(options);
|
|
597
|
+
const uploadBodySize = await get_body_size_1.default(this[kBody], options.headers);
|
|
588
598
|
// See https://tools.ietf.org/html/rfc7230#section-3.3.2
|
|
589
599
|
// A user agent SHOULD send a Content-Length in a request message when
|
|
590
600
|
// no Transfer-Encoding is sent and the request method defines a meaning
|
|
@@ -617,7 +627,7 @@ class Request extends stream_1.Duplex {
|
|
|
617
627
|
}
|
|
618
628
|
const statusCode = response.statusCode;
|
|
619
629
|
const typedResponse = response;
|
|
620
|
-
typedResponse.statusMessage = typedResponse.statusMessage
|
|
630
|
+
typedResponse.statusMessage = typedResponse.statusMessage ? typedResponse.statusMessage : http.STATUS_CODES[statusCode];
|
|
621
631
|
typedResponse.url = options.url.toString();
|
|
622
632
|
typedResponse.requestUrl = this.requestUrl;
|
|
623
633
|
typedResponse.redirectUrls = this.redirects;
|
|
@@ -631,8 +641,17 @@ class Request extends stream_1.Duplex {
|
|
|
631
641
|
this[kResponseSize] = this[kDownloadedSize];
|
|
632
642
|
this.emit('downloadProgress', this.downloadProgress);
|
|
633
643
|
});
|
|
634
|
-
response.
|
|
635
|
-
this._beforeError(new ReadError(error,
|
|
644
|
+
response.once('error', (error) => {
|
|
645
|
+
this._beforeError(new ReadError(error, this));
|
|
646
|
+
});
|
|
647
|
+
response.once('aborted', () => {
|
|
648
|
+
if (this.aborted) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
this._beforeError(new ReadError({
|
|
652
|
+
name: 'Error',
|
|
653
|
+
message: 'The server aborted the pending request'
|
|
654
|
+
}, this));
|
|
636
655
|
});
|
|
637
656
|
this.emit('downloadProgress', this.downloadProgress);
|
|
638
657
|
const rawCookies = response.headers['set-cookie'];
|
|
@@ -676,7 +695,7 @@ class Request extends stream_1.Duplex {
|
|
|
676
695
|
}
|
|
677
696
|
}
|
|
678
697
|
if (this.redirects.length >= options.maxRedirects) {
|
|
679
|
-
this._beforeError(new MaxRedirectsError(
|
|
698
|
+
this._beforeError(new MaxRedirectsError(this));
|
|
680
699
|
return;
|
|
681
700
|
}
|
|
682
701
|
try {
|
|
@@ -716,14 +735,13 @@ class Request extends stream_1.Duplex {
|
|
|
716
735
|
const limitStatusCode = options.followRedirect ? 299 : 399;
|
|
717
736
|
const isOk = (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304;
|
|
718
737
|
if (options.throwHttpErrors && !isOk) {
|
|
719
|
-
await this._beforeError(new HTTPError(typedResponse
|
|
738
|
+
await this._beforeError(new HTTPError(typedResponse));
|
|
720
739
|
if (this.destroyed) {
|
|
721
740
|
return;
|
|
722
741
|
}
|
|
723
742
|
}
|
|
724
|
-
// We need to call `_read()` only when the Request stream is flowing
|
|
725
743
|
response.on('readable', () => {
|
|
726
|
-
if (this
|
|
744
|
+
if (this[kTriggerRead]) {
|
|
727
745
|
this._read();
|
|
728
746
|
}
|
|
729
747
|
});
|
|
@@ -762,10 +780,10 @@ class Request extends stream_1.Duplex {
|
|
|
762
780
|
});
|
|
763
781
|
request.once('error', (error) => {
|
|
764
782
|
if (error instanceof timed_out_1.TimeoutError) {
|
|
765
|
-
error = new TimeoutError(error, this.timings,
|
|
783
|
+
error = new TimeoutError(error, this.timings, this);
|
|
766
784
|
}
|
|
767
785
|
else {
|
|
768
|
-
error = new RequestError(error.message, error,
|
|
786
|
+
error = new RequestError(error.message, error, this);
|
|
769
787
|
}
|
|
770
788
|
this._beforeError(error);
|
|
771
789
|
});
|
|
@@ -773,20 +791,21 @@ class Request extends stream_1.Duplex {
|
|
|
773
791
|
this[kRequest] = request;
|
|
774
792
|
this.emit('uploadProgress', this.uploadProgress);
|
|
775
793
|
// Send body
|
|
794
|
+
const body = this[kBody];
|
|
776
795
|
const currentRequest = this.redirects.length === 0 ? this : request;
|
|
777
|
-
if (is_1.default.nodeStream(
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
this._beforeError(new UploadError(error,
|
|
796
|
+
if (is_1.default.nodeStream(body)) {
|
|
797
|
+
body.pipe(currentRequest);
|
|
798
|
+
body.once('error', (error) => {
|
|
799
|
+
this._beforeError(new UploadError(error, this));
|
|
781
800
|
});
|
|
782
|
-
|
|
801
|
+
body.once('end', () => {
|
|
783
802
|
delete options.body;
|
|
784
803
|
});
|
|
785
804
|
}
|
|
786
805
|
else {
|
|
787
806
|
this._unlockWrite();
|
|
788
|
-
if (!is_1.default.undefined(
|
|
789
|
-
this._writeRequest(
|
|
807
|
+
if (!is_1.default.undefined(body)) {
|
|
808
|
+
this._writeRequest(body, null, () => { });
|
|
790
809
|
currentRequest.end();
|
|
791
810
|
this._lockWrite();
|
|
792
811
|
}
|
|
@@ -797,8 +816,28 @@ class Request extends stream_1.Duplex {
|
|
|
797
816
|
}
|
|
798
817
|
this.emit('request', request);
|
|
799
818
|
}
|
|
819
|
+
async _createCacheableRequest(url, options) {
|
|
820
|
+
return new Promise((resolve, reject) => {
|
|
821
|
+
// TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed
|
|
822
|
+
Object.assign(options, url_to_options_1.default(url));
|
|
823
|
+
// `http-cache-semantics` checks this
|
|
824
|
+
delete options.url;
|
|
825
|
+
// This is ugly
|
|
826
|
+
const cacheRequest = cacheableStore.get(options.cache)(options, resolve);
|
|
827
|
+
// Restore options
|
|
828
|
+
options.url = url;
|
|
829
|
+
cacheRequest.once('error', (error) => {
|
|
830
|
+
if (error instanceof CacheableRequest.CacheError) {
|
|
831
|
+
reject(new CacheError(error, this));
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
reject(error);
|
|
835
|
+
});
|
|
836
|
+
cacheRequest.once('request', resolve);
|
|
837
|
+
});
|
|
838
|
+
}
|
|
800
839
|
async _makeRequest() {
|
|
801
|
-
var _a
|
|
840
|
+
var _a;
|
|
802
841
|
const { options } = this;
|
|
803
842
|
const { url, headers, request, agent, timeout } = options;
|
|
804
843
|
for (const key in headers) {
|
|
@@ -835,7 +874,7 @@ class Request extends stream_1.Duplex {
|
|
|
835
874
|
// UNIX sockets
|
|
836
875
|
if (url.hostname === 'unix') {
|
|
837
876
|
const matches = /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`);
|
|
838
|
-
if (
|
|
877
|
+
if (matches === null || matches === void 0 ? void 0 : matches.groups) {
|
|
839
878
|
const { socketPath, path } = matches.groups;
|
|
840
879
|
Object.assign(options, {
|
|
841
880
|
socketPath,
|
|
@@ -852,8 +891,8 @@ class Request extends stream_1.Duplex {
|
|
|
852
891
|
else {
|
|
853
892
|
fallbackFn = isHttps ? https.request : http.request;
|
|
854
893
|
}
|
|
855
|
-
const realFn = (
|
|
856
|
-
const fn = options.
|
|
894
|
+
const realFn = (_a = options.request) !== null && _a !== void 0 ? _a : fallbackFn;
|
|
895
|
+
const fn = options.cache ? this._createCacheableRequest.bind(this) : realFn;
|
|
857
896
|
if (agent && !options.http2) {
|
|
858
897
|
options.agent = agent[isHttps ? 'https' : 'http'];
|
|
859
898
|
}
|
|
@@ -890,21 +929,20 @@ class Request extends stream_1.Duplex {
|
|
|
890
929
|
if (error instanceof RequestError) {
|
|
891
930
|
throw error;
|
|
892
931
|
}
|
|
893
|
-
throw new RequestError(error.message, error,
|
|
932
|
+
throw new RequestError(error.message, error, this);
|
|
894
933
|
}
|
|
895
934
|
}
|
|
896
935
|
async _beforeError(error) {
|
|
897
|
-
this
|
|
936
|
+
this[kStopReading] = true;
|
|
898
937
|
if (!(error instanceof RequestError)) {
|
|
899
|
-
error = new RequestError(error.message, error, this
|
|
938
|
+
error = new RequestError(error.message, error, this);
|
|
900
939
|
}
|
|
901
940
|
try {
|
|
902
941
|
const { response } = error;
|
|
903
|
-
if (response
|
|
904
|
-
response.
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
});
|
|
942
|
+
if (response) {
|
|
943
|
+
response.setEncoding(this._readableState.encoding);
|
|
944
|
+
response.rawBody = await getStream.buffer(response);
|
|
945
|
+
response.body = response.rawBody.toString();
|
|
908
946
|
}
|
|
909
947
|
}
|
|
910
948
|
catch (_) { }
|
|
@@ -915,14 +953,21 @@ class Request extends stream_1.Duplex {
|
|
|
915
953
|
}
|
|
916
954
|
}
|
|
917
955
|
catch (error_) {
|
|
918
|
-
error = new RequestError(error_.message, error_, this
|
|
956
|
+
error = new RequestError(error_.message, error_, this);
|
|
919
957
|
}
|
|
920
958
|
this.destroy(error);
|
|
921
959
|
}
|
|
922
960
|
_read() {
|
|
923
|
-
|
|
961
|
+
this[kTriggerRead] = true;
|
|
962
|
+
const response = this[kResponse];
|
|
963
|
+
if (response && !this[kStopReading]) {
|
|
964
|
+
// We cannot put this in the `if` above
|
|
965
|
+
// because `.read()` also triggers the `end` event
|
|
966
|
+
if (response.readableLength) {
|
|
967
|
+
this[kTriggerRead] = false;
|
|
968
|
+
}
|
|
924
969
|
let data;
|
|
925
|
-
while ((data =
|
|
970
|
+
while ((data = response.read()) !== null) {
|
|
926
971
|
this[kDownloadedSize] += data.length;
|
|
927
972
|
this[kStartedReading] = true;
|
|
928
973
|
const progress = this.downloadProgress;
|
|
@@ -937,11 +982,11 @@ class Request extends stream_1.Duplex {
|
|
|
937
982
|
const write = () => {
|
|
938
983
|
this._writeRequest(chunk, encoding, callback);
|
|
939
984
|
};
|
|
940
|
-
if (this.
|
|
985
|
+
if (this.requestInitialized) {
|
|
941
986
|
write();
|
|
942
987
|
}
|
|
943
988
|
else {
|
|
944
|
-
this.
|
|
989
|
+
this[kJobs].push(write);
|
|
945
990
|
}
|
|
946
991
|
}
|
|
947
992
|
_writeRequest(chunk, encoding, callback) {
|
|
@@ -952,6 +997,7 @@ class Request extends stream_1.Duplex {
|
|
|
952
997
|
this.emit('uploadProgress', progress);
|
|
953
998
|
}
|
|
954
999
|
});
|
|
1000
|
+
// TODO: What happens if it's from cache? Then this[kRequest] won't be defined.
|
|
955
1001
|
this[kRequest].write(chunk, encoding, (error) => {
|
|
956
1002
|
if (!error && this._progressCallbacks.length !== 0) {
|
|
957
1003
|
this._progressCallbacks.shift()();
|
|
@@ -980,26 +1026,26 @@ class Request extends stream_1.Duplex {
|
|
|
980
1026
|
callback(error);
|
|
981
1027
|
});
|
|
982
1028
|
};
|
|
983
|
-
if (this.
|
|
1029
|
+
if (this.requestInitialized) {
|
|
984
1030
|
endRequest();
|
|
985
1031
|
}
|
|
986
1032
|
else {
|
|
987
|
-
this.
|
|
1033
|
+
this[kJobs].push(endRequest);
|
|
988
1034
|
}
|
|
989
1035
|
}
|
|
990
1036
|
_destroy(error, callback) {
|
|
1037
|
+
var _a;
|
|
991
1038
|
if (kRequest in this) {
|
|
992
|
-
this[
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
});
|
|
1039
|
+
this[kCancelTimeouts]();
|
|
1040
|
+
// TODO: Remove the next `if` when these get fixed:
|
|
1041
|
+
// - https://github.com/nodejs/node/issues/32851
|
|
1042
|
+
// - https://github.com/nock/nock/issues/1981
|
|
1043
|
+
if (!((_a = this[kResponse]) === null || _a === void 0 ? void 0 : _a.complete) && !this[kRequest].destroyed) {
|
|
1044
|
+
this[kRequest].abort();
|
|
1045
|
+
}
|
|
1000
1046
|
}
|
|
1001
1047
|
if (error !== null && !is_1.default.undefined(error) && !(error instanceof RequestError)) {
|
|
1002
|
-
error = new RequestError(error.message, error, this
|
|
1048
|
+
error = new RequestError(error.message, error, this);
|
|
1003
1049
|
}
|
|
1004
1050
|
callback(error);
|
|
1005
1051
|
}
|
|
@@ -1011,6 +1057,10 @@ class Request extends stream_1.Duplex {
|
|
|
1011
1057
|
var _a;
|
|
1012
1058
|
return Boolean((_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.aborted);
|
|
1013
1059
|
}
|
|
1060
|
+
get socket() {
|
|
1061
|
+
var _a;
|
|
1062
|
+
return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket;
|
|
1063
|
+
}
|
|
1014
1064
|
get downloadProgress() {
|
|
1015
1065
|
let percent;
|
|
1016
1066
|
if (this[kResponseSize]) {
|