got 9.3.0 → 9.5.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/package.json +5 -5
- package/readme.md +30 -11
- package/source/errors.js +25 -24
- package/source/index.js +10 -0
- package/source/normalize-arguments.js +29 -35
- package/source/request-as-event-emitter.js +12 -11
- package/source/utils/timed-out.js +48 -42
- package/source/utils/is-retry-on-network-error-allowed.js +0 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "got",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.5.0",
|
|
4
4
|
"description": "Simplified HTTP requests",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/got",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"electron"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@sindresorhus/is": "^0.
|
|
37
|
+
"@sindresorhus/is": "^0.14.0",
|
|
38
38
|
"@szmarczak/http-timer": "^1.1.0",
|
|
39
39
|
"cacheable-request": "^5.1.0",
|
|
40
40
|
"decompress-response": "^3.3.0",
|
|
@@ -47,17 +47,17 @@
|
|
|
47
47
|
"url-parse-lax": "^3.0.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"ava": "1.0.
|
|
50
|
+
"ava": "^1.0.1",
|
|
51
51
|
"coveralls": "^3.0.0",
|
|
52
52
|
"delay": "^4.1.0",
|
|
53
53
|
"form-data": "^2.3.3",
|
|
54
54
|
"get-port": "^4.0.0",
|
|
55
|
-
"np": "^3.0
|
|
55
|
+
"np": "^3.1.0",
|
|
56
56
|
"nyc": "^13.1.0",
|
|
57
57
|
"p-event": "^2.1.0",
|
|
58
58
|
"pem": "^1.13.2",
|
|
59
59
|
"proxyquire": "^2.0.1",
|
|
60
|
-
"sinon": "^7.
|
|
60
|
+
"sinon": "^7.2.2",
|
|
61
61
|
"slow-stream": "0.0.4",
|
|
62
62
|
"tempfile": "^2.0.0",
|
|
63
63
|
"tempy": "^0.2.1",
|
package/readme.md
CHANGED
|
@@ -42,8 +42,9 @@ Got is for Node.js. For browsers, we recommend [Ky](https://github.com/sindresor
|
|
|
42
42
|
- [Used by ~2000 packages and ~500K repos](https://github.com/sindresorhus/got/network/dependents)
|
|
43
43
|
- Actively maintained
|
|
44
44
|
|
|
45
|
-
[
|
|
45
|
+
[Moving from Request?](migration-guides.md)
|
|
46
46
|
|
|
47
|
+
[See how Got compares to other HTTP libraries](#comparison)
|
|
47
48
|
|
|
48
49
|
## Install
|
|
49
50
|
|
|
@@ -258,22 +259,26 @@ Default:
|
|
|
258
259
|
- methods: `GET` `PUT` `HEAD` `DELETE` `OPTIONS` `TRACE`
|
|
259
260
|
- statusCodes: [`408`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) [`413`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/413) [`429`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) [`500`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) [`502`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502) [`503`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) [`504`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504)
|
|
260
261
|
- maxRetryAfter: `undefined`
|
|
262
|
+
- errorCodes: `ETIMEDOUT` `ECONNRESET` `EADDRINUSE` `ECONNREFUSED` `EPIPE` `ENOTFOUND` `ENETUNREACH` `EAI_AGAIN`
|
|
261
263
|
|
|
262
|
-
An object representing `retries`, `methods`, `statusCodes` and `
|
|
264
|
+
An object representing `retries`, `methods`, `statusCodes`, `maxRetryAfter` and `errorCodes` fields for the time until retry, allowed methods, allowed status codes, maximum [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) time and allowed error codes.
|
|
263
265
|
|
|
264
266
|
If `maxRetryAfter` is set to `undefined`, it will use `options.timeout`.<br>
|
|
265
267
|
If [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header is greater than `maxRetryAfter`, it will cancel the request.
|
|
266
268
|
|
|
267
|
-
Delays between retries counts with function `1000 * Math.pow(2, retry) + Math.random() * 100`, where `retry` is attempt number (starts from
|
|
269
|
+
Delays between retries counts with function `1000 * Math.pow(2, retry) + Math.random() * 100`, where `retry` is attempt number (starts from 1).
|
|
268
270
|
|
|
269
271
|
The `retries` property can be a `number` or a `function` with `retry` and `error` arguments. The function must return a delay in milliseconds (`0` return value cancels retry).
|
|
270
272
|
|
|
271
|
-
**Note:**
|
|
273
|
+
**Note:** By default, it retries *only* on the specified methods, status codes, and on these network errors:
|
|
272
274
|
- `ETIMEDOUT`: One of the [timeout](#timeout) limits were reached.
|
|
273
275
|
- `ECONNRESET`: Connection was forcibly closed by a peer.
|
|
274
276
|
- `EADDRINUSE`: Could not bind to any free port.
|
|
275
277
|
- `ECONNREFUSED`: Connection was refused by the server.
|
|
276
278
|
- `EPIPE`: The remote side of the stream being written has been closed.
|
|
279
|
+
- `ENOTFOUND`: Couldn't resolve the hostname to an IP address.
|
|
280
|
+
- `ENETUNREACH`: No internet connection.
|
|
281
|
+
- `EAI_AGAIN`: DNS lookup timed out.
|
|
277
282
|
|
|
278
283
|
###### followRedirect
|
|
279
284
|
|
|
@@ -448,6 +453,14 @@ const instance = got.extend({
|
|
|
448
453
|
|
|
449
454
|
The response object will typically be a [Node.js HTTP response stream](https://nodejs.org/api/http.html#http_class_http_incomingmessage), however, if returned from the cache it will be a [response-like object](https://github.com/lukechilds/responselike) which behaves in the same way.
|
|
450
455
|
|
|
456
|
+
##### request
|
|
457
|
+
|
|
458
|
+
Type: `Object`
|
|
459
|
+
|
|
460
|
+
**Note:** This is not a [http.ClientRequest](https://nodejs.org/api/http.html#http_class_http_clientrequest).
|
|
461
|
+
|
|
462
|
+
- `gotOptions` - The options that were set on this request.
|
|
463
|
+
|
|
451
464
|
##### body
|
|
452
465
|
|
|
453
466
|
Type: `string` `Object` *(depending on `options.json`)*
|
|
@@ -584,7 +597,7 @@ Sets `options.method` to the method name and makes a request.
|
|
|
584
597
|
|
|
585
598
|
#### got.extend([options])
|
|
586
599
|
|
|
587
|
-
Configure a new `got` instance with default `options`. `options` are merged with the parent instance's `defaults.options` using [`got.mergeOptions`](#gotmergeoptionsparentoptions-newoptions).
|
|
600
|
+
Configure a new `got` instance with default `options`. The `options` are merged with the parent instance's `defaults.options` using [`got.mergeOptions`](#gotmergeoptionsparentoptions-newoptions). You can access the resolved options with the `.defaults` property on the instance.
|
|
588
601
|
|
|
589
602
|
```js
|
|
590
603
|
const client = got.extend({
|
|
@@ -650,9 +663,15 @@ Options are deeply merged to a new object. The value of each key is determined a
|
|
|
650
663
|
- If the new property is an `Array`, it overwrites the old one with a deep clone of the new property.
|
|
651
664
|
- Otherwise, the new value is assigned to the key.
|
|
652
665
|
|
|
666
|
+
#### got.defaults
|
|
667
|
+
|
|
668
|
+
Type: `Object`
|
|
669
|
+
|
|
670
|
+
The default Got options.
|
|
671
|
+
|
|
653
672
|
## Errors
|
|
654
673
|
|
|
655
|
-
Each error contains
|
|
674
|
+
Each error contains `host`, `hostname`, `method`, `path`, `protocol`, `url` and `gotOptions` properties to make debugging easier.
|
|
656
675
|
|
|
657
676
|
In Promise mode, the `response` is attached to the error.
|
|
658
677
|
|
|
@@ -670,15 +689,15 @@ When reading from response stream fails.
|
|
|
670
689
|
|
|
671
690
|
#### got.ParseError
|
|
672
691
|
|
|
673
|
-
When `json` option is enabled, server response code is 2xx, and `JSON.parse` fails.
|
|
692
|
+
When `json` option is enabled, server response code is 2xx, and `JSON.parse` fails. Includes `statusCode` and `statusMessage` properties.
|
|
674
693
|
|
|
675
694
|
#### got.HTTPError
|
|
676
695
|
|
|
677
|
-
When the server response code is not 2xx. Includes `statusCode`, `statusMessage`, and `redirectUrls` properties.
|
|
696
|
+
When the server response code is not 2xx. Includes `body`, `statusCode`, `statusMessage`, and `redirectUrls` properties.
|
|
678
697
|
|
|
679
698
|
#### got.MaxRedirectsError
|
|
680
699
|
|
|
681
|
-
When the server redirects you more than ten times. Includes a `redirectUrls` property
|
|
700
|
+
When the server redirects you more than ten times. Includes a `statusCode`, `statusMessage`, and `redirectUrls` property which is an array of the URLs Got was redirected to before giving up.
|
|
682
701
|
|
|
683
702
|
#### got.UnsupportedProtocolError
|
|
684
703
|
|
|
@@ -690,7 +709,7 @@ When the request is aborted with `.cancel()`.
|
|
|
690
709
|
|
|
691
710
|
#### got.TimeoutError
|
|
692
711
|
|
|
693
|
-
When the request is aborted due to a [timeout](#timeout)
|
|
712
|
+
When the request is aborted due to a [timeout](#timeout). Includes an `event` property.
|
|
694
713
|
|
|
695
714
|
## Aborting the request
|
|
696
715
|
|
|
@@ -1023,7 +1042,7 @@ const h2got = got.extend({request});
|
|
|
1023
1042
|
| Electron support | ✔ | ✖ | ✖ | ✖ |
|
|
1024
1043
|
| Promise API | ✔ | ✔ | ✔ | ✔ |
|
|
1025
1044
|
| Stream API | ✔ | ✔ | Node.js only | ✖ |
|
|
1026
|
-
| Request cancelation | ✔ | ✖ |
|
|
1045
|
+
| Request cancelation | ✔ | ✖ | ✔ | ✔ |
|
|
1027
1046
|
| RFC compliant caching | ✔ | ✖ | ✖ | ✖ |
|
|
1028
1047
|
| Cookies (out-of-box) | ✔ | ✔ | ✖ | ✖ |
|
|
1029
1048
|
| Follows redirects | ✔ | ✔ | ✔ | ✔ |
|
package/source/errors.js
CHANGED
|
@@ -5,7 +5,7 @@ const PCancelable = require('p-cancelable');
|
|
|
5
5
|
const is = require('@sindresorhus/is');
|
|
6
6
|
|
|
7
7
|
class GotError extends Error {
|
|
8
|
-
constructor(message, error,
|
|
8
|
+
constructor(message, error, options) {
|
|
9
9
|
super(message);
|
|
10
10
|
Error.captureStackTrace(this, this.constructor);
|
|
11
11
|
this.name = 'GotError';
|
|
@@ -15,13 +15,14 @@ class GotError extends Error {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
Object.assign(this, {
|
|
18
|
-
host:
|
|
19
|
-
hostname:
|
|
20
|
-
method:
|
|
21
|
-
path:
|
|
22
|
-
socketPath:
|
|
23
|
-
protocol:
|
|
24
|
-
url:
|
|
18
|
+
host: options.host,
|
|
19
|
+
hostname: options.hostname,
|
|
20
|
+
method: options.method,
|
|
21
|
+
path: options.path,
|
|
22
|
+
socketPath: options.socketPath,
|
|
23
|
+
protocol: options.protocol,
|
|
24
|
+
url: options.href,
|
|
25
|
+
gotOptions: options
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
}
|
|
@@ -29,29 +30,29 @@ class GotError extends Error {
|
|
|
29
30
|
module.exports.GotError = GotError;
|
|
30
31
|
|
|
31
32
|
module.exports.CacheError = class extends GotError {
|
|
32
|
-
constructor(error,
|
|
33
|
-
super(error.message, error,
|
|
33
|
+
constructor(error, options) {
|
|
34
|
+
super(error.message, error, options);
|
|
34
35
|
this.name = 'CacheError';
|
|
35
36
|
}
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
module.exports.RequestError = class extends GotError {
|
|
39
|
-
constructor(error,
|
|
40
|
-
super(error.message, error,
|
|
40
|
+
constructor(error, options) {
|
|
41
|
+
super(error.message, error, options);
|
|
41
42
|
this.name = 'RequestError';
|
|
42
43
|
}
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
module.exports.ReadError = class extends GotError {
|
|
46
|
-
constructor(error,
|
|
47
|
-
super(error.message, error,
|
|
47
|
+
constructor(error, options) {
|
|
48
|
+
super(error.message, error, options);
|
|
48
49
|
this.name = 'ReadError';
|
|
49
50
|
}
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
module.exports.ParseError = class extends GotError {
|
|
53
|
-
constructor(error, statusCode,
|
|
54
|
-
super(`${error.message} in "${urlLib.format(
|
|
54
|
+
constructor(error, statusCode, options, data) {
|
|
55
|
+
super(`${error.message} in "${urlLib.format(options)}": \n${data.slice(0, 77)}...`, error, options);
|
|
55
56
|
this.name = 'ParseError';
|
|
56
57
|
this.statusCode = statusCode;
|
|
57
58
|
this.statusMessage = http.STATUS_CODES[this.statusCode];
|
|
@@ -59,7 +60,7 @@ module.exports.ParseError = class extends GotError {
|
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
module.exports.HTTPError = class extends GotError {
|
|
62
|
-
constructor(response,
|
|
63
|
+
constructor(response, options) {
|
|
63
64
|
const {statusCode} = response;
|
|
64
65
|
let {statusMessage} = response;
|
|
65
66
|
|
|
@@ -68,7 +69,7 @@ module.exports.HTTPError = class extends GotError {
|
|
|
68
69
|
} else {
|
|
69
70
|
statusMessage = http.STATUS_CODES[statusCode];
|
|
70
71
|
}
|
|
71
|
-
super(`Response code ${statusCode} (${statusMessage})`, {},
|
|
72
|
+
super(`Response code ${statusCode} (${statusMessage})`, {}, options);
|
|
72
73
|
this.name = 'HTTPError';
|
|
73
74
|
this.statusCode = statusCode;
|
|
74
75
|
this.statusMessage = statusMessage;
|
|
@@ -78,8 +79,8 @@ module.exports.HTTPError = class extends GotError {
|
|
|
78
79
|
};
|
|
79
80
|
|
|
80
81
|
module.exports.MaxRedirectsError = class extends GotError {
|
|
81
|
-
constructor(statusCode, redirectUrls,
|
|
82
|
-
super('Redirected 10 times. Aborting.', {},
|
|
82
|
+
constructor(statusCode, redirectUrls, options) {
|
|
83
|
+
super('Redirected 10 times. Aborting.', {}, options);
|
|
83
84
|
this.name = 'MaxRedirectsError';
|
|
84
85
|
this.statusCode = statusCode;
|
|
85
86
|
this.statusMessage = http.STATUS_CODES[this.statusCode];
|
|
@@ -88,15 +89,15 @@ module.exports.MaxRedirectsError = class extends GotError {
|
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
module.exports.UnsupportedProtocolError = class extends GotError {
|
|
91
|
-
constructor(
|
|
92
|
-
super(`Unsupported protocol "${
|
|
92
|
+
constructor(options) {
|
|
93
|
+
super(`Unsupported protocol "${options.protocol}"`, {}, options);
|
|
93
94
|
this.name = 'UnsupportedProtocolError';
|
|
94
95
|
}
|
|
95
96
|
};
|
|
96
97
|
|
|
97
98
|
module.exports.TimeoutError = class extends GotError {
|
|
98
|
-
constructor(error,
|
|
99
|
-
super(error.message, {code: 'ETIMEDOUT'},
|
|
99
|
+
constructor(error, options) {
|
|
100
|
+
super(error.message, {code: 'ETIMEDOUT'}, options);
|
|
100
101
|
this.name = 'TimeoutError';
|
|
101
102
|
this.event = error.event;
|
|
102
103
|
}
|
package/source/index.js
CHANGED
|
@@ -4,7 +4,6 @@ const urlLib = require('url');
|
|
|
4
4
|
const is = require('@sindresorhus/is');
|
|
5
5
|
const urlParseLax = require('url-parse-lax');
|
|
6
6
|
const lowercaseKeys = require('lowercase-keys');
|
|
7
|
-
const isRetryOnNetworkErrorAllowed = require('./utils/is-retry-on-network-error-allowed');
|
|
8
7
|
const urlToOptions = require('./utils/url-to-options');
|
|
9
8
|
const isFormData = require('./utils/is-form-data');
|
|
10
9
|
const merge = require('./merge');
|
|
@@ -56,7 +55,8 @@ const preNormalize = (options, defaults) => {
|
|
|
56
55
|
options.retry = {
|
|
57
56
|
retries: 0,
|
|
58
57
|
methods: [],
|
|
59
|
-
statusCodes: []
|
|
58
|
+
statusCodes: [],
|
|
59
|
+
errorCodes: []
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
if (is.nonEmptyObject(defaults) && retry !== false) {
|
|
@@ -83,20 +83,24 @@ const preNormalize = (options, defaults) => {
|
|
|
83
83
|
options.retry.statusCodes = new Set(options.retry.statusCodes);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
if (is.array(options.retry.errorCodes)) {
|
|
87
|
+
options.retry.errorCodes = new Set(options.retry.errorCodes);
|
|
88
|
+
}
|
|
89
|
+
|
|
86
90
|
return options;
|
|
87
91
|
};
|
|
88
92
|
|
|
89
93
|
const normalize = (url, options, defaults) => {
|
|
90
|
-
if (is.plainObject(url)
|
|
91
|
-
options = url;
|
|
92
|
-
url =
|
|
94
|
+
if (is.plainObject(url)) {
|
|
95
|
+
options = {...url, ...options};
|
|
96
|
+
url = options.url || {};
|
|
93
97
|
delete options.url;
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
if (defaults) {
|
|
97
101
|
options = merge({}, defaults.options, options ? preNormalize(options, defaults.options) : {});
|
|
98
102
|
} else {
|
|
99
|
-
options = merge({},
|
|
103
|
+
options = merge({}, preNormalize(options));
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
if (!is.string(url) && !is.object(url)) {
|
|
@@ -112,22 +116,14 @@ const normalize = (url, options, defaults) => {
|
|
|
112
116
|
url = urlToOptions(new URL(url, options.baseUrl));
|
|
113
117
|
} else {
|
|
114
118
|
url = url.replace(/^unix:/, 'http://$&');
|
|
115
|
-
|
|
116
119
|
url = urlParseLax(url);
|
|
117
|
-
if (url.auth) {
|
|
118
|
-
throw new Error('Basic authentication must be done with the `auth` option');
|
|
119
|
-
}
|
|
120
120
|
}
|
|
121
121
|
} else if (is(url) === 'URL') {
|
|
122
122
|
url = urlToOptions(url);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
...url,
|
|
128
|
-
protocol: url.protocol || 'https:', // Override both null/undefined with default protocol
|
|
129
|
-
...options
|
|
130
|
-
};
|
|
125
|
+
// Override both null/undefined with default protocol
|
|
126
|
+
options = merge({path: ''}, url, {protocol: url.protocol || 'https:'}, options);
|
|
131
127
|
|
|
132
128
|
const {baseUrl} = options;
|
|
133
129
|
Object.defineProperty(options, 'baseUrl', {
|
|
@@ -214,33 +210,31 @@ const normalize = (url, options, defaults) => {
|
|
|
214
210
|
return 0;
|
|
215
211
|
}
|
|
216
212
|
|
|
217
|
-
if (error
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (Reflect.has(error, 'headers') && Reflect.has(error.headers, 'retry-after') && retryAfterStatusCodes.has(error.statusCode)) {
|
|
223
|
-
let after = Number(error.headers['retry-after']);
|
|
224
|
-
if (is.nan(after)) {
|
|
225
|
-
after = Date.parse(error.headers['retry-after']) - Date.now();
|
|
226
|
-
} else {
|
|
227
|
-
after *= 1000;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (after > options.retry.maxRetryAfter) {
|
|
231
|
-
return 0;
|
|
232
|
-
}
|
|
213
|
+
if ((!error || !options.retry.errorCodes.has(error.code)) && (!options.retry.methods.has(error.method) || !options.retry.statusCodes.has(error.statusCode))) {
|
|
214
|
+
return 0;
|
|
215
|
+
}
|
|
233
216
|
|
|
234
|
-
|
|
217
|
+
if (Reflect.has(error, 'headers') && Reflect.has(error.headers, 'retry-after') && retryAfterStatusCodes.has(error.statusCode)) {
|
|
218
|
+
let after = Number(error.headers['retry-after']);
|
|
219
|
+
if (is.nan(after)) {
|
|
220
|
+
after = Date.parse(error.headers['retry-after']) - Date.now();
|
|
221
|
+
} else {
|
|
222
|
+
after *= 1000;
|
|
235
223
|
}
|
|
236
224
|
|
|
237
|
-
if (
|
|
225
|
+
if (after > options.retry.maxRetryAfter) {
|
|
238
226
|
return 0;
|
|
239
227
|
}
|
|
228
|
+
|
|
229
|
+
return after;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (error.statusCode === 413) {
|
|
233
|
+
return 0;
|
|
240
234
|
}
|
|
241
235
|
|
|
242
236
|
const noise = Math.random() * 100;
|
|
243
|
-
return ((
|
|
237
|
+
return ((2 ** (iteration - 1)) * 1000) + noise;
|
|
244
238
|
};
|
|
245
239
|
}
|
|
246
240
|
|
|
@@ -27,7 +27,6 @@ module.exports = (options, input) => {
|
|
|
27
27
|
let redirectString;
|
|
28
28
|
let uploadBodySize;
|
|
29
29
|
let retryCount = 0;
|
|
30
|
-
let retryTries = 0;
|
|
31
30
|
let shouldAbort = false;
|
|
32
31
|
|
|
33
32
|
const setCookie = options.cookieJar ? util.promisify(options.cookieJar.setCookie.bind(options.cookieJar)) : null;
|
|
@@ -93,6 +92,9 @@ module.exports = (options, input) => {
|
|
|
93
92
|
response.retryCount = retryCount;
|
|
94
93
|
response.timings = timings;
|
|
95
94
|
response.redirectUrls = redirects;
|
|
95
|
+
response.request = {
|
|
96
|
+
gotOptions: options
|
|
97
|
+
};
|
|
96
98
|
|
|
97
99
|
const rawCookies = response.headers['set-cookie'];
|
|
98
100
|
if (options.cookieJar && rawCookies) {
|
|
@@ -120,19 +122,19 @@ module.exports = (options, input) => {
|
|
|
120
122
|
|
|
121
123
|
redirects.push(redirectString);
|
|
122
124
|
|
|
123
|
-
const
|
|
125
|
+
const redirectOptions = {
|
|
124
126
|
...options,
|
|
125
127
|
...urlToOptions(redirectURL)
|
|
126
128
|
};
|
|
127
129
|
|
|
128
130
|
for (const hook of options.hooks.beforeRedirect) {
|
|
129
131
|
// eslint-disable-next-line no-await-in-loop
|
|
130
|
-
await hook(
|
|
132
|
+
await hook(redirectOptions);
|
|
131
133
|
}
|
|
132
134
|
|
|
133
|
-
emitter.emit('redirect', response,
|
|
135
|
+
emitter.emit('redirect', response, redirectOptions);
|
|
134
136
|
|
|
135
|
-
await get(
|
|
137
|
+
await get(redirectOptions);
|
|
136
138
|
return;
|
|
137
139
|
}
|
|
138
140
|
}
|
|
@@ -202,9 +204,9 @@ module.exports = (options, input) => {
|
|
|
202
204
|
|
|
203
205
|
if (options.cache) {
|
|
204
206
|
const cacheableRequest = new CacheableRequest(fn.request, options.cache);
|
|
205
|
-
const
|
|
207
|
+
const cacheRequest = cacheableRequest(options, handleResponse);
|
|
206
208
|
|
|
207
|
-
|
|
209
|
+
cacheRequest.once('error', error => {
|
|
208
210
|
if (error instanceof CacheableRequest.RequestError) {
|
|
209
211
|
emitter.emit('error', new RequestError(error, options));
|
|
210
212
|
} else {
|
|
@@ -212,7 +214,7 @@ module.exports = (options, input) => {
|
|
|
212
214
|
}
|
|
213
215
|
});
|
|
214
216
|
|
|
215
|
-
|
|
217
|
+
cacheRequest.once('request', handleRequest);
|
|
216
218
|
} else {
|
|
217
219
|
// Catches errors thrown by calling fn.request(...)
|
|
218
220
|
try {
|
|
@@ -227,7 +229,7 @@ module.exports = (options, input) => {
|
|
|
227
229
|
let backoff;
|
|
228
230
|
|
|
229
231
|
try {
|
|
230
|
-
backoff = options.retry.retries(++
|
|
232
|
+
backoff = options.retry.retries(++retryCount, error);
|
|
231
233
|
} catch (error2) {
|
|
232
234
|
emitter.emit('error', error2);
|
|
233
235
|
return;
|
|
@@ -241,7 +243,6 @@ module.exports = (options, input) => {
|
|
|
241
243
|
await hook(options, error, retryCount);
|
|
242
244
|
}
|
|
243
245
|
|
|
244
|
-
retryCount++;
|
|
245
246
|
await get(options);
|
|
246
247
|
} catch (error) {
|
|
247
248
|
emitter.emit('error', error);
|
|
@@ -276,7 +277,7 @@ module.exports = (options, input) => {
|
|
|
276
277
|
}
|
|
277
278
|
|
|
278
279
|
if (is.undefined(options.headers['content-length']) && is.undefined(options.headers['transfer-encoding'])) {
|
|
279
|
-
if (uploadBodySize > 0 || options.method === 'PUT') {
|
|
280
|
+
if ((uploadBodySize > 0 || options.method === 'PUT') && !is.null(uploadBodySize)) {
|
|
280
281
|
options.headers['content-length'] = uploadBodySize;
|
|
281
282
|
}
|
|
282
283
|
}
|
|
@@ -12,31 +12,7 @@ class TimeoutError extends Error {
|
|
|
12
12
|
|
|
13
13
|
const reentry = Symbol('reentry');
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
// Event loop order is timers, poll, immediates.
|
|
17
|
-
// The timed event may emit during the current tick poll phase, so
|
|
18
|
-
// defer calling the handler until the poll phase completes.
|
|
19
|
-
let immediate;
|
|
20
|
-
const timeout = setTimeout(() => {
|
|
21
|
-
immediate = setImmediate(callback, delay, ...args);
|
|
22
|
-
/* istanbul ignore next: added in node v9.7.0 */
|
|
23
|
-
if (immediate.unref) {
|
|
24
|
-
immediate.unref();
|
|
25
|
-
}
|
|
26
|
-
}, delay);
|
|
27
|
-
|
|
28
|
-
/* istanbul ignore next: in order to support electron renderer */
|
|
29
|
-
if (timeout.unref) {
|
|
30
|
-
timeout.unref();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const cancel = () => {
|
|
34
|
-
clearTimeout(timeout);
|
|
35
|
-
clearImmediate(immediate);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
return cancel;
|
|
39
|
-
}
|
|
15
|
+
const noop = () => {};
|
|
40
16
|
|
|
41
17
|
module.exports = (request, delays, options) => {
|
|
42
18
|
/* istanbul ignore next: this makes sure timed-out isn't called twice */
|
|
@@ -45,6 +21,43 @@ module.exports = (request, delays, options) => {
|
|
|
45
21
|
}
|
|
46
22
|
|
|
47
23
|
request[reentry] = true;
|
|
24
|
+
|
|
25
|
+
let stopNewTimeouts = false;
|
|
26
|
+
|
|
27
|
+
const addTimeout = (delay, callback, ...args) => {
|
|
28
|
+
// An error had been thrown before. Going further would result in uncaught errors.
|
|
29
|
+
// See https://github.com/sindresorhus/got/issues/631#issuecomment-435675051
|
|
30
|
+
if (stopNewTimeouts) {
|
|
31
|
+
return noop;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Event loop order is timers, poll, immediates.
|
|
35
|
+
// The timed event may emit during the current tick poll phase, so
|
|
36
|
+
// defer calling the handler until the poll phase completes.
|
|
37
|
+
let immediate;
|
|
38
|
+
const timeout = setTimeout(() => {
|
|
39
|
+
immediate = setImmediate(callback, delay, ...args);
|
|
40
|
+
/* istanbul ignore next: added in node v9.7.0 */
|
|
41
|
+
if (immediate.unref) {
|
|
42
|
+
immediate.unref();
|
|
43
|
+
}
|
|
44
|
+
}, delay);
|
|
45
|
+
|
|
46
|
+
/* istanbul ignore next: in order to support electron renderer */
|
|
47
|
+
if (timeout.unref) {
|
|
48
|
+
timeout.unref();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const cancel = () => {
|
|
52
|
+
clearTimeout(timeout);
|
|
53
|
+
clearImmediate(immediate);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
cancelers.push(cancel);
|
|
57
|
+
|
|
58
|
+
return cancel;
|
|
59
|
+
};
|
|
60
|
+
|
|
48
61
|
const {host, hostname} = options;
|
|
49
62
|
const timeoutHandler = (delay, event) => {
|
|
50
63
|
request.emit('error', new TimeoutError(delay, event));
|
|
@@ -55,6 +68,7 @@ module.exports = (request, delays, options) => {
|
|
|
55
68
|
|
|
56
69
|
const cancelers = [];
|
|
57
70
|
const cancelTimeouts = () => {
|
|
71
|
+
stopNewTimeouts = true;
|
|
58
72
|
cancelers.forEach(cancelTimeout => cancelTimeout());
|
|
59
73
|
};
|
|
60
74
|
|
|
@@ -64,14 +78,15 @@ module.exports = (request, delays, options) => {
|
|
|
64
78
|
});
|
|
65
79
|
|
|
66
80
|
if (delays.request !== undefined) {
|
|
67
|
-
|
|
68
|
-
cancelers.push(cancelTimeout);
|
|
81
|
+
addTimeout(delays.request, timeoutHandler, 'request');
|
|
69
82
|
}
|
|
70
83
|
|
|
71
84
|
if (delays.socket !== undefined) {
|
|
72
85
|
request.setTimeout(delays.socket, () => {
|
|
73
86
|
timeoutHandler(delays.socket, 'socket');
|
|
74
87
|
});
|
|
88
|
+
|
|
89
|
+
cancelers.push(() => request.setTimeout(0));
|
|
75
90
|
}
|
|
76
91
|
|
|
77
92
|
if (delays.lookup !== undefined && !request.socketPath && !net.isIP(hostname || host)) {
|
|
@@ -79,7 +94,6 @@ module.exports = (request, delays, options) => {
|
|
|
79
94
|
/* istanbul ignore next: hard to test */
|
|
80
95
|
if (socket.connecting) {
|
|
81
96
|
const cancelTimeout = addTimeout(delays.lookup, timeoutHandler, 'lookup');
|
|
82
|
-
cancelers.push(cancelTimeout);
|
|
83
97
|
socket.once('lookup', cancelTimeout);
|
|
84
98
|
}
|
|
85
99
|
});
|
|
@@ -89,17 +103,15 @@ module.exports = (request, delays, options) => {
|
|
|
89
103
|
request.once('socket', socket => {
|
|
90
104
|
/* istanbul ignore next: hard to test */
|
|
91
105
|
if (socket.connecting) {
|
|
92
|
-
const timeConnect = () =>
|
|
93
|
-
const cancelTimeout = addTimeout(delays.connect, timeoutHandler, 'connect');
|
|
94
|
-
cancelers.push(cancelTimeout);
|
|
95
|
-
return cancelTimeout;
|
|
96
|
-
};
|
|
106
|
+
const timeConnect = () => addTimeout(delays.connect, timeoutHandler, 'connect');
|
|
97
107
|
|
|
98
108
|
if (request.socketPath || net.isIP(hostname || host)) {
|
|
99
109
|
socket.once('connect', timeConnect());
|
|
100
110
|
} else {
|
|
101
|
-
socket.once('lookup',
|
|
102
|
-
|
|
111
|
+
socket.once('lookup', error => {
|
|
112
|
+
if (error === null) {
|
|
113
|
+
socket.once('connect', timeConnect());
|
|
114
|
+
}
|
|
103
115
|
});
|
|
104
116
|
}
|
|
105
117
|
}
|
|
@@ -112,7 +124,6 @@ module.exports = (request, delays, options) => {
|
|
|
112
124
|
if (socket.connecting) {
|
|
113
125
|
socket.once('connect', () => {
|
|
114
126
|
const cancelTimeout = addTimeout(delays.secureConnect, timeoutHandler, 'secureConnect');
|
|
115
|
-
cancelers.push(cancelTimeout);
|
|
116
127
|
socket.once('secureConnect', cancelTimeout);
|
|
117
128
|
});
|
|
118
129
|
}
|
|
@@ -121,11 +132,7 @@ module.exports = (request, delays, options) => {
|
|
|
121
132
|
|
|
122
133
|
if (delays.send !== undefined) {
|
|
123
134
|
request.once('socket', socket => {
|
|
124
|
-
const timeRequest = () =>
|
|
125
|
-
const cancelTimeout = addTimeout(delays.send, timeoutHandler, 'send');
|
|
126
|
-
cancelers.push(cancelTimeout);
|
|
127
|
-
return cancelTimeout;
|
|
128
|
-
};
|
|
135
|
+
const timeRequest = () => addTimeout(delays.send, timeoutHandler, 'send');
|
|
129
136
|
/* istanbul ignore next: hard to test */
|
|
130
137
|
if (socket.connecting) {
|
|
131
138
|
socket.once('connect', () => {
|
|
@@ -140,7 +147,6 @@ module.exports = (request, delays, options) => {
|
|
|
140
147
|
if (delays.response !== undefined) {
|
|
141
148
|
request.once('upload-complete', () => {
|
|
142
149
|
const cancelTimeout = addTimeout(delays.response, timeoutHandler, 'response');
|
|
143
|
-
cancelers.push(cancelTimeout);
|
|
144
150
|
request.once('response', cancelTimeout);
|
|
145
151
|
});
|
|
146
152
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const WHITELIST = new Set([
|
|
4
|
-
'ETIMEDOUT',
|
|
5
|
-
'ECONNRESET',
|
|
6
|
-
'EADDRINUSE',
|
|
7
|
-
'ECONNREFUSED',
|
|
8
|
-
'EPIPE',
|
|
9
|
-
'ENOTFOUND',
|
|
10
|
-
'ENETUNREACH',
|
|
11
|
-
'EAI_AGAIN'
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
module.exports = error => {
|
|
15
|
-
if (error && WHITELIST.has(error.code)) {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return false;
|
|
20
|
-
};
|