superagent 2.0.0 → 2.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/lib/node/index.js CHANGED
@@ -352,10 +352,7 @@ Request.prototype.pipe = function(stream, options){
352
352
  }
353
353
 
354
354
  self.res = res;
355
- var response = new Response(self);
356
- self.response = response;
357
- self.emit('response', response);
358
- response.redirects = self._redirectList;
355
+ self._emitResponse();
359
356
  if (self._aborted) return;
360
357
 
361
358
  if (self._shouldUnzip(res)) {
@@ -379,9 +376,7 @@ Request.prototype.pipe = function(stream, options){
379
376
  */
380
377
 
381
378
  Request.prototype.buffer = function(val){
382
- this._buffer = false === val
383
- ? false
384
- : true;
379
+ this._buffer = (false !== val);
385
380
  return this;
386
381
  };
387
382
 
@@ -494,6 +489,32 @@ Request.prototype.ca = function(cert){
494
489
  return this;
495
490
  };
496
491
 
492
+ /**
493
+ * Set the client certificate key option for https request.
494
+ *
495
+ * @param {Buffer | String} cert
496
+ * @return {Request} for chaining
497
+ * @api public
498
+ */
499
+
500
+ Request.prototype.key = function(cert){
501
+ this._key = cert;
502
+ return this;
503
+ };
504
+
505
+ /**
506
+ * Set the client certificate option for https request.
507
+ *
508
+ * @param {Buffer | String} cert
509
+ * @return {Request} for chaining
510
+ * @api public
511
+ */
512
+
513
+ Request.prototype.cert = function(cert){
514
+ this._cert = cert;
515
+ return this;
516
+ };
517
+
497
518
  /**
498
519
  * Return an http[s] request.
499
520
  *
@@ -519,6 +540,8 @@ Request.prototype.request = function(){
519
540
  options.path = url.pathname;
520
541
  options.host = url.hostname;
521
542
  options.ca = this._ca;
543
+ options.key = this._key;
544
+ options.cert = this._cert;
522
545
  options.agent = this._agent;
523
546
 
524
547
  // initiate request
@@ -616,7 +639,7 @@ Request.prototype.callback = function(err, res){
616
639
  */
617
640
 
618
641
  Request.prototype._appendQueryString = function(req){
619
- var querystring = qs.stringify(this.qs, { indices: false });
642
+ var querystring = qs.stringify(this.qs, { indices: false, strictNullHandling: true });
620
643
  querystring += ((querystring.length && this.qsRaw.length) ? '&' : '') + this.qsRaw.join('&');
621
644
  req.path += querystring.length
622
645
  ? (~req.path.indexOf('?') ? '&' : '?') + querystring
@@ -632,6 +655,18 @@ Request.prototype._appendQueryString = function(req){
632
655
  * @api public
633
656
  */
634
657
 
658
+ Request.prototype._emitResponse = function(body, files){
659
+ var response = new Response(this);
660
+ this.response = response;
661
+ response.redirects = this._redirectList;
662
+ if (undefined !== body) {
663
+ response.body = body;
664
+ }
665
+ response.files = files;
666
+ this.emit('response', response);
667
+ return response;
668
+ };
669
+
635
670
  Request.prototype.end = function(fn){
636
671
  var self = this;
637
672
  var data = this._data;
@@ -658,6 +693,7 @@ Request.prototype.end = function(fn){
658
693
  var err = new Error('timeout of ' + timeout + 'ms exceeded');
659
694
  err.timeout = timeout;
660
695
  err.code = 'ECONNABORTED';
696
+ self.timedout = true;
661
697
  self.abort();
662
698
  self.callback(err);
663
699
  }, timeout);
@@ -691,10 +727,7 @@ Request.prototype.end = function(fn){
691
727
 
692
728
  var max = self._maxRedirects;
693
729
  var mime = utils.type(res.headers['content-type'] || '') || 'text/plain';
694
- var len = res.headers['content-length'];
695
- var type = mime.split('/');
696
- var subtype = type[1];
697
- var type = type[0];
730
+ var type = mime.split('/')[0];
698
731
  var multipart = 'multipart' == type;
699
732
  var redirect = isRedirect(res.statusCode);
700
733
  var parser = self._parser;
@@ -707,12 +740,8 @@ Request.prototype.end = function(fn){
707
740
  }
708
741
 
709
742
  if ('HEAD' == self.method) {
710
- var response = new Response(self);
711
- self.response = response;
712
- response.redirects = self._redirectList;
713
- self.emit('response', response);
714
- self.callback(null, response);
715
743
  self.emit('end');
744
+ self.callback(null, self._emitResponse());
716
745
  return;
717
746
  }
718
747
 
@@ -721,64 +750,50 @@ Request.prototype.end = function(fn){
721
750
  utils.unzip(req, res);
722
751
  }
723
752
 
724
-
725
- // don't buffer multipart
726
- if (multipart) buffer = false;
727
-
728
- // TODO: make all parsers take callbacks
729
- if (!parser && multipart) {
730
- var form = new formidable.IncomingForm;
731
-
732
- form.parse(res, function(err, fields, files){
733
- if (err) return self.callback(err);
734
- var response = new Response(self);
735
- self.response = response;
736
- response.body = fields;
737
- response.files = files;
738
- response.redirects = self._redirectList;
739
- self.emit('end');
740
- self.callback(null, response);
741
- });
742
- return;
743
- }
744
-
745
- // check for images, one more special treatment
746
- if (!parser && isImage(mime)) {
747
- exports.parse.image(res, function(err, obj){
748
- if (err) return self.callback(err);
749
- var response = new Response(self);
750
- self.response = response;
751
- response.body = obj;
752
- response.redirects = self._redirectList;
753
- self.emit('end');
754
- self.callback(null, response);
755
- });
756
- return;
753
+ if (!parser) {
754
+ if (multipart) {
755
+ var form = new formidable.IncomingForm();
756
+ parser = form.parse.bind(form);
757
+ buffer = true;
758
+ } else if (isImage(mime)) {
759
+ parser = exports.parse.image;
760
+ buffer = true; // For backwards-compatibility buffering default is ad-hoc MIME-dependent
761
+ } else if ('text' == type) {
762
+ parser = exports.parse.text;
763
+ buffer = (buffer !== false);
764
+ } else if (exports.parse[mime]) {
765
+ parser = exports.parse[mime];
766
+
767
+ // everyone wants their own white-labeled json
768
+ } else if (isJSON(mime)) {
769
+ parser = exports.parse['application/json'];
770
+ buffer = (buffer !== false);
771
+ } else if (buffer) {
772
+ parser = exports.parse.text;
773
+ }
757
774
  }
758
775
 
759
776
  // by default only buffer text/*, json and messed up thing from hell
760
- if (null == buffer && isText(mime) || isJSON(mime)) buffer = true;
761
-
762
- // parser
763
- var parse = 'text' == type
764
- ? exports.parse.text
765
- : exports.parse[mime];
777
+ if (undefined === buffer && isText(mime) || isJSON(mime)) buffer = true;
766
778
 
767
- // everyone wants their own white-labeled json
768
- if (!parse && isJSON(mime)) parse = exports.parse['application/json'];
779
+ var parserHandlesEnd = false;
780
+ if (parser) {
781
+ try {
782
+ // Unbuffered parsers are supposed to emit response early,
783
+ // which is weird BTW, because response.body won't be there.
784
+ parserHandlesEnd = buffer;
769
785
 
770
- // buffered response
771
- if (buffer) parse = parse || exports.parse.text;
786
+ parser(res, function(err, obj, files) {
787
+ if (err && !self._aborted) {
788
+ return self.callback(err);
789
+ }
772
790
 
773
- // explicit parser
774
- if (parser) parse = parser;
791
+ res.body = obj; // Deprecated. For backwards compat only. It's not the response object user sees.
775
792
 
776
- // parse
777
- if (parse) {
778
- try {
779
- parse(res, function(err, obj){
780
- if (err && !self._aborted) self.callback(err);
781
- res.body = obj;
793
+ if (parserHandlesEnd) {
794
+ self.emit('end');
795
+ self.callback(null, self._emitResponse(obj, files));
796
+ }
782
797
  });
783
798
  } catch (err) {
784
799
  self.callback(err);
@@ -786,15 +801,12 @@ Request.prototype.end = function(fn){
786
801
  }
787
802
  }
788
803
 
804
+ self.res = res;
805
+
789
806
  // unbuffered
790
807
  if (!buffer) {
791
808
  debug('unbuffered %s %s', self.method, self.url);
792
- self.res = res;
793
- var response = new Response(self);
794
- self.response = response;
795
- response.redirects = self._redirectList;
796
- self.emit('response', response);
797
- self.callback(null, response);
809
+ self.callback(null, self._emitResponse());
798
810
  if (multipart) return // allow multipart to handle end event
799
811
  res.on('end', function(){
800
812
  debug('end %s %s', self.method, self.url);
@@ -804,19 +816,14 @@ Request.prototype.end = function(fn){
804
816
  }
805
817
 
806
818
  // terminating events
807
- self.res = res;
808
819
  res.on('error', function(err){
809
820
  self.callback(err, null);
810
821
  });
811
- res.on('end', function(){
822
+ if (!parserHandlesEnd) res.on('end', function(){
812
823
  debug('end %s %s', self.method, self.url);
813
824
  // TODO: unless buffering emit earlier to stream
814
- var response = new Response(self);
815
- self.response = response;
816
- response.redirects = self._redirectList;
817
- self.emit('response', response);
818
- self.callback(null, response);
819
825
  self.emit('end');
826
+ self.callback(null, self._emitResponse());
820
827
  });
821
828
  });
822
829
 
package/lib/node/utils.js CHANGED
@@ -83,6 +83,10 @@ exports.unzip = function(req, res){
83
83
  stream.req = req;
84
84
 
85
85
  unzip.on('error', function(err){
86
+ if (err && err.code === 'Z_BUF_ERROR') { // unexpected end of file is ignored by browsers and curl
87
+ stream.emit('end');
88
+ return;
89
+ }
86
90
  stream.emit('error', err);
87
91
  });
88
92
 
@@ -119,6 +123,7 @@ exports.unzip = function(req, res){
119
123
  } else {
120
124
  _on.call(res, type, fn);
121
125
  }
126
+ return this;
122
127
  };
123
128
  };
124
129
 
@@ -77,6 +77,10 @@ exports.then = function then(resolve, reject) {
77
77
  return this._fullfilledPromise.then(resolve, reject);
78
78
  }
79
79
 
80
+ exports.catch = function(cb) {
81
+ return this.then(undefined, cb);
82
+ };
83
+
80
84
  /**
81
85
  * Allow for extension
82
86
  */
@@ -166,21 +170,42 @@ exports.unset = function(field){
166
170
  };
167
171
 
168
172
  /**
169
- * Write the field `name` and `val` for "multipart/form-data"
170
- * request bodies.
173
+ * Write the field `name` and `val`, or multiple fields with one object
174
+ * for "multipart/form-data" request bodies.
171
175
  *
172
176
  * ``` js
173
177
  * request.post('/upload')
174
178
  * .field('foo', 'bar')
175
179
  * .end(callback);
180
+ *
181
+ * request.post('/upload')
182
+ * .field({ foo: 'bar', baz: 'qux' })
183
+ * .end(callback);
176
184
  * ```
177
185
  *
178
- * @param {String} name
186
+ * @param {String|Object} name
179
187
  * @param {String|Blob|File|Buffer|fs.ReadStream} val
180
188
  * @return {Request} for chaining
181
189
  * @api public
182
190
  */
183
191
  exports.field = function(name, val) {
192
+
193
+ // name should be either a string or an object.
194
+ if (null === name || undefined === name) {
195
+ throw new Error('.field(name, val) name can not be empty');
196
+ }
197
+
198
+ if (isObject(name)) {
199
+ for (var key in name) {
200
+ this.field(key, name[key]);
201
+ }
202
+ return this;
203
+ }
204
+
205
+ // val should be defined now
206
+ if (null === val || undefined === val) {
207
+ throw new Error('.field(name, val) val can not be empty');
208
+ }
184
209
  this._getFormData().append(name, val);
185
210
  return this;
186
211
  };
@@ -246,7 +271,8 @@ exports.toJSON = function(){
246
271
  return {
247
272
  method: this.method,
248
273
  url: this.url,
249
- data: this._data
274
+ data: this._data,
275
+ headers: this._header
250
276
  };
251
277
  };
252
278
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "superagent",
3
- "version": "2.0.0",
3
+ "version": "2.3.0",
4
4
  "description": "elegant & feature rich browser / node HTTP with a fluent API",
5
5
  "scripts": {
6
6
  "prepublish": "make all",
@@ -31,7 +31,6 @@
31
31
  "methods": "^1.1.1",
32
32
  "cookiejar": "^2.0.6",
33
33
  "debug": "^2.2.0",
34
- "reduce-component": "^1.0.1",
35
34
  "extend": "^3.0.0",
36
35
  "form-data": "1.0.0-rc4",
37
36
  "readable-stream": "^2.0.5"
@@ -54,7 +53,6 @@
54
53
  "browser": {
55
54
  "./lib/node/index.js": "./lib/client.js",
56
55
  "emitter": "component-emitter",
57
- "reduce": "reduce-component",
58
56
  "./test/support/server.js": "./test/support/blank.js"
59
57
  },
60
58
  "component": {