superagent 3.7.0 → 3.8.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.
package/lib/node/index.js CHANGED
@@ -4,30 +4,29 @@
4
4
  * Module dependencies.
5
5
  */
6
6
 
7
- var debug = require('debug')('superagent');
8
- var formidable = require('formidable');
9
- var FormData = require('form-data');
10
- var Response = require('./response');
11
- var parse = require('url').parse;
12
- var format = require('url').format;
13
- var resolve = require('url').resolve;
14
- var methods = require('methods');
15
- var Stream = require('stream');
16
- var utils = require('../utils');
17
- var unzip = require('./unzip').unzip;
18
- var extend = require('extend');
19
- var mime = require('mime');
20
- var https = require('https');
21
- var http = require('http');
22
- var fs = require('fs');
23
- var qs = require('qs');
24
- var zlib = require('zlib');
25
- var util = require('util');
26
- var pkg = require('../../package.json');
27
- var RequestBase = require('../request-base');
28
- var shouldRetry = require('../should-retry');
29
-
30
- var request = exports = module.exports = function(method, url) {
7
+ const debug = require('debug')('superagent');
8
+ const formidable = require('formidable');
9
+ const FormData = require('form-data');
10
+ const Response = require('./response');
11
+ const parse = require('url').parse;
12
+ const format = require('url').format;
13
+ const resolve = require('url').resolve;
14
+ let methods = require('methods');
15
+ const Stream = require('stream');
16
+ const utils = require('../utils');
17
+ const unzip = require('./unzip').unzip;
18
+ const extend = require('extend');
19
+ const mime = require('mime');
20
+ const https = require('https');
21
+ const http = require('http');
22
+ const fs = require('fs');
23
+ const qs = require('qs');
24
+ const zlib = require('zlib');
25
+ const util = require('util');
26
+ const pkg = require('../../package.json');
27
+ const RequestBase = require('../request-base');
28
+
29
+ function request(method, url) {
31
30
  // callback
32
31
  if ('function' == typeof url) {
33
32
  return new exports.Request('GET', method).end(url);
@@ -40,6 +39,7 @@ var request = exports = module.exports = function(method, url) {
40
39
 
41
40
  return new exports.Request(method, url);
42
41
  }
42
+ exports = module.exports = request;
43
43
 
44
44
  /**
45
45
  * Expose `Request`.
@@ -79,7 +79,7 @@ mime.define({
79
79
 
80
80
  exports.protocols = {
81
81
  'http:': http,
82
- 'https:': https
82
+ 'https:': https,
83
83
  };
84
84
 
85
85
  /**
@@ -93,7 +93,7 @@ exports.protocols = {
93
93
 
94
94
  exports.serialize = {
95
95
  'application/x-www-form-urlencoded': qs.stringify,
96
- 'application/json': JSON.stringify
96
+ 'application/json': JSON.stringify,
97
97
  };
98
98
 
99
99
  /**
@@ -114,7 +114,7 @@ exports.parse = require('./parsers');
114
114
  * @api private
115
115
  */
116
116
  function _initHeaders(req) {
117
- var ua = 'node-superagent/' + pkg.version;
117
+ const ua = `node-superagent/${pkg.version}`;
118
118
  req._header = { // coerces header names to lowercase
119
119
  'user-agent': ua
120
120
  };
@@ -164,7 +164,7 @@ RequestBase(Request.prototype);
164
164
  *
165
165
  * ``` js
166
166
  * request.post('http://localhost/upload')
167
- * .attach(new Buffer('<b>Hello world</b>'), 'hello.html')
167
+ * .attach('field', Buffer.from('<b>Hello world</b>'), 'hello.html')
168
168
  * .end(callback);
169
169
  * ```
170
170
  *
@@ -189,7 +189,7 @@ Request.prototype.attach = function(field, file, options){
189
189
  throw Error("superagent can't mix .send() and .attach()");
190
190
  }
191
191
 
192
- var o = options || {};
192
+ let o = options || {};
193
193
  if ('string' == typeof options) {
194
194
  o = { filename: options };
195
195
  }
@@ -210,10 +210,9 @@ Request.prototype.attach = function(field, file, options){
210
210
  Request.prototype._getFormData = function() {
211
211
  if (!this._formData) {
212
212
  this._formData = new FormData();
213
- var that = this;
214
- this._formData.on('error', function(err) {
215
- that.emit('error', err);
216
- that.abort();
213
+ this._formData.on('error', err => {
214
+ this.emit('error', err);
215
+ this.abort();
217
216
  });
218
217
  }
219
218
  return this._formData;
@@ -259,10 +258,11 @@ Request.prototype.agent = function(agent){
259
258
  * @api public
260
259
  */
261
260
 
262
- Request.prototype.type = function(type){
263
- return this.set('Content-Type', ~type.indexOf('/')
264
- ? type
265
- : mime.lookup(type));
261
+ Request.prototype.type = function(type) {
262
+ return this.set(
263
+ 'Content-Type',
264
+ ~type.indexOf('/') ? type : mime.lookup(type)
265
+ );
266
266
  };
267
267
 
268
268
  /**
@@ -324,7 +324,7 @@ Request.prototype.query = function(val){
324
324
  */
325
325
 
326
326
  Request.prototype.write = function(data, encoding){
327
- var req = this.request();
327
+ const req = this.request();
328
328
  if (!this._streamRequest) {
329
329
  this._streamRequest = true;
330
330
  }
@@ -348,25 +348,32 @@ Request.prototype.pipe = function(stream, options){
348
348
  };
349
349
 
350
350
  Request.prototype._pipeContinue = function(stream, options){
351
- var self = this;
352
- this.req.once('response', function(res){
351
+ this.req.once('response', res => {
353
352
  // redirect
354
- var redirect = isRedirect(res.statusCode);
355
- if (redirect && self._redirects++ != self._maxRedirects) {
356
- return self._redirect(res)._pipeContinue(stream, options);
353
+ const redirect = isRedirect(res.statusCode);
354
+ if (redirect && this._redirects++ != this._maxRedirects) {
355
+ return this._redirect(res)._pipeContinue(stream, options);
357
356
  }
358
357
 
359
- self.res = res;
360
- self._emitResponse();
361
- if (self._aborted) return;
358
+ this.res = res;
359
+ this._emitResponse();
360
+ if (this._aborted) return;
362
361
 
363
- if (self._shouldUnzip(res)) {
364
- res.pipe(zlib.createUnzip()).pipe(stream, options);
362
+ if (this._shouldUnzip(res)) {
363
+ const unzipObj = zlib.createUnzip();
364
+ unzipObj.on('error', err => {
365
+ if (err && err.code === 'Z_BUF_ERROR') { // unexpected end of file is ignored by browsers and curl
366
+ stream.emit('end');
367
+ return;
368
+ }
369
+ stream.emit('error', err);
370
+ });
371
+ res.pipe(unzipObj).pipe(stream, options);
365
372
  } else {
366
373
  res.pipe(stream, options);
367
374
  }
368
- res.once('end', function(){
369
- self.emit('end');
375
+ res.once('end', () => {
376
+ this.emit('end');
370
377
  });
371
378
  });
372
379
  return stream;
@@ -394,7 +401,7 @@ Request.prototype.buffer = function(val){
394
401
  */
395
402
 
396
403
  Request.prototype._redirect = function(res){
397
- var url = res.headers.location;
404
+ let url = res.headers.location;
398
405
  if (!url) {
399
406
  return this.callback(new Error('No location header for redirect'), res);
400
407
  }
@@ -408,15 +415,15 @@ Request.prototype._redirect = function(res){
408
415
  // this is required for Node v0.10+
409
416
  res.resume();
410
417
 
411
- var headers = this.req._headers;
418
+ let headers = this.req._headers;
412
419
 
413
- var shouldStripCookie = parse(url).host !== parse(this.url).host;
420
+ const changesOrigin = parse(url).host !== parse(this.url).host;
414
421
 
415
422
  // implementation of 302 following defacto standard
416
423
  if (res.statusCode == 301 || res.statusCode == 302){
417
424
  // strip Content-* related fields
418
425
  // in case of POST etc
419
- headers = utils.cleanHeader(this.req._headers, shouldStripCookie);
426
+ headers = utils.cleanHeader(this.req._headers, changesOrigin);
420
427
 
421
428
  // force GET
422
429
  this.method = 'HEAD' == this.method
@@ -430,7 +437,7 @@ Request.prototype._redirect = function(res){
430
437
  if (res.statusCode == 303) {
431
438
  // strip Content-* related fields
432
439
  // in case of POST etc
433
- headers = utils.cleanHeader(this.req._headers, shouldStripCookie);
440
+ headers = utils.cleanHeader(this.req._headers, changesOrigin);
434
441
 
435
442
  // force method
436
443
  this.method = 'GET';
@@ -446,7 +453,7 @@ Request.prototype._redirect = function(res){
446
453
  delete this._formData;
447
454
 
448
455
  // remove all add header except User-Agent
449
- _initHeaders(this)
456
+ _initHeaders(this);
450
457
 
451
458
  // redirect
452
459
  this._endCalled = false;
@@ -479,19 +486,19 @@ Request.prototype._redirect = function(res){
479
486
 
480
487
  Request.prototype.auth = function(user, pass, options){
481
488
  if (1 === arguments.length) pass = '';
482
- if (2 === arguments.length && typeof pass === 'object') options = pass;
489
+ if (typeof pass === 'object' && pass !== null) { // pass is optional and can be replaced with options
490
+ options = pass;
491
+ pass = '';
492
+ }
483
493
  if (!options) {
484
494
  options = { type: 'basic' };
485
495
  }
486
- switch (options.type) {
487
- case 'bearer':
488
- return this.set('Authorization', 'Bearer ' + user);
489
-
490
- default: // 'basic'
491
- if (!~user.indexOf(':')) user = user + ':';
492
- var str = new Buffer(user + pass).toString('base64');
493
- return this.set('Authorization', 'Basic ' + str);
494
- }
496
+
497
+ var encoder = function(string) {
498
+ return new Buffer(string).toString('base64');
499
+ };
500
+
501
+ return this._auth(user, pass, options, encoder);
495
502
  };
496
503
 
497
504
  /**
@@ -528,8 +535,8 @@ Request.prototype.key = function(cert){
528
535
  * @api public
529
536
  */
530
537
 
531
- Request.prototype.pfx = function(cert){
532
- if(typeof cert === 'object' && !Buffer.isBuffer(cert)){
538
+ Request.prototype.pfx = function(cert) {
539
+ if (typeof cert === 'object' && !Buffer.isBuffer(cert)) {
533
540
  this._pfx = cert.pfx;
534
541
  this._passphrase = cert.passphrase;
535
542
  } else {
@@ -561,11 +568,13 @@ Request.prototype.cert = function(cert){
561
568
  Request.prototype.request = function(){
562
569
  if (this.req) return this.req;
563
570
 
564
- var self = this;
565
- var options = {};
571
+ const options = {};
566
572
 
567
573
  try {
568
- var query = qs.stringify(this.qs, { indices: false, strictNullHandling: true });
574
+ const query = qs.stringify(this.qs, {
575
+ indices: false,
576
+ strictNullHandling: true,
577
+ });
569
578
  if (query) {
570
579
  this.qs = {};
571
580
  this._query.push(query);
@@ -575,20 +584,20 @@ Request.prototype.request = function(){
575
584
  return this.emit('error', e);
576
585
  }
577
586
 
578
- var url = this.url;
579
- var retries = this._retries;
587
+ let url = this.url;
588
+ const retries = this._retries;
580
589
 
581
590
  // default to http://
582
- if (0 != url.indexOf('http')) url = 'http://' + url;
591
+ if (0 != url.indexOf('http')) url = `http://${url}`;
583
592
  url = parse(url);
584
593
 
585
594
  // support unix sockets
586
595
  if (/^https?\+unix:/.test(url.protocol) === true) {
587
596
  // get the protocol
588
- url.protocol = url.protocol.split('+')[0] + ':';
597
+ url.protocol = `${url.protocol.split('+')[0]}:`;
589
598
 
590
599
  // get the socket, path
591
- var unixParts = url.path.match(/^([^/]+)(.+)$/);
600
+ const unixParts = url.path.match(/^([^/]+)(.+)$/);
592
601
  options.socketPath = unixParts[1].replace(/%2F/g, '/');
593
602
  url.path = unixParts[2];
594
603
  }
@@ -606,10 +615,10 @@ Request.prototype.request = function(){
606
615
  options.agent = this._agent;
607
616
 
608
617
  // initiate request
609
- var mod = exports.protocols[url.protocol];
618
+ const mod = exports.protocols[url.protocol];
610
619
 
611
620
  // request
612
- var req = this.req = mod.request(options);
621
+ const req = (this.req = mod.request(options));
613
622
 
614
623
  // set tcp no delay
615
624
  req.setNoDelay(true);
@@ -621,32 +630,35 @@ Request.prototype.request = function(){
621
630
  this.host = url.host;
622
631
 
623
632
  // expose events
624
- req.once('drain', function(){ self.emit('drain'); });
633
+ req.once('drain', () => { this.emit('drain'); });
625
634
 
626
- req.once('error', function(err){
635
+ req.once('error', err => {
627
636
  // flag abortion here for out timeouts
628
637
  // because node will emit a faux-error "socket hang up"
629
638
  // when request is aborted before a connection is made
630
- if (self._aborted) return;
639
+ if (this._aborted) return;
631
640
  // if not the same, we are in the **old** (cancelled) request,
632
641
  // so need to continue (same as for above)
633
- if (self._retries !== retries) return;
642
+ if (this._retries !== retries) return;
634
643
  // if we've received a response then we don't want to let
635
644
  // an error in the request blow up the response
636
- if (self.response) return;
637
- self.callback(err);
645
+ if (this.response) return;
646
+ this.callback(err);
638
647
  });
639
648
 
640
649
  // auth
641
650
  if (url.auth) {
642
- var auth = url.auth.split(':');
651
+ const auth = url.auth.split(':');
643
652
  this.auth(auth[0], auth[1]);
644
653
  }
654
+ if (this.username && this.password) {
655
+ this.auth(this.username, this.password);
656
+ }
645
657
 
646
658
  // add cookies
647
659
  if (this.cookies) req.setHeader('Cookie', this.cookies);
648
660
 
649
- for (var key in this.header) {
661
+ for (const key in this.header) {
650
662
  if (this.header.hasOwnProperty(key))
651
663
  req.setHeader(key, this.header[key]);
652
664
  }
@@ -664,33 +676,35 @@ Request.prototype.request = function(){
664
676
  */
665
677
 
666
678
  Request.prototype.callback = function(err, res){
667
- // console.log(this._retries, this._maxRetries)
668
- if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) {
679
+ if (this._shouldRetry(err, res)) {
669
680
  return this._retry();
670
681
  }
671
682
 
672
683
  // Avoid the error which is emitted from 'socket hang up' to cause the fn undefined error on JS runtime.
673
- var fn = this._callback || noop;
684
+ const fn = this._callback || noop;
674
685
  this.clearTimeout();
675
686
  if (this.called) return console.warn('superagent: double callback bug');
676
687
  this.called = true;
677
688
 
678
689
  if (!err) {
679
690
  try {
680
- if (this._isResponseOK(res)) {
681
- return fn(err, res);
682
- }
683
-
684
- var msg = 'Unsuccessful HTTP response';
685
- if (res) {
686
- msg = http.STATUS_CODES[res.status] || msg;
691
+ if (!this._isResponseOK(res)) {
692
+ let msg = 'Unsuccessful HTTP response';
693
+ if (res) {
694
+ msg = http.STATUS_CODES[res.status] || msg;
695
+ }
696
+ err = new Error(msg);
697
+ err.status = res ? res.status : undefined;
687
698
  }
688
- err = new Error(msg);
689
- err.status = res ? res.status : undefined;
690
699
  } catch (new_err) {
691
700
  err = new_err;
692
701
  }
693
702
  }
703
+ // It's important that the callback is called outside try/catch
704
+ // to avoid double callback
705
+ if (!err) {
706
+ return fn(null, res);
707
+ }
694
708
 
695
709
  err.response = res;
696
710
  if (this._maxRetries) err.retries = this._retries - 1;
@@ -724,24 +738,26 @@ Request.prototype._isHost = function _isHost(obj) {
724
738
  * @api public
725
739
  */
726
740
 
727
- Request.prototype._emitResponse = function(body, files){
728
- var response = new Response(this);
729
- this.response = response;
730
- response.redirects = this._redirectList;
731
- if (undefined !== body) {
732
- response.body = body;
733
- }
734
- response.files = files;
735
- this.emit('response', response);
736
- return response;
741
+ Request.prototype._emitResponse = function(body, files) {
742
+ const response = new Response(this);
743
+ this.response = response;
744
+ response.redirects = this._redirectList;
745
+ if (undefined !== body) {
746
+ response.body = body;
747
+ }
748
+ response.files = files;
749
+ this.emit('response', response);
750
+ return response;
737
751
  };
738
752
 
739
- Request.prototype.end = function(fn){
753
+ Request.prototype.end = function(fn) {
740
754
  this.request();
741
755
  debug('%s %s', this.method, this.url);
742
756
 
743
757
  if (this._endCalled) {
744
- console.warn("Warning: .end() was called twice. This is not supported in superagent");
758
+ console.warn(
759
+ 'Warning: .end() was called twice. This is not supported in superagent'
760
+ );
745
761
  }
746
762
  this._endCalled = true;
747
763
 
@@ -752,11 +768,10 @@ Request.prototype.end = function(fn){
752
768
  };
753
769
 
754
770
  Request.prototype._end = function() {
755
- var self = this;
756
- var data = this._data;
757
- var req = this.req;
758
- var buffer = this._buffer;
759
- var method = this.method;
771
+ let data = this._data;
772
+ const req = this.req;
773
+ let buffer = this._buffer;
774
+ const method = this.method;
760
775
 
761
776
  this._setTimeouts();
762
777
 
@@ -764,10 +779,10 @@ Request.prototype._end = function() {
764
779
  if ('HEAD' != method && !req._headerSent) {
765
780
  // serialize stuff
766
781
  if ('string' != typeof data) {
767
- var contentType = req.getHeader('Content-Type')
782
+ let contentType = req.getHeader('Content-Type');
768
783
  // Parse out just the content type from the header (ignore the charset)
769
- if (contentType) contentType = contentType.split(';')[0]
770
- var serialize = exports.serialize[contentType];
784
+ if (contentType) contentType = contentType.split(';')[0];
785
+ let serialize = exports.serialize[contentType];
771
786
  if (!serialize && isJSON(contentType)) {
772
787
  serialize = exports.serialize['application/json'];
773
788
  }
@@ -781,40 +796,40 @@ Request.prototype._end = function() {
781
796
  }
782
797
 
783
798
  // response
784
- req.once('response', function(res){
785
- debug('%s %s -> %s', self.method, self.url, res.statusCode);
799
+ req.once('response', res => {
800
+ debug('%s %s -> %s', this.method, this.url, res.statusCode);
786
801
 
787
- if (self._responseTimeoutTimer) {
788
- clearTimeout(self._responseTimeoutTimer);
802
+ if (this._responseTimeoutTimer) {
803
+ clearTimeout(this._responseTimeoutTimer);
789
804
  }
790
805
 
791
- if (self.piped) {
806
+ if (this.piped) {
792
807
  return;
793
808
  }
794
809
 
795
- var max = self._maxRedirects;
796
- var mime = utils.type(res.headers['content-type'] || '') || 'text/plain';
797
- var type = mime.split('/')[0];
798
- var multipart = 'multipart' == type;
799
- var redirect = isRedirect(res.statusCode);
800
- var parser = self._parser;
801
- var responseType = self._responseType;
810
+ const max = this._maxRedirects;
811
+ const mime = utils.type(res.headers['content-type'] || '') || 'text/plain';
812
+ const type = mime.split('/')[0];
813
+ const multipart = 'multipart' == type;
814
+ const redirect = isRedirect(res.statusCode);
815
+ let parser = this._parser;
816
+ const responseType = this._responseType;
802
817
 
803
- self.res = res;
818
+ this.res = res;
804
819
 
805
820
  // redirect
806
- if (redirect && self._redirects++ != max) {
807
- return self._redirect(res);
821
+ if (redirect && this._redirects++ != max) {
822
+ return this._redirect(res);
808
823
  }
809
824
 
810
- if ('HEAD' == self.method) {
811
- self.emit('end');
812
- self.callback(null, self._emitResponse());
825
+ if ('HEAD' == this.method) {
826
+ this.emit('end');
827
+ this.callback(null, this._emitResponse());
813
828
  return;
814
829
  }
815
830
 
816
831
  // zlib support
817
- if (self._shouldUnzip(res)) {
832
+ if (this._shouldUnzip(res)) {
818
833
  unzip(req, res);
819
834
  }
820
835
 
@@ -823,7 +838,7 @@ Request.prototype._end = function() {
823
838
  parser = exports.parse.image; // It's actually a generic Buffer
824
839
  buffer = true;
825
840
  } else if (multipart) {
826
- var form = new formidable.IncomingForm();
841
+ const form = new formidable.IncomingForm();
827
842
  parser = form.parse.bind(form);
828
843
  buffer = true;
829
844
  } else if (isImageOrVideo(mime)) {
@@ -845,15 +860,15 @@ Request.prototype._end = function() {
845
860
  }
846
861
 
847
862
  // by default only buffer text/*, json and messed up thing from hell
848
- if (undefined === buffer && isText(mime) || isJSON(mime)) {
863
+ if ((undefined === buffer && isText(mime)) || isJSON(mime)) {
849
864
  buffer = true;
850
865
  }
851
866
 
852
- var parserHandlesEnd = false;
867
+ let parserHandlesEnd = false;
853
868
  if (buffer) {
854
869
  // Protectiona against zip bombs and other nuisance
855
- let responseBytesLeft = self._maxResponseSize || 200000000;
856
- res.on('data', function(buf) {
870
+ let responseBytesLeft = this._maxResponseSize || 200000000;
871
+ res.on('data', buf => {
857
872
  responseBytesLeft -= buf.byteLength || buf.length;
858
873
  if (responseBytesLeft < 0) {
859
874
  // This will propagate through error event
@@ -874,71 +889,72 @@ Request.prototype._end = function() {
874
889
  // which is weird BTW, because response.body won't be there.
875
890
  parserHandlesEnd = buffer;
876
891
 
877
- parser(res, function(err, obj, files) {
878
- if (self.timedout) {
892
+ parser(res, (err, obj, files) => {
893
+ if (this.timedout) {
879
894
  // Timeout has already handled all callbacks
880
895
  return;
881
896
  }
882
897
 
883
898
  // Intentional (non-timeout) abort is supposed to preserve partial response,
884
899
  // even if it doesn't parse.
885
- if (err && !self._aborted) {
886
- return self.callback(err);
900
+ if (err && !this._aborted) {
901
+ return this.callback(err);
887
902
  }
888
903
 
889
904
  if (parserHandlesEnd) {
890
- self.emit('end');
891
- self.callback(null, self._emitResponse(obj, files));
905
+ this.emit('end');
906
+ this.callback(null, this._emitResponse(obj, files));
892
907
  }
893
908
  });
894
909
  } catch (err) {
895
- self.callback(err);
910
+ this.callback(err);
896
911
  return;
897
912
  }
898
913
  }
899
914
 
900
- self.res = res;
915
+ this.res = res;
901
916
 
902
917
  // unbuffered
903
918
  if (!buffer) {
904
- debug('unbuffered %s %s', self.method, self.url);
905
- self.callback(null, self._emitResponse());
906
- if (multipart) return // allow multipart to handle end event
907
- res.once('end', function(){
908
- debug('end %s %s', self.method, self.url);
909
- self.emit('end');
910
- })
919
+ debug('unbuffered %s %s', this.method, this.url);
920
+ this.callback(null, this._emitResponse());
921
+ if (multipart) return; // allow multipart to handle end event
922
+ res.once('end', () => {
923
+ debug('end %s %s', this.method, this.url);
924
+ this.emit('end');
925
+ });
911
926
  return;
912
927
  }
913
928
 
914
929
  // terminating events
915
- res.once('error', function(err){
930
+ res.once('error', err => {
916
931
  parserHandlesEnd = false;
917
- self.callback(err, null);
918
- });
919
- if (!parserHandlesEnd) res.once('end', function(){
920
- debug('end %s %s', self.method, self.url);
921
- // TODO: unless buffering emit earlier to stream
922
- self.emit('end');
923
- self.callback(null, self._emitResponse());
932
+ this.callback(err, null);
924
933
  });
934
+ if (!parserHandlesEnd)
935
+ res.once('end', () => {
936
+ debug('end %s %s', this.method, this.url);
937
+ // TODO: unless buffering emit earlier to stream
938
+ this.emit('end');
939
+ this.callback(null, this._emitResponse());
940
+ });
925
941
  });
926
942
 
927
943
  this.emit('request', this);
928
944
 
929
945
  // if a FormData instance got created, then we send that as the request body
930
- var formData = this._formData;
946
+ const formData = this._formData;
931
947
  if (formData) {
932
948
 
933
949
  // set headers
934
- var headers = formData.getHeaders();
935
- for (var i in headers) {
950
+ const headers = formData.getHeaders();
951
+ for (const i in headers) {
936
952
  debug('setting FormData header: "%s: %s"', i, headers[i]);
937
953
  req.setHeader(i, headers[i]);
938
954
  }
939
955
 
940
956
  // attempt to get "Content-Length" header
941
- formData.getLength(function(err, length) {
957
+ formData.getLength((err, length) => {
942
958
  // TODO: Add chunked encoding when no length (if err)
943
959
 
944
960
  debug('got FormData Content-Length: %s', length);
@@ -946,19 +962,19 @@ Request.prototype._end = function() {
946
962
  req.setHeader('Content-Length', length);
947
963
  }
948
964
 
949
- var getProgressMonitor = function () {
950
- var lengthComputable = true;
951
- var total = req.getHeader('Content-Length');
952
- var loaded = 0;
965
+ const getProgressMonitor = () => {
966
+ const lengthComputable = true;
967
+ const total = req.getHeader('Content-Length');
968
+ let loaded = 0;
953
969
 
954
- var progress = new Stream.Transform();
955
- progress._transform = function (chunk, encoding, cb) {
970
+ const progress = new Stream.Transform();
971
+ progress._transform = (chunk, encoding, cb) => {
956
972
  loaded += chunk.length;
957
- self.emit('progress', {
973
+ this.emit('progress', {
958
974
  direction: 'upload',
959
- lengthComputable: lengthComputable,
960
- loaded: loaded,
961
- total: total
975
+ lengthComputable,
976
+ loaded,
977
+ total,
962
978
  });
963
979
  cb(null, chunk);
964
980
  };
@@ -976,7 +992,7 @@ Request.prototype._end = function() {
976
992
  /**
977
993
  * Check whether response has a non-0-sized gzip-encoded body
978
994
  */
979
- Request.prototype._shouldUnzip = function(res){
995
+ Request.prototype._shouldUnzip = res => {
980
996
  if (res.statusCode === 204 || res.statusCode === 304) {
981
997
  // These aren't supposed to have any body
982
998
  return false;
@@ -1000,14 +1016,14 @@ if (methods.indexOf('del') == -1) {
1000
1016
  methods = methods.slice(0);
1001
1017
  methods.push('del');
1002
1018
  }
1003
- methods.forEach(function(method){
1004
- var name = method;
1019
+ methods.forEach(method => {
1020
+ const name = method;
1005
1021
  method = 'del' == method ? 'delete' : method;
1006
1022
 
1007
1023
  method = method.toUpperCase();
1008
- request[name] = function(url, data, fn){
1009
- var req = request(method, url);
1010
- if ('function' == typeof data) fn = data, data = null;
1024
+ request[name] = (url, data, fn) => {
1025
+ const req = request(method, url);
1026
+ if ('function' == typeof data) (fn = data), (data = null);
1011
1027
  if (data) {
1012
1028
  if (method === 'GET' || method === 'HEAD') {
1013
1029
  req.query(data);
@@ -1029,16 +1045,15 @@ methods.forEach(function(method){
1029
1045
  */
1030
1046
 
1031
1047
  function isText(mime) {
1032
- var parts = mime.split('/');
1033
- var type = parts[0];
1034
- var subtype = parts[1];
1048
+ const parts = mime.split('/');
1049
+ const type = parts[0];
1050
+ const subtype = parts[1];
1035
1051
 
1036
- return 'text' == type
1037
- || 'x-www-form-urlencoded' == subtype;
1052
+ return 'text' == type || 'x-www-form-urlencoded' == subtype;
1038
1053
  }
1039
1054
 
1040
1055
  function isImageOrVideo(mime) {
1041
- var type = mime.split('/')[0];
1056
+ const type = mime.split('/')[0];
1042
1057
 
1043
1058
  return 'image' == type || 'video' == type;
1044
1059
  }
@@ -1052,7 +1067,9 @@ function isImageOrVideo(mime) {
1052
1067
  */
1053
1068
 
1054
1069
  function isJSON(mime) {
1055
- return /[\/+]json\b/.test(mime);
1070
+ // should match /json or +json
1071
+ // but not /json-seq
1072
+ return /[\/+]json($|[^-\w])/.test(mime);
1056
1073
  }
1057
1074
 
1058
1075
  /**