got 8.0.2 → 8.3.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/index.js +111 -62
- package/package.json +5 -4
- package/readme.md +66 -4
package/index.js
CHANGED
|
@@ -142,59 +142,12 @@ function requestAsEventEmitter(opts) {
|
|
|
142
142
|
return;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
const downloadBodySize = Number(res.headers['content-length']) || null;
|
|
146
|
-
let downloaded = 0;
|
|
147
|
-
|
|
148
145
|
setImmediate(() => {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const percent = downloadBodySize ? downloaded / downloadBodySize : 0;
|
|
154
|
-
|
|
155
|
-
// Let flush() be responsible for emitting the last event
|
|
156
|
-
if (percent < 1) {
|
|
157
|
-
ee.emit('downloadProgress', {
|
|
158
|
-
percent,
|
|
159
|
-
transferred: downloaded,
|
|
160
|
-
total: downloadBodySize
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
callback(null, chunk);
|
|
165
|
-
},
|
|
166
|
-
|
|
167
|
-
flush(callback) {
|
|
168
|
-
ee.emit('downloadProgress', {
|
|
169
|
-
percent: 1,
|
|
170
|
-
transferred: downloaded,
|
|
171
|
-
total: downloadBodySize
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
callback();
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
mimicResponse(res, progressStream);
|
|
179
|
-
progressStream.redirectUrls = redirects;
|
|
180
|
-
|
|
181
|
-
const response = opts.decompress === true &&
|
|
182
|
-
is.function(decompressResponse) &&
|
|
183
|
-
opts.method !== 'HEAD' ? decompressResponse(progressStream) : progressStream;
|
|
184
|
-
|
|
185
|
-
if (!opts.decompress && ['gzip', 'deflate'].indexOf(res.headers['content-encoding']) !== -1) {
|
|
186
|
-
opts.encoding = null;
|
|
146
|
+
try {
|
|
147
|
+
getResponse(res, opts, ee, redirects);
|
|
148
|
+
} catch (e) {
|
|
149
|
+
ee.emit('error', e);
|
|
187
150
|
}
|
|
188
|
-
|
|
189
|
-
ee.emit('response', response);
|
|
190
|
-
|
|
191
|
-
ee.emit('downloadProgress', {
|
|
192
|
-
percent: 0,
|
|
193
|
-
transferred: 0,
|
|
194
|
-
total: downloadBodySize
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
res.pipe(progressStream);
|
|
198
151
|
});
|
|
199
152
|
});
|
|
200
153
|
|
|
@@ -207,9 +160,18 @@ function requestAsEventEmitter(opts) {
|
|
|
207
160
|
});
|
|
208
161
|
|
|
209
162
|
cacheReq.once('request', req => {
|
|
163
|
+
let aborted = false;
|
|
164
|
+
req.once('abort', _ => {
|
|
165
|
+
aborted = true;
|
|
166
|
+
});
|
|
167
|
+
|
|
210
168
|
req.once('error', err => {
|
|
211
169
|
clearInterval(progressInterval);
|
|
212
170
|
|
|
171
|
+
if (aborted) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
213
175
|
const backoff = opts.retries(++retryCount, err);
|
|
214
176
|
|
|
215
177
|
if (backoff) {
|
|
@@ -227,14 +189,18 @@ function requestAsEventEmitter(opts) {
|
|
|
227
189
|
total: uploadBodySize
|
|
228
190
|
});
|
|
229
191
|
|
|
230
|
-
|
|
231
|
-
|
|
192
|
+
const socket = req.connection;
|
|
193
|
+
if (socket) {
|
|
194
|
+
// `._connecting` was the old property which was made public in node v6.1.0
|
|
195
|
+
const isConnecting = socket.connecting === undefined ? socket._connecting : socket.connecting;
|
|
196
|
+
|
|
197
|
+
const onSocketConnect = () => {
|
|
232
198
|
const uploadEventFrequency = 150;
|
|
233
199
|
|
|
234
200
|
progressInterval = setInterval(() => {
|
|
235
201
|
const lastUploaded = uploaded;
|
|
236
202
|
const headersSize = Buffer.byteLength(req._header);
|
|
237
|
-
uploaded =
|
|
203
|
+
uploaded = socket.bytesWritten - headersSize;
|
|
238
204
|
|
|
239
205
|
// Prevent the known issue of `bytesWritten` being larger than body size
|
|
240
206
|
if (uploadBodySize && uploaded > uploadBodySize) {
|
|
@@ -254,7 +220,17 @@ function requestAsEventEmitter(opts) {
|
|
|
254
220
|
total: uploadBodySize
|
|
255
221
|
});
|
|
256
222
|
}, uploadEventFrequency);
|
|
257
|
-
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Only subscribe to 'connect' event if we're actually connecting a new
|
|
226
|
+
// socket, otherwise if we're already connected (because this is a
|
|
227
|
+
// keep-alive connection) do not bother. This is important since we won't
|
|
228
|
+
// get a 'connect' event for an already connected socket.
|
|
229
|
+
if (isConnecting) {
|
|
230
|
+
socket.once('connect', onSocketConnect);
|
|
231
|
+
} else {
|
|
232
|
+
onSocketConnect();
|
|
233
|
+
}
|
|
258
234
|
}
|
|
259
235
|
});
|
|
260
236
|
|
|
@@ -283,6 +259,61 @@ function requestAsEventEmitter(opts) {
|
|
|
283
259
|
return ee;
|
|
284
260
|
}
|
|
285
261
|
|
|
262
|
+
function getResponse(res, opts, ee, redirects) {
|
|
263
|
+
const downloadBodySize = Number(res.headers['content-length']) || null;
|
|
264
|
+
let downloaded = 0;
|
|
265
|
+
|
|
266
|
+
const progressStream = new Transform({
|
|
267
|
+
transform(chunk, encoding, callback) {
|
|
268
|
+
downloaded += chunk.length;
|
|
269
|
+
|
|
270
|
+
const percent = downloadBodySize ? downloaded / downloadBodySize : 0;
|
|
271
|
+
|
|
272
|
+
// Let flush() be responsible for emitting the last event
|
|
273
|
+
if (percent < 1) {
|
|
274
|
+
ee.emit('downloadProgress', {
|
|
275
|
+
percent,
|
|
276
|
+
transferred: downloaded,
|
|
277
|
+
total: downloadBodySize
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
callback(null, chunk);
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
flush(callback) {
|
|
285
|
+
ee.emit('downloadProgress', {
|
|
286
|
+
percent: 1,
|
|
287
|
+
transferred: downloaded,
|
|
288
|
+
total: downloadBodySize
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
callback();
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
mimicResponse(res, progressStream);
|
|
296
|
+
progressStream.redirectUrls = redirects;
|
|
297
|
+
|
|
298
|
+
const response = opts.decompress === true &&
|
|
299
|
+
is.function(decompressResponse) &&
|
|
300
|
+
opts.method !== 'HEAD' ? decompressResponse(progressStream) : progressStream;
|
|
301
|
+
|
|
302
|
+
if (!opts.decompress && ['gzip', 'deflate'].indexOf(res.headers['content-encoding']) !== -1) {
|
|
303
|
+
opts.encoding = null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
ee.emit('response', response);
|
|
307
|
+
|
|
308
|
+
ee.emit('downloadProgress', {
|
|
309
|
+
percent: 0,
|
|
310
|
+
transferred: 0,
|
|
311
|
+
total: downloadBodySize
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
res.pipe(progressStream);
|
|
315
|
+
}
|
|
316
|
+
|
|
286
317
|
function asPromise(opts) {
|
|
287
318
|
const timeoutFn = requestPromise => opts.gotTimeout && opts.gotTimeout.request ?
|
|
288
319
|
pTimeout(requestPromise, opts.gotTimeout.request, new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts)) :
|
|
@@ -290,7 +321,7 @@ function asPromise(opts) {
|
|
|
290
321
|
|
|
291
322
|
const proxy = new EventEmitter();
|
|
292
323
|
|
|
293
|
-
const cancelable = new PCancelable((
|
|
324
|
+
const cancelable = new PCancelable((resolve, reject, onCancel) => {
|
|
294
325
|
const ee = requestAsEventEmitter(opts);
|
|
295
326
|
let cancelOnRequest = false;
|
|
296
327
|
|
|
@@ -337,7 +368,7 @@ function asPromise(opts) {
|
|
|
337
368
|
}
|
|
338
369
|
}
|
|
339
370
|
|
|
340
|
-
if (statusCode !== 304 && (statusCode < 200 || statusCode > limitStatusCode)) {
|
|
371
|
+
if (opts.throwHttpErrors && statusCode !== 304 && (statusCode < 200 || statusCode > limitStatusCode)) {
|
|
341
372
|
throw new got.HTTPError(statusCode, res.statusMessage, res.headers, opts);
|
|
342
373
|
}
|
|
343
374
|
|
|
@@ -355,6 +386,14 @@ function asPromise(opts) {
|
|
|
355
386
|
ee.on('downloadProgress', proxy.emit.bind(proxy, 'downloadProgress'));
|
|
356
387
|
});
|
|
357
388
|
|
|
389
|
+
// Preserve backwards-compatibility
|
|
390
|
+
// TODO: Remove this in the next major version
|
|
391
|
+
Object.defineProperty(cancelable, 'canceled', {
|
|
392
|
+
get() {
|
|
393
|
+
return cancelable.isCanceled;
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
358
397
|
const promise = timeoutFn(cancelable);
|
|
359
398
|
|
|
360
399
|
promise.cancel = cancelable.cancel.bind(cancelable);
|
|
@@ -425,7 +464,7 @@ function asStream(opts) {
|
|
|
425
464
|
|
|
426
465
|
res.pipe(output);
|
|
427
466
|
|
|
428
|
-
if (statusCode !== 304 && (statusCode < 200 || statusCode > 299)) {
|
|
467
|
+
if (opts.throwHttpErrors && statusCode !== 304 && (statusCode < 200 || statusCode > 299)) {
|
|
429
468
|
proxy.emit('error', new got.HTTPError(statusCode, res.statusMessage, res.headers, opts), null, res);
|
|
430
469
|
return;
|
|
431
470
|
}
|
|
@@ -467,7 +506,8 @@ function normalizeArguments(url, opts) {
|
|
|
467
506
|
retries: 2,
|
|
468
507
|
cache: false,
|
|
469
508
|
decompress: true,
|
|
470
|
-
useElectronNet: false
|
|
509
|
+
useElectronNet: false,
|
|
510
|
+
throwHttpErrors: true
|
|
471
511
|
},
|
|
472
512
|
url,
|
|
473
513
|
{
|
|
@@ -484,10 +524,13 @@ function normalizeArguments(url, opts) {
|
|
|
484
524
|
}
|
|
485
525
|
|
|
486
526
|
opts.headers = Object.assign({
|
|
487
|
-
'user-agent': `${pkg.name}/${pkg.version} (https://github.com/sindresorhus/got)
|
|
488
|
-
'accept-encoding': 'gzip,deflate'
|
|
527
|
+
'user-agent': `${pkg.name}/${pkg.version} (https://github.com/sindresorhus/got)`
|
|
489
528
|
}, headers);
|
|
490
529
|
|
|
530
|
+
if (opts.decompress) {
|
|
531
|
+
opts.headers['accept-encoding'] = 'gzip,deflate';
|
|
532
|
+
}
|
|
533
|
+
|
|
491
534
|
const query = opts.query;
|
|
492
535
|
|
|
493
536
|
if (query) {
|
|
@@ -585,7 +628,13 @@ function normalizeArguments(url, opts) {
|
|
|
585
628
|
|
|
586
629
|
function got(url, opts) {
|
|
587
630
|
try {
|
|
588
|
-
|
|
631
|
+
const normalizedArgs = normalizeArguments(url, opts);
|
|
632
|
+
|
|
633
|
+
if (normalizedArgs.stream) {
|
|
634
|
+
return asStream(normalizedArgs);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
return asPromise(normalizedArgs);
|
|
589
638
|
} catch (err) {
|
|
590
639
|
return Promise.reject(err);
|
|
591
640
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "got",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.3.0",
|
|
4
4
|
"description": "Simplified HTTP requests",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/got",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"isurl": "^1.0.0-alpha5",
|
|
62
62
|
"lowercase-keys": "^1.0.0",
|
|
63
63
|
"mimic-response": "^1.0.0",
|
|
64
|
-
"p-cancelable": "^0.
|
|
64
|
+
"p-cancelable": "^0.4.0",
|
|
65
65
|
"p-timeout": "^2.0.1",
|
|
66
66
|
"pify": "^3.0.0",
|
|
67
67
|
"safe-buffer": "^5.1.1",
|
|
@@ -70,19 +70,20 @@
|
|
|
70
70
|
"url-to-options": "^1.0.1"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
|
-
"ava": "^0.
|
|
73
|
+
"ava": "^0.25.0",
|
|
74
74
|
"coveralls": "^3.0.0",
|
|
75
75
|
"form-data": "^2.1.1",
|
|
76
76
|
"get-port": "^3.0.0",
|
|
77
77
|
"nyc": "^11.0.2",
|
|
78
78
|
"p-event": "^1.3.0",
|
|
79
79
|
"pem": "^1.4.4",
|
|
80
|
+
"proxyquire": "^1.8.0",
|
|
80
81
|
"sinon": "^4.0.0",
|
|
81
82
|
"slow-stream": "0.0.4",
|
|
82
83
|
"tempfile": "^2.0.0",
|
|
83
84
|
"tempy": "^0.2.1",
|
|
84
85
|
"universal-url": "1.0.0-alpha",
|
|
85
|
-
"xo": "^0.
|
|
86
|
+
"xo": "^0.20.0"
|
|
86
87
|
},
|
|
87
88
|
"ava": {
|
|
88
89
|
"concurrency": 4
|
package/readme.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
<
|
|
1
|
+
<div align="center">
|
|
2
|
+
<br>
|
|
2
3
|
<br>
|
|
3
4
|
<img width="360" src="https://rawgit.com/sindresorhus/got/master/media/logo.svg" alt="got">
|
|
4
5
|
<br>
|
|
5
6
|
<br>
|
|
6
7
|
<br>
|
|
7
|
-
|
|
8
|
+
<p align="center">Huge thanks to <a href="https://moxy.studio"><img src="https://sindresorhus.com/assets/thanks/moxy-logo.svg" width="150"></a> for sponsoring me!
|
|
9
|
+
</p>
|
|
10
|
+
<br>
|
|
11
|
+
<br>
|
|
12
|
+
</div>
|
|
8
13
|
|
|
9
14
|
> Simplified HTTP requests
|
|
10
15
|
|
|
@@ -37,6 +42,10 @@ Created because [`request`](https://github.com/request/request) is bloated *(sev
|
|
|
37
42
|
$ npm install got
|
|
38
43
|
```
|
|
39
44
|
|
|
45
|
+
<a href="https://www.patreon.com/sindresorhus">
|
|
46
|
+
<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
|
|
47
|
+
</a>
|
|
48
|
+
|
|
40
49
|
|
|
41
50
|
## Usage
|
|
42
51
|
|
|
@@ -96,6 +105,13 @@ Type: `Object`
|
|
|
96
105
|
|
|
97
106
|
Any of the [`http.request`](http://nodejs.org/api/http.html#http_http_request_options_callback) options.
|
|
98
107
|
|
|
108
|
+
###### stream
|
|
109
|
+
|
|
110
|
+
Type: `boolean`<br>
|
|
111
|
+
Default: `false`
|
|
112
|
+
|
|
113
|
+
Returns a `Stream` instead of a `Promise`. This is equivalent to calling `got.stream(url, [options])`.
|
|
114
|
+
|
|
99
115
|
###### body
|
|
100
116
|
|
|
101
117
|
Type: `string` `Buffer` `stream.Readable`
|
|
@@ -113,7 +129,7 @@ If `content-length` or `transfer-encoding` is not set in `options.headers` and `
|
|
|
113
129
|
Type: `string` `null`<br>
|
|
114
130
|
Default: `'utf8'`
|
|
115
131
|
|
|
116
|
-
[Encoding](https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings) to be used on `setEncoding` of the response data. If `null`, the body is returned as a Buffer.
|
|
132
|
+
[Encoding](https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings) to be used on `setEncoding` of the response data. If `null`, the body is returned as a [`Buffer`](https://nodejs.org/api/buffer.html) (binary data).
|
|
117
133
|
|
|
118
134
|
###### form
|
|
119
135
|
|
|
@@ -197,6 +213,14 @@ Default: `false`
|
|
|
197
213
|
|
|
198
214
|
When used in Electron, Got will use [`electron.net`](https://electronjs.org/docs/api/net/) instead of the Node.js `http` module. According to the Electron docs, it should be fully compatible, but it's not entirely. See [#315](https://github.com/sindresorhus/got/issues/315).
|
|
199
215
|
|
|
216
|
+
###### throwHttpErrors
|
|
217
|
+
|
|
218
|
+
Type: `boolean`<br>
|
|
219
|
+
Default: `true`
|
|
220
|
+
|
|
221
|
+
Determines if a `got.HTTPError` is thrown for error responses (non-2xx status codes).
|
|
222
|
+
|
|
223
|
+
If this is disabled, requests that encounter an error status code will be resolved with the `response` instead of throwing. This may be useful if you are checking for resource availability and are expecting error responses.
|
|
200
224
|
|
|
201
225
|
#### Streams
|
|
202
226
|
|
|
@@ -327,7 +351,7 @@ The promise returned by Got has a [`.cancel()`](https://github.com/sindresorhus/
|
|
|
327
351
|
try {
|
|
328
352
|
await request;
|
|
329
353
|
} catch (error) {
|
|
330
|
-
if (request.
|
|
354
|
+
if (request.isCanceled) { // Or `error instanceof got.CancelError`
|
|
331
355
|
// Handle cancelation
|
|
332
356
|
}
|
|
333
357
|
|
|
@@ -545,6 +569,44 @@ request(`https://${config.host}/production/`, {
|
|
|
545
569
|
```
|
|
546
570
|
|
|
547
571
|
|
|
572
|
+
## Testing
|
|
573
|
+
|
|
574
|
+
You can test your requests by using the [`nock`](https://github.com/node-nock/nock) module to mock an endpoint:
|
|
575
|
+
|
|
576
|
+
```js
|
|
577
|
+
const got = require('got');
|
|
578
|
+
const nock = require('nock');
|
|
579
|
+
|
|
580
|
+
nock('https://sindresorhus.com')
|
|
581
|
+
.get('/')
|
|
582
|
+
.reply(200, 'Hello world!');
|
|
583
|
+
|
|
584
|
+
(async () => {
|
|
585
|
+
const response = await got('sindresorhus.com');
|
|
586
|
+
console.log(response.body);
|
|
587
|
+
//=> 'Hello world!'
|
|
588
|
+
})();
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
If you need real integration tests you can use [`create-test-server`](https://github.com/lukechilds/create-test-server):
|
|
592
|
+
|
|
593
|
+
```js
|
|
594
|
+
const got = require('got');
|
|
595
|
+
const createTestServer = require('create-test-server');
|
|
596
|
+
|
|
597
|
+
(async () => {
|
|
598
|
+
const server = await createTestServer();
|
|
599
|
+
server.get('/', 'Hello world!');
|
|
600
|
+
|
|
601
|
+
const response = await got(server.url);
|
|
602
|
+
console.log(response.body);
|
|
603
|
+
//=> 'Hello world!'
|
|
604
|
+
|
|
605
|
+
await server.close();
|
|
606
|
+
})();
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
|
|
548
610
|
## Tips
|
|
549
611
|
|
|
550
612
|
### User Agent
|