got 8.1.0 → 8.3.2

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.
Files changed (3) hide show
  1. package/index.js +115 -59
  2. package/package.json +5 -4
  3. package/readme.md +42 -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
- const progressStream = new Transform({
150
- transform(chunk, encoding, callback) {
151
- downloaded += chunk.length;
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,23 @@ function requestAsEventEmitter(opts) {
227
189
  total: uploadBodySize
228
190
  });
229
191
 
230
- if (req.connection) {
231
- req.connection.once('connect', () => {
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(() => {
201
+ if (socket.destroyed) {
202
+ clearInterval(progressInterval);
203
+ return;
204
+ }
205
+
235
206
  const lastUploaded = uploaded;
236
- const headersSize = Buffer.byteLength(req._header);
237
- uploaded = req.connection.bytesWritten - headersSize;
207
+ const headersSize = req._header ? Buffer.byteLength(req._header) : 0;
208
+ uploaded = socket.bytesWritten - headersSize;
238
209
 
239
210
  // Prevent the known issue of `bytesWritten` being larger than body size
240
211
  if (uploadBodySize && uploaded > uploadBodySize) {
@@ -254,7 +225,17 @@ function requestAsEventEmitter(opts) {
254
225
  total: uploadBodySize
255
226
  });
256
227
  }, uploadEventFrequency);
257
- });
228
+ };
229
+
230
+ // Only subscribe to 'connect' event if we're actually connecting a new
231
+ // socket, otherwise if we're already connected (because this is a
232
+ // keep-alive connection) do not bother. This is important since we won't
233
+ // get a 'connect' event for an already connected socket.
234
+ if (isConnecting) {
235
+ socket.once('connect', onSocketConnect);
236
+ } else {
237
+ onSocketConnect();
238
+ }
258
239
  }
259
240
  });
260
241
 
