superagent 0.18.2 → 0.21.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/History.md +35 -0
- package/component.json +1 -1
- package/components/component-emitter/component.json +14 -0
- package/components/component-emitter/index.js +164 -0
- package/components/component-reduce/component.json +16 -0
- package/components/component-reduce/index.js +24 -0
- package/lib/client.js +37 -5
- package/lib/node/agent.js +1 -1
- package/lib/node/index.js +55 -8
- package/lib/node/parsers/image.js +7 -5
- package/lib/node/parsers/json.js +7 -4
- package/lib/node/response.js +22 -5
- package/package.json +12 -8
- package/superagent.js +37 -5
- package/docs/head.html +0 -39
- package/docs/index.md +0 -219
- package/docs/tail.html +0 -2
package/History.md
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
0.21.0 / 2014-11-11
|
|
3
|
+
==================
|
|
4
|
+
|
|
5
|
+
* Trim text before parsing json (gjohnson)
|
|
6
|
+
* Update tests to express 4 (gaastonsr)
|
|
7
|
+
* Prevent double callback when error is thrown (pgn-vole)
|
|
8
|
+
* Fix missing clearTimeout (nickdima)
|
|
9
|
+
* Update debug (TooTallNate)
|
|
10
|
+
|
|
11
|
+
0.20.0 / 2014-10-02
|
|
12
|
+
==================
|
|
13
|
+
|
|
14
|
+
* Add toJSON() to request and response instances. (yields)
|
|
15
|
+
* Prevent HEAD requests from getting parsed. (gjohnson)
|
|
16
|
+
* Update debug. (TooTallNate)
|
|
17
|
+
|
|
18
|
+
0.19.1 / 2014-09-24
|
|
19
|
+
==================
|
|
20
|
+
|
|
21
|
+
* Fix basic auth issue when password is falsey value. (gjohnson)
|
|
22
|
+
|
|
23
|
+
0.19.0 / 2014-09-24
|
|
24
|
+
==================
|
|
25
|
+
|
|
26
|
+
* Add unset() to browser. (shesek)
|
|
27
|
+
* Prefer XHR over ActiveX. (omeid)
|
|
28
|
+
* Catch parse errors. (jacwright)
|
|
29
|
+
* Update qs dependency. (wercker)
|
|
30
|
+
* Add use() to node. (Financial-Times)
|
|
31
|
+
* Add response text to errors. (yields)
|
|
32
|
+
* Don't send empty cookie headers. (undoZen)
|
|
33
|
+
* Don't parse empty response bodies. (DveMac)
|
|
34
|
+
* Use hostname when setting cookie host. (prasunsultania)
|
|
35
|
+
|
|
1
36
|
0.18.2 / 2014-07-12
|
|
2
37
|
==================
|
|
3
38
|
|
package/component.json
CHANGED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Expose `Emitter`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = Emitter;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initialize a new `Emitter`.
|
|
10
|
+
*
|
|
11
|
+
* @api public
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
function Emitter(obj) {
|
|
15
|
+
if (obj) return mixin(obj);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Mixin the emitter properties.
|
|
20
|
+
*
|
|
21
|
+
* @param {Object} obj
|
|
22
|
+
* @return {Object}
|
|
23
|
+
* @api private
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
function mixin(obj) {
|
|
27
|
+
for (var key in Emitter.prototype) {
|
|
28
|
+
obj[key] = Emitter.prototype[key];
|
|
29
|
+
}
|
|
30
|
+
return obj;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Listen on the given `event` with `fn`.
|
|
35
|
+
*
|
|
36
|
+
* @param {String} event
|
|
37
|
+
* @param {Function} fn
|
|
38
|
+
* @return {Emitter}
|
|
39
|
+
* @api public
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
Emitter.prototype.on =
|
|
43
|
+
Emitter.prototype.addEventListener = function(event, fn){
|
|
44
|
+
this._callbacks = this._callbacks || {};
|
|
45
|
+
(this._callbacks[event] = this._callbacks[event] || [])
|
|
46
|
+
.push(fn);
|
|
47
|
+
return this;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Adds an `event` listener that will be invoked a single
|
|
52
|
+
* time then automatically removed.
|
|
53
|
+
*
|
|
54
|
+
* @param {String} event
|
|
55
|
+
* @param {Function} fn
|
|
56
|
+
* @return {Emitter}
|
|
57
|
+
* @api public
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
Emitter.prototype.once = function(event, fn){
|
|
61
|
+
var self = this;
|
|
62
|
+
this._callbacks = this._callbacks || {};
|
|
63
|
+
|
|
64
|
+
function on() {
|
|
65
|
+
self.off(event, on);
|
|
66
|
+
fn.apply(this, arguments);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
on.fn = fn;
|
|
70
|
+
this.on(event, on);
|
|
71
|
+
return this;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Remove the given callback for `event` or all
|
|
76
|
+
* registered callbacks.
|
|
77
|
+
*
|
|
78
|
+
* @param {String} event
|
|
79
|
+
* @param {Function} fn
|
|
80
|
+
* @return {Emitter}
|
|
81
|
+
* @api public
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
Emitter.prototype.off =
|
|
85
|
+
Emitter.prototype.removeListener =
|
|
86
|
+
Emitter.prototype.removeAllListeners =
|
|
87
|
+
Emitter.prototype.removeEventListener = function(event, fn){
|
|
88
|
+
this._callbacks = this._callbacks || {};
|
|
89
|
+
|
|
90
|
+
// all
|
|
91
|
+
if (0 == arguments.length) {
|
|
92
|
+
this._callbacks = {};
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// specific event
|
|
97
|
+
var callbacks = this._callbacks[event];
|
|
98
|
+
if (!callbacks) return this;
|
|
99
|
+
|
|
100
|
+
// remove all handlers
|
|
101
|
+
if (1 == arguments.length) {
|
|
102
|
+
delete this._callbacks[event];
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// remove specific handler
|
|
107
|
+
var cb;
|
|
108
|
+
for (var i = 0; i < callbacks.length; i++) {
|
|
109
|
+
cb = callbacks[i];
|
|
110
|
+
if (cb === fn || cb.fn === fn) {
|
|
111
|
+
callbacks.splice(i, 1);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return this;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Emit `event` with the given args.
|
|
120
|
+
*
|
|
121
|
+
* @param {String} event
|
|
122
|
+
* @param {Mixed} ...
|
|
123
|
+
* @return {Emitter}
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
Emitter.prototype.emit = function(event){
|
|
127
|
+
this._callbacks = this._callbacks || {};
|
|
128
|
+
var args = [].slice.call(arguments, 1)
|
|
129
|
+
, callbacks = this._callbacks[event];
|
|
130
|
+
|
|
131
|
+
if (callbacks) {
|
|
132
|
+
callbacks = callbacks.slice(0);
|
|
133
|
+
for (var i = 0, len = callbacks.length; i < len; ++i) {
|
|
134
|
+
callbacks[i].apply(this, args);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return this;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Return array of callbacks for `event`.
|
|
143
|
+
*
|
|
144
|
+
* @param {String} event
|
|
145
|
+
* @return {Array}
|
|
146
|
+
* @api public
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
Emitter.prototype.listeners = function(event){
|
|
150
|
+
this._callbacks = this._callbacks || {};
|
|
151
|
+
return this._callbacks[event] || [];
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Check if this emitter has `event` handlers.
|
|
156
|
+
*
|
|
157
|
+
* @param {String} event
|
|
158
|
+
* @return {Boolean}
|
|
159
|
+
* @api public
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
Emitter.prototype.hasListeners = function(event){
|
|
163
|
+
return !! this.listeners(event).length;
|
|
164
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reduce",
|
|
3
|
+
"repo": "component/reduce",
|
|
4
|
+
"description": "Array reduce component",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"array",
|
|
8
|
+
"reduce"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": {},
|
|
11
|
+
"development": {},
|
|
12
|
+
"license": "Apache, Version 2.0",
|
|
13
|
+
"scripts": [
|
|
14
|
+
"index.js"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Reduce `arr` with `fn`.
|
|
4
|
+
*
|
|
5
|
+
* @param {Array} arr
|
|
6
|
+
* @param {Function} fn
|
|
7
|
+
* @param {Mixed} initial
|
|
8
|
+
*
|
|
9
|
+
* TODO: combatible error handling?
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
module.exports = function(arr, fn, initial){
|
|
13
|
+
var idx = 0;
|
|
14
|
+
var len = arr.length;
|
|
15
|
+
var curr = arguments.length == 3
|
|
16
|
+
? initial
|
|
17
|
+
: arr[idx++];
|
|
18
|
+
|
|
19
|
+
while (idx < len) {
|
|
20
|
+
curr = fn.call(null, curr, arr[idx], ++idx, arr);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return curr;
|
|
24
|
+
};
|
package/lib/client.js
CHANGED
|
@@ -294,7 +294,9 @@ function Response(req, options) {
|
|
|
294
294
|
options = options || {};
|
|
295
295
|
this.req = req;
|
|
296
296
|
this.xhr = this.req.xhr;
|
|
297
|
-
this.text = this.
|
|
297
|
+
this.text = this.req.method !='HEAD'
|
|
298
|
+
? this.xhr.responseText
|
|
299
|
+
: null;
|
|
298
300
|
this.setStatusProperties(this.xhr.status);
|
|
299
301
|
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
|
|
300
302
|
// getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
|
|
@@ -354,7 +356,7 @@ Response.prototype.setHeaderProperties = function(header){
|
|
|
354
356
|
|
|
355
357
|
Response.prototype.parseBody = function(str){
|
|
356
358
|
var parse = request.parse[this.type];
|
|
357
|
-
return parse
|
|
359
|
+
return parse && str && str.length
|
|
358
360
|
? parse(str)
|
|
359
361
|
: null;
|
|
360
362
|
};
|
|
@@ -450,9 +452,18 @@ function Request(method, url) {
|
|
|
450
452
|
this.header = {};
|
|
451
453
|
this._header = {};
|
|
452
454
|
this.on('end', function(){
|
|
453
|
-
var
|
|
454
|
-
|
|
455
|
-
|
|
455
|
+
var err = null;
|
|
456
|
+
var res = null;
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
res = new Response(self);
|
|
460
|
+
} catch(e) {
|
|
461
|
+
err = new Error('Parser is unable to parse the response');
|
|
462
|
+
err.parse = true;
|
|
463
|
+
err.original = e;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
self.callback(err, res);
|
|
456
467
|
});
|
|
457
468
|
}
|
|
458
469
|
|
|
@@ -545,6 +556,26 @@ Request.prototype.set = function(field, val){
|
|
|
545
556
|
return this;
|
|
546
557
|
};
|
|
547
558
|
|
|
559
|
+
/**
|
|
560
|
+
* Remove header `field`.
|
|
561
|
+
*
|
|
562
|
+
* Example:
|
|
563
|
+
*
|
|
564
|
+
* req.get('/')
|
|
565
|
+
* .unset('User-Agent')
|
|
566
|
+
* .end(callback);
|
|
567
|
+
*
|
|
568
|
+
* @param {String} field
|
|
569
|
+
* @return {Request} for chaining
|
|
570
|
+
* @api public
|
|
571
|
+
*/
|
|
572
|
+
|
|
573
|
+
Request.prototype.unset = function(field){
|
|
574
|
+
delete this._header[field.toLowerCase()];
|
|
575
|
+
delete this.header[field];
|
|
576
|
+
return this;
|
|
577
|
+
};
|
|
578
|
+
|
|
548
579
|
/**
|
|
549
580
|
* Get case-insensitive header `field` value.
|
|
550
581
|
*
|
|
@@ -779,6 +810,7 @@ Request.prototype.send = function(data){
|
|
|
779
810
|
|
|
780
811
|
Request.prototype.callback = function(err, res){
|
|
781
812
|
var fn = this._callback;
|
|
813
|
+
this.clearTimeout();
|
|
782
814
|
if (2 == fn.length) return fn(err, res);
|
|
783
815
|
if (err) return this.emit('error', err);
|
|
784
816
|
fn(res);
|
package/lib/node/agent.js
CHANGED
|
@@ -49,7 +49,7 @@ Agent.prototype.saveCookies = function(res){
|
|
|
49
49
|
|
|
50
50
|
Agent.prototype.attachCookies = function(req){
|
|
51
51
|
var url = parse(req.url);
|
|
52
|
-
var access = CookieAccess(url.
|
|
52
|
+
var access = CookieAccess(url.hostname, url.pathname, 'https:' == url.protocol);
|
|
53
53
|
var cookies = this.jar.getCookies(access).toValueString();
|
|
54
54
|
req.cookies = cookies;
|
|
55
55
|
};
|
package/lib/node/index.js
CHANGED
|
@@ -559,6 +559,7 @@ Request.prototype.abort = function(){
|
|
|
559
559
|
this._aborted = true;
|
|
560
560
|
this.clearTimeout();
|
|
561
561
|
this.req.abort();
|
|
562
|
+
this.emit('abort');
|
|
562
563
|
};
|
|
563
564
|
|
|
564
565
|
/**
|
|
@@ -622,6 +623,12 @@ Request.prototype.redirect = function(res){
|
|
|
622
623
|
/**
|
|
623
624
|
* Set Authorization field value with `user` and `pass`.
|
|
624
625
|
*
|
|
626
|
+
* Examples:
|
|
627
|
+
*
|
|
628
|
+
* .auth('tobi', 'learnboost')
|
|
629
|
+
* .auth('tobi:learnboost')
|
|
630
|
+
* .auth('tobi')
|
|
631
|
+
*
|
|
625
632
|
* @param {String} user
|
|
626
633
|
* @param {String} pass
|
|
627
634
|
* @return {Request} for chaining
|
|
@@ -629,8 +636,9 @@ Request.prototype.redirect = function(res){
|
|
|
629
636
|
*/
|
|
630
637
|
|
|
631
638
|
Request.prototype.auth = function(user, pass){
|
|
632
|
-
if (
|
|
633
|
-
|
|
639
|
+
if (1 === arguments.length) pass = '';
|
|
640
|
+
if (!~user.indexOf(':')) user = user + ':';
|
|
641
|
+
var str = new Buffer(user + pass).toString('base64');
|
|
634
642
|
return this.set('Authorization', 'Basic ' + str);
|
|
635
643
|
};
|
|
636
644
|
|
|
@@ -647,6 +655,15 @@ Request.prototype.ca = function(cert){
|
|
|
647
655
|
return this;
|
|
648
656
|
};
|
|
649
657
|
|
|
658
|
+
/**
|
|
659
|
+
* Allow for extension
|
|
660
|
+
*/
|
|
661
|
+
|
|
662
|
+
Request.prototype.use = function(fn) {
|
|
663
|
+
fn(this);
|
|
664
|
+
return this;
|
|
665
|
+
};
|
|
666
|
+
|
|
650
667
|
/**
|
|
651
668
|
* Return an http[s] request.
|
|
652
669
|
*
|
|
@@ -704,7 +721,7 @@ Request.prototype.request = function(){
|
|
|
704
721
|
this.query(url.query);
|
|
705
722
|
|
|
706
723
|
// add cookies
|
|
707
|
-
req.setHeader('Cookie', this.cookies);
|
|
724
|
+
if (this.cookies) req.setHeader('Cookie', this.cookies);
|
|
708
725
|
|
|
709
726
|
// set default UA
|
|
710
727
|
req.setHeader('User-Agent', 'node-superagent/' + pkg.version);
|
|
@@ -801,7 +818,18 @@ Request.prototype.end = function(fn){
|
|
|
801
818
|
var type = type[0];
|
|
802
819
|
var multipart = 'multipart' == type;
|
|
803
820
|
var redirect = isRedirect(res.statusCode);
|
|
804
|
-
var parser = self._parser
|
|
821
|
+
var parser = self._parser;
|
|
822
|
+
|
|
823
|
+
self.res = res;
|
|
824
|
+
|
|
825
|
+
if ('HEAD' == self.method) {
|
|
826
|
+
var response = new Response(self);
|
|
827
|
+
self.response = response;
|
|
828
|
+
response.redirects = self._redirectList;
|
|
829
|
+
self.emit('response', response);
|
|
830
|
+
self.emit('end');
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
805
833
|
|
|
806
834
|
if (self.piped) {
|
|
807
835
|
res.on('end', function(){
|
|
@@ -829,7 +857,8 @@ Request.prototype.end = function(fn){
|
|
|
829
857
|
|
|
830
858
|
form.parse(res, function(err, fields, files){
|
|
831
859
|
if (err) return self.callback(err);
|
|
832
|
-
var response = new Response(
|
|
860
|
+
var response = new Response(self);
|
|
861
|
+
self.response = response;
|
|
833
862
|
response.body = fields;
|
|
834
863
|
response.files = files;
|
|
835
864
|
response.redirects = self._redirectList;
|
|
@@ -843,7 +872,8 @@ Request.prototype.end = function(fn){
|
|
|
843
872
|
if (!parser && isImage(mime)) {
|
|
844
873
|
exports.parse.image(res, function(err, obj){
|
|
845
874
|
if (err) return self.callback(err);
|
|
846
|
-
var response = new Response(
|
|
875
|
+
var response = new Response(self);
|
|
876
|
+
self.response = response;
|
|
847
877
|
response.body = obj;
|
|
848
878
|
response.redirects = self._redirectList;
|
|
849
879
|
self.emit('end');
|
|
@@ -885,7 +915,8 @@ Request.prototype.end = function(fn){
|
|
|
885
915
|
if (!buffer) {
|
|
886
916
|
debug('unbuffered %s %s', self.method, self.url);
|
|
887
917
|
self.res = res;
|
|
888
|
-
var response = new Response(self
|
|
918
|
+
var response = new Response(self);
|
|
919
|
+
self.response = response;
|
|
889
920
|
response.redirects = self._redirectList;
|
|
890
921
|
self.emit('response', response);
|
|
891
922
|
if (multipart) return // allow multipart to handle end event
|
|
@@ -901,7 +932,8 @@ Request.prototype.end = function(fn){
|
|
|
901
932
|
res.on('end', function(){
|
|
902
933
|
debug('end %s %s', self.method, self.url);
|
|
903
934
|
// TODO: unless buffering emit earlier to stream
|
|
904
|
-
var response = new Response(self
|
|
935
|
+
var response = new Response(self);
|
|
936
|
+
self.response = response;
|
|
905
937
|
response.redirects = self._redirectList;
|
|
906
938
|
self.emit('response', response);
|
|
907
939
|
self.emit('end');
|
|
@@ -939,6 +971,21 @@ Request.prototype.end = function(fn){
|
|
|
939
971
|
return this;
|
|
940
972
|
};
|
|
941
973
|
|
|
974
|
+
/**
|
|
975
|
+
* To json.
|
|
976
|
+
*
|
|
977
|
+
* @return {Object}
|
|
978
|
+
* @api public
|
|
979
|
+
*/
|
|
980
|
+
|
|
981
|
+
Request.prototype.toJSON = function(){
|
|
982
|
+
return {
|
|
983
|
+
method: this.method,
|
|
984
|
+
url: this.url,
|
|
985
|
+
data: this._data
|
|
986
|
+
};
|
|
987
|
+
};
|
|
988
|
+
|
|
942
989
|
/**
|
|
943
990
|
* Expose `Request`.
|
|
944
991
|
*/
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
2
1
|
module.exports = function(res, fn){
|
|
3
|
-
var data =
|
|
4
|
-
|
|
2
|
+
var data = []; // Binary data needs binary storage
|
|
3
|
+
|
|
4
|
+
res.on('data', function(chunk){
|
|
5
|
+
data.push(chunk);
|
|
6
|
+
});
|
|
5
7
|
res.on('end', function () {
|
|
6
|
-
|
|
8
|
+
fn(null, Buffer.concat(data));
|
|
7
9
|
});
|
|
8
|
-
};
|
|
10
|
+
};
|
package/lib/node/parsers/json.js
CHANGED
|
@@ -5,9 +5,12 @@ module.exports = function(res, fn){
|
|
|
5
5
|
res.on('data', function(chunk){ res.text += chunk; });
|
|
6
6
|
res.on('end', function(){
|
|
7
7
|
try {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
var text = res.text && res.text.replace(/^\s*|\s*$/g, '');
|
|
9
|
+
var body = text && JSON.parse(text);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
var err = e;
|
|
12
|
+
} finally {
|
|
13
|
+
fn(err, body);
|
|
11
14
|
}
|
|
12
15
|
});
|
|
13
|
-
};
|
|
16
|
+
};
|
package/lib/node/response.js
CHANGED
|
@@ -19,8 +19,7 @@ module.exports = Response;
|
|
|
19
19
|
* - set flags (.ok, .error, etc)
|
|
20
20
|
* - parse header
|
|
21
21
|
*
|
|
22
|
-
* @param {
|
|
23
|
-
* @param {IncomingMessage} res
|
|
22
|
+
* @param {Request} req
|
|
24
23
|
* @param {Object} options
|
|
25
24
|
* @constructor
|
|
26
25
|
* @extends {Stream}
|
|
@@ -28,11 +27,12 @@ module.exports = Response;
|
|
|
28
27
|
* @api private
|
|
29
28
|
*/
|
|
30
29
|
|
|
31
|
-
function Response(req,
|
|
30
|
+
function Response(req, options) {
|
|
32
31
|
Stream.call(this);
|
|
33
32
|
options = options || {};
|
|
34
|
-
this.
|
|
35
|
-
this.
|
|
33
|
+
var res = this.res = req.res;
|
|
34
|
+
this.request = req;
|
|
35
|
+
this.req = req.req;
|
|
36
36
|
this.links = {};
|
|
37
37
|
this.text = res.text;
|
|
38
38
|
this.body = res.body || {};
|
|
@@ -105,6 +105,7 @@ Response.prototype.toError = function(){
|
|
|
105
105
|
var msg = 'cannot ' + method + ' ' + path + ' (' + this.status + ')';
|
|
106
106
|
var err = new Error(msg);
|
|
107
107
|
err.status = this.status;
|
|
108
|
+
err.text = this.text;
|
|
108
109
|
err.method = method;
|
|
109
110
|
err.path = path;
|
|
110
111
|
|
|
@@ -201,3 +202,19 @@ Response.prototype.setStatusProperties = function(status){
|
|
|
201
202
|
this.forbidden = 403 == status;
|
|
202
203
|
this.notFound = 404 == status;
|
|
203
204
|
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* To json.
|
|
208
|
+
*
|
|
209
|
+
* @return {Object}
|
|
210
|
+
* @api public
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
Response.prototype.toJSON = function(){
|
|
214
|
+
return {
|
|
215
|
+
req: this.request.toJSON(),
|
|
216
|
+
header: this.header,
|
|
217
|
+
status: this.status,
|
|
218
|
+
text: this.text
|
|
219
|
+
};
|
|
220
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superagent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "elegant & feature rich browser / node HTTP with a fluent API",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "make test"
|
|
@@ -20,24 +20,28 @@
|
|
|
20
20
|
"url": "git://github.com/visionmedia/superagent.git"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"qs": "
|
|
23
|
+
"qs": "1.2.0",
|
|
24
24
|
"formidable": "1.0.14",
|
|
25
25
|
"mime": "1.2.11",
|
|
26
26
|
"component-emitter": "1.1.2",
|
|
27
27
|
"methods": "1.0.1",
|
|
28
28
|
"cookiejar": "2.0.1",
|
|
29
|
-
"debug": "
|
|
29
|
+
"debug": "2",
|
|
30
30
|
"reduce-component": "1.0.1",
|
|
31
31
|
"extend": "~1.2.1",
|
|
32
32
|
"form-data": "0.1.3",
|
|
33
33
|
"readable-stream": "1.0.27-1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
36
|
+
"basic-auth-connect": "^1.0.0",
|
|
37
|
+
"better-assert": "~1.0.1",
|
|
38
|
+
"body-parser": "^1.9.2",
|
|
39
|
+
"cookie-parser": "^1.3.3",
|
|
40
|
+
"express": "^4.9.8",
|
|
41
|
+
"express-session": "^1.9.1",
|
|
42
|
+
"mocha": "*",
|
|
39
43
|
"should": "3.1.3",
|
|
40
|
-
"
|
|
44
|
+
"zuul": "~1.6.0"
|
|
41
45
|
},
|
|
42
46
|
"browser": {
|
|
43
47
|
"./lib/node/index.js": "./lib/client.js",
|
|
@@ -51,6 +55,6 @@
|
|
|
51
55
|
},
|
|
52
56
|
"main": "./lib/node/index.js",
|
|
53
57
|
"engines": {
|
|
54
|
-
"node": "
|
|
58
|
+
"node": ">= 0.8"
|
|
55
59
|
}
|
|
56
60
|
}
|
package/superagent.js
CHANGED
|
@@ -690,7 +690,9 @@ function Response(req, options) {
|
|
|
690
690
|
options = options || {};
|
|
691
691
|
this.req = req;
|
|
692
692
|
this.xhr = this.req.xhr;
|
|
693
|
-
this.text = this.
|
|
693
|
+
this.text = this.req.method !='HEAD'
|
|
694
|
+
? this.xhr.responseText
|
|
695
|
+
: null;
|
|
694
696
|
this.setStatusProperties(this.xhr.status);
|
|
695
697
|
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
|
|
696
698
|
// getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
|
|
@@ -750,7 +752,7 @@ Response.prototype.setHeaderProperties = function(header){
|
|
|
750
752
|
|
|
751
753
|
Response.prototype.parseBody = function(str){
|
|
752
754
|
var parse = request.parse[this.type];
|
|
753
|
-
return parse
|
|
755
|
+
return parse && str && str.length
|
|
754
756
|
? parse(str)
|
|
755
757
|
: null;
|
|
756
758
|
};
|
|
@@ -846,9 +848,18 @@ function Request(method, url) {
|
|
|
846
848
|
this.header = {};
|
|
847
849
|
this._header = {};
|
|
848
850
|
this.on('end', function(){
|
|
849
|
-
var
|
|
850
|
-
|
|
851
|
-
|
|
851
|
+
var err = null;
|
|
852
|
+
var res = null;
|
|
853
|
+
|
|
854
|
+
try {
|
|
855
|
+
res = new Response(self);
|
|
856
|
+
} catch(e) {
|
|
857
|
+
err = new Error('Parser is unable to parse the response');
|
|
858
|
+
err.parse = true;
|
|
859
|
+
err.original = e;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
self.callback(err, res);
|
|
852
863
|
});
|
|
853
864
|
}
|
|
854
865
|
|
|
@@ -941,6 +952,26 @@ Request.prototype.set = function(field, val){
|
|
|
941
952
|
return this;
|
|
942
953
|
};
|
|
943
954
|
|
|
955
|
+
/**
|
|
956
|
+
* Remove header `field`.
|
|
957
|
+
*
|
|
958
|
+
* Example:
|
|
959
|
+
*
|
|
960
|
+
* req.get('/')
|
|
961
|
+
* .unset('User-Agent')
|
|
962
|
+
* .end(callback);
|
|
963
|
+
*
|
|
964
|
+
* @param {String} field
|
|
965
|
+
* @return {Request} for chaining
|
|
966
|
+
* @api public
|
|
967
|
+
*/
|
|
968
|
+
|
|
969
|
+
Request.prototype.unset = function(field){
|
|
970
|
+
delete this._header[field.toLowerCase()];
|
|
971
|
+
delete this.header[field];
|
|
972
|
+
return this;
|
|
973
|
+
};
|
|
974
|
+
|
|
944
975
|
/**
|
|
945
976
|
* Get case-insensitive header `field` value.
|
|
946
977
|
*
|
|
@@ -1175,6 +1206,7 @@ Request.prototype.send = function(data){
|
|
|
1175
1206
|
|
|
1176
1207
|
Request.prototype.callback = function(err, res){
|
|
1177
1208
|
var fn = this._callback;
|
|
1209
|
+
this.clearTimeout();
|
|
1178
1210
|
if (2 == fn.length) return fn(err, res);
|
|
1179
1211
|
if (err) return this.emit('error', err);
|
|
1180
1212
|
fn(res);
|
package/docs/head.html
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>Superagent</title>
|
|
5
|
-
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
|
|
6
|
-
<style>
|
|
7
|
-
body {
|
|
8
|
-
font: 16px/1.6 "Helvetica Neue", arial, sans-serif;
|
|
9
|
-
padding: 60px;
|
|
10
|
-
}
|
|
11
|
-
pre { font-size: 14px; line-height: 1.3 }
|
|
12
|
-
code .init { color: #2F6FAD }
|
|
13
|
-
code .string { color: #5890AD }
|
|
14
|
-
code .keyword { color: #8A6343 }
|
|
15
|
-
code .number { color: #2F6FAD }
|
|
16
|
-
</style>
|
|
17
|
-
<script>
|
|
18
|
-
$(function(){
|
|
19
|
-
$('code').each(function(){
|
|
20
|
-
$(this).html(highlight($(this).text()));
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
function highlight(js) {
|
|
25
|
-
return js
|
|
26
|
-
.replace(/</g, '<')
|
|
27
|
-
.replace(/>/g, '>')
|
|
28
|
-
.replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
|
|
29
|
-
.replace(/('.*')/gm, '<span class="string">$1</span>')
|
|
30
|
-
.replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
|
|
31
|
-
.replace(/(\d+)/gm, '<span class="number">$1</span>')
|
|
32
|
-
.replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
|
|
33
|
-
.replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
|
|
34
|
-
}
|
|
35
|
-
</script>
|
|
36
|
-
</head>
|
|
37
|
-
<body>
|
|
38
|
-
<h1>Superagent</h1>
|
|
39
|
-
<p>The superagent test suite.</p>
|
package/docs/index.md
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
# SuperAgent
|
|
2
|
-
|
|
3
|
-
Super Agent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs.
|
|
4
|
-
|
|
5
|
-
request
|
|
6
|
-
.post('/api/pet')
|
|
7
|
-
.send({ name: 'Manny', species: 'cat' })
|
|
8
|
-
.set('X-API-Key', 'foobar')
|
|
9
|
-
.set('Accept', 'application/json')
|
|
10
|
-
.end(function(res){
|
|
11
|
-
if (res.ok) {
|
|
12
|
-
alert('yay got ' + JSON.stringify(res.body));
|
|
13
|
-
} else {
|
|
14
|
-
alert('Oh no! error ' + res.text);
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
## Request basics
|
|
19
|
-
|
|
20
|
-
A request can be initiated by invoking the appropriate method on the `request` object, then calling `.end()` to send the request. For example a simple GET request:
|
|
21
|
-
|
|
22
|
-
request
|
|
23
|
-
.get('/search')
|
|
24
|
-
.end(function(res){
|
|
25
|
-
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
The __node__ client may also provide absolute urls:
|
|
29
|
-
|
|
30
|
-
request
|
|
31
|
-
.get('http://example.com/search')
|
|
32
|
-
.end(function(res){
|
|
33
|
-
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
__DELETE__, __HEAD__, __POST__, __PUT__ and other __HTTP__ verbs may also be used, simply change the method name:
|
|
37
|
-
|
|
38
|
-
request
|
|
39
|
-
.head('/favicon.ico')
|
|
40
|
-
.end(function(res){
|
|
41
|
-
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
__DELETE__ is a special-case, as it's a reserved word, so the method is named `.del()`:
|
|
45
|
-
|
|
46
|
-
request
|
|
47
|
-
.del('/user/1')
|
|
48
|
-
.end(function(res){
|
|
49
|
-
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
### Crafting requests
|
|
53
|
-
|
|
54
|
-
SuperAgent's flexible API gives you the granularity you need, _when_ you need, yet more concise variations help reduce the amount of code necessary. For example the following GET request:
|
|
55
|
-
|
|
56
|
-
request
|
|
57
|
-
.get('/search')
|
|
58
|
-
.end(function(res){
|
|
59
|
-
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
Could also be defined as the following, where a callback is given to the HTTP verb method:
|
|
63
|
-
|
|
64
|
-
request
|
|
65
|
-
.get('/search', function(res){
|
|
66
|
-
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
Taking this further the default HTTP verb is __GET__ so the following works as well:
|
|
70
|
-
|
|
71
|
-
request('/search', function(res){
|
|
72
|
-
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
This applies to more complicated requests as well, for example the following __GET__ request with a query-string can be written in the chaining manner:
|
|
76
|
-
|
|
77
|
-
request
|
|
78
|
-
.get('/search')
|
|
79
|
-
.send({ query: 'tobi the ferret' })
|
|
80
|
-
.end(function(res){
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
Or one may pass the query-string object to `.get()`:
|
|
85
|
-
|
|
86
|
-
request
|
|
87
|
-
.get('/search', { query: 'tobi the ferret' })
|
|
88
|
-
.end(function(res){
|
|
89
|
-
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
Taking this even further the callback may be passed as well:
|
|
93
|
-
|
|
94
|
-
request
|
|
95
|
-
.get('/search', { query: 'tobi the ferret' }, function(res){
|
|
96
|
-
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
## Dealing with errors
|
|
100
|
-
|
|
101
|
-
On a network error (e.g. connection refused or timeout), SuperAgent emits
|
|
102
|
-
`error` unless you pass `.end()` a callback with two parameters. Then
|
|
103
|
-
SuperAgent will invoke it with the error first, followed by a null response.
|
|
104
|
-
|
|
105
|
-
request
|
|
106
|
-
.get('http://wrongurl')
|
|
107
|
-
.end(function(err, res){
|
|
108
|
-
console.log('ERROR: ', err)
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
On HTTP errors instead, SuperAgent populates the response with flags
|
|
112
|
-
indicating the error. See `Response status` below.
|
|
113
|
-
|
|
114
|
-
## Setting header fields
|
|
115
|
-
|
|
116
|
-
Setting header fields is simple, invoke `.set()` with a field name and value:
|
|
117
|
-
|
|
118
|
-
request
|
|
119
|
-
.get('/search')
|
|
120
|
-
.set('API-Key', 'foobar')
|
|
121
|
-
.set('Accept', 'application/json')
|
|
122
|
-
.end(callback);
|
|
123
|
-
|
|
124
|
-
## GET requests
|
|
125
|
-
|
|
126
|
-
The `.send()` method accepts objects, which when used with the __GET__ method will form a query-string. The following will produce the path `/search?query=Manny&range=1..5&order=desc`.
|
|
127
|
-
|
|
128
|
-
request
|
|
129
|
-
.get('/search')
|
|
130
|
-
.send({ query: 'Manny' })
|
|
131
|
-
.send({ range: '1..5' })
|
|
132
|
-
.send({ order: 'desc' })
|
|
133
|
-
.end(function(res){
|
|
134
|
-
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
The `.send()` method accepts strings as well:
|
|
138
|
-
|
|
139
|
-
request
|
|
140
|
-
.get('/querystring')
|
|
141
|
-
.send('search=Manny&range=1..5')
|
|
142
|
-
.end(function(res){
|
|
143
|
-
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
### POST / PUT requests
|
|
147
|
-
|
|
148
|
-
A typical JSON __POST__ request might look a little like the following, where we set the Content-Type header field appropriately, and "write" some data, in this case just a JSON string.
|
|
149
|
-
|
|
150
|
-
request.post('/user')
|
|
151
|
-
.set('Content-Type', 'application/json')
|
|
152
|
-
.send('{"name":"tj","pet":"tobi"})
|
|
153
|
-
.end(callback)
|
|
154
|
-
|
|
155
|
-
Since JSON is undoubtably the most common, it's the _default_! The following example is equivalent to the previous.
|
|
156
|
-
|
|
157
|
-
request.post('/user')
|
|
158
|
-
.send({ name: 'tj', pet: 'tobi' })
|
|
159
|
-
.end(callback)
|
|
160
|
-
|
|
161
|
-
Or using multiple `.send()` calls:
|
|
162
|
-
|
|
163
|
-
request.post('/user')
|
|
164
|
-
.send({ name: 'tj' })
|
|
165
|
-
.send({ pet: 'tobi' })
|
|
166
|
-
.end(callback)
|
|
167
|
-
|
|
168
|
-
SuperAgent formats are extensible, however by default "json" and "form" are supported. To send the data as `application/x-www-form-urlencoded` simply invoke `.type()` with "form-data", where the default is "json". This request will POST the body "name=tj&pet=tobi".
|
|
169
|
-
|
|
170
|
-
request.post('/user')
|
|
171
|
-
.type('form')
|
|
172
|
-
.send({ name: 'tj' })
|
|
173
|
-
.send({ pet: 'tobi' })
|
|
174
|
-
.end(callback)
|
|
175
|
-
|
|
176
|
-
## Response properties
|
|
177
|
-
|
|
178
|
-
Many helpful flags and properties are set on the `Response` object, ranging from the response text, parsed response body, header fields, status flags and more.
|
|
179
|
-
|
|
180
|
-
### Response text
|
|
181
|
-
|
|
182
|
-
The `res.text` property contains the unparsed response body string.
|
|
183
|
-
|
|
184
|
-
### Response body
|
|
185
|
-
|
|
186
|
-
Much like SuperAgent can auto-serialize request data, it can also automatically parse it. When a parser is defined for the Content-Type, it is parsed, which by default includes "application/json" and "application/x-www-form-urlencoded". The parsed object is then available via `res.body`.
|
|
187
|
-
|
|
188
|
-
### Response header fields
|
|
189
|
-
|
|
190
|
-
The `res.header` contains an object of parsed header fields, lowercasing field names much like node does. For example `res.header['content-length']`.
|
|
191
|
-
|
|
192
|
-
### Response Content-Type
|
|
193
|
-
|
|
194
|
-
The Content-Type response header is special-cased, providing `res.contentType`, which is void of the charset (if any). For example the Content-Type of "text/html; charset=utf8" will provide "text/html" as `res.contentType`, and the `res.charset` property would then contain "utf8".
|
|
195
|
-
|
|
196
|
-
### Response status
|
|
197
|
-
|
|
198
|
-
The response status flags help determine if the request was a success, among other useful information, making SuperAgent ideal for interacting with RESTful web services. These flags are currently defined as:
|
|
199
|
-
|
|
200
|
-
var type = status / 100 | 0;
|
|
201
|
-
|
|
202
|
-
// status / class
|
|
203
|
-
res.status = status;
|
|
204
|
-
res.statusType = type;
|
|
205
|
-
|
|
206
|
-
// basics
|
|
207
|
-
res.info = 1 == type;
|
|
208
|
-
res.ok = 2 == type;
|
|
209
|
-
res.clientError = 4 == type;
|
|
210
|
-
res.serverError = 5 == type;
|
|
211
|
-
res.error = 4 == type || 5 == type;
|
|
212
|
-
|
|
213
|
-
// sugar
|
|
214
|
-
res.accepted = 202 == status;
|
|
215
|
-
res.noContent = 204 == status || 1223 == status;
|
|
216
|
-
res.badRequest = 400 == status;
|
|
217
|
-
res.unauthorized = 401 == status;
|
|
218
|
-
res.notAcceptable = 406 == status;
|
|
219
|
-
res.notFound = 404 == status;
|
package/docs/tail.html
DELETED