@@ -273,6 +254,15 @@ function requestAsEventEmitter(opts) {
273
254
  Promise.resolve(getBodySize(opts))
274
255
  .then(size => {
275
256
  uploadBodySize = size;
257
+
258
+ if (
259
+ is.undefined(opts.headers['content-length']) &&
260
+ is.undefined(opts.headers['transfer-encoding']) &&
261
+ isFormData(opts.body)
262
+ ) {
263
+ opts.headers['content-length'] = size;
264
+ }
265
+
276
266
  get(opts);
277
267
  })
278
268
  .catch(err => {
@@ -283,6 +273,61 @@ function requestAsEventEmitter(opts) {
283
273
  return ee;
284
274
  }
285
275
 
276
+ function getResponse(res, opts, ee, redirects) {
277
+ const downloadBodySize = Number(res.headers['content-length']) || null;
278
+ let downloaded = 0;
279
+
280
+ const progressStream = new Transform({
281
+ transform(chunk, encoding, callback) {
282
+ downloaded += chunk.length;
283
+
284
+ const percent = downloadBodySize ? downloaded / downloadBodySize : 0;
285
+
286
+ // Let flush() be responsible for emitting the last event
287
+ if (percent < 1) {
288
+ ee.emit('downloadProgress', {
289
+ percent,
290
+ transferred: downloaded,
291
+ total: downloadBodySize
292
+ });
293
+ }
294
+
295
+ callback(null, chunk);
296
+ },
297
+
298
+ flush(callback) {
299
+ ee.emit('downloadProgress', {
300
+ percent: 1,
301
+ transferred: downloaded,
302
+ total: downloadBodySize
303
+ });
304
+
305
+ callback();
306
+ }
307
+ });
308
+
309
+ mimicResponse(res, progressStream);
310
+ progressStream.redirectUrls = redirects;
311
+
312
+ const response = opts.decompress === true &&
313
+ is.function(decompressResponse) &&
314
+ opts.method !== 'HEAD' ? decompressResponse(progressStream) : progressStream;
315
+
316
+ if (!opts.decompress && ['gzip', 'deflate'].indexOf(res.headers['content-encoding']) !== -1) {
317
+ opts.encoding = null;
318
+ }
319
+
320
+ ee.emit('response', response);
321
+
322
+ ee.emit('downloadProgress', {
323
+ percent: 0,
324
+ transferred: 0,
325
+ total: downloadBodySize
326
+ });
327
+
328
+ res.pipe(progressStream);
329
+ }
330
+
286
331
  function asPromise(opts) {
287
332
  const timeoutFn = requestPromise => opts.gotTimeout && opts.gotTimeout.request ?
288
333
  pTimeout(requestPromise, opts.gotTimeout.request, new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts)) :
@@ -290,7 +335,7 @@ function asPromise(opts) {
290
335
 
291
336
  const proxy = new EventEmitter();
292
337
 
293
- const cancelable = new PCancelable((onCancel, resolve, reject) => {
338
+ const cancelable = new PCancelable((resolve, reject, onCancel) => {
294
339
  const ee = requestAsEventEmitter(opts);
295
340
  let cancelOnRequest = false;
296
341
 
@@ -355,6 +400,14 @@ function asPromise(opts) {
355
400
  ee.on('downloadProgress', proxy.emit.bind(proxy, 'downloadProgress'));
356
401
  });
357
402
 
403
+ // Preserve backwards-compatibility
404
+ // TODO: Remove this in the next major version
405
+ Object.defineProperty(cancelable, 'canceled', {
406
+ get() {
407
+ return cancelable.isCanceled;
408
+ }
409
+ });
410
+
358
411
  const promise = timeoutFn(cancelable);
359
412
 
360
413
  promise.cancel = cancelable.cancel.bind(cancelable);
@@ -485,10 +538,13 @@ function normalizeArguments(url, opts) {
485
538
  }
486
539
 
487
540
  opts.headers = Object.assign({
488
- 'user-agent': `${pkg.name}/${pkg.version} (https://github.com/sindresorhus/got)`,
489
- 'accept-encoding': 'gzip,deflate'
541
+ 'user-agent': `${pkg.name}/${pkg.version} (https://github.com/sindresorhus/got)`
490
542
  }, headers);
491
543
 
544
+ if (opts.decompress && is.undefined(opts.headers['accept-encoding'])) {
545
+ opts.headers['accept-encoding'] = 'gzip, deflate';
546
+ }
547
+
492
548
  const query = opts.query;
493
549
 
494
550
  if (query) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "got",
3
- "version": "8.1.0",
3
+ "version": "8.3.2",
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.3.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.24.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.18.0"
86
+ "xo": "^0.20.0"
86
87
  },
87
88
  "ava": {
88
89
  "concurrency": 4
package/readme.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <br>
3
3
  <br>
4
- <img width="360" src="https://rawgit.com/sindresorhus/got/master/media/logo.svg" alt="got">
4
+ <img width="360" src="media/logo.svg" alt="Got">
5
5
  <br>
6
6
  <br>
7
7
  <br>
@@ -129,7 +129,7 @@ If `content-length` or `transfer-encoding` is not set in `options.headers` and `
129
129
  Type: `string` `null`<br>
130
130
  Default: `'utf8'`
131
131
 
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.
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).
133
133
 
134
134
  ###### form
135
135
 
@@ -195,7 +195,7 @@ request the resource pointed to in the location header via `GET`. This is in acc
195
195
  Type: `boolean`<br>
196
196
  Default: `true`
197
197
 
198
- Decompress the response automatically.
198
+ Decompress the response automatically. This will set the `accept-encoding` header to `gzip, deflate` unless you set it yourself.
199
199
 
200
200
  If this is disabled, a compressed response is returned as a `Buffer`. This may be useful if you want to handle decompression yourself or stream the raw compressed data.
201
201
 
@@ -351,7 +351,7 @@ The promise returned by Got has a [`.cancel()`](https://github.com/sindresorhus/
351
351
  try {
352
352
  await request;
353
353
  } catch (error) {
354
- if (request.canceled) { // Or `error instanceof got.CancelError`
354
+ if (request.isCanceled) { // Or `error instanceof got.CancelError`
355
355
  // Handle cancelation
356
356
  }
357
357
 
@@ -569,6 +569,44 @@ request(`https://${config.host}/production/`, {
569
569
  ```
570
570
 
571
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
+
572
610
  ## Tips
573
611
 
574
612
  ### User Agent