]> git.immae.eu Git - perso/Immae/Projets/Nodejs/Surfer.git/blob - frontend/js/superagent.js
Use custom public folder listing
[perso/Immae/Projets/Nodejs/Surfer.git] / frontend / js / superagent.js
1 !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.superagent=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
3 /**
4 * Expose `Emitter`.
5 */
6
7 module.exports = Emitter;
8
9 /**
10 * Initialize a new `Emitter`.
11 *
12 * @api public
13 */
14
15 function Emitter(obj) {
16 if (obj) return mixin(obj);
17 };
18
19 /**
20 * Mixin the emitter properties.
21 *
22 * @param {Object} obj
23 * @return {Object}
24 * @api private
25 */
26
27 function mixin(obj) {
28 for (var key in Emitter.prototype) {
29 obj[key] = Emitter.prototype[key];
30 }
31 return obj;
32 }
33
34 /**
35 * Listen on the given `event` with `fn`.
36 *
37 * @param {String} event
38 * @param {Function} fn
39 * @return {Emitter}
40 * @api public
41 */
42
43 Emitter.prototype.on =
44 Emitter.prototype.addEventListener = function(event, fn){
45 this._callbacks = this._callbacks || {};
46 (this._callbacks['$' + event] = this._callbacks['$' + event] || [])
47 .push(fn);
48 return this;
49 };
50
51 /**
52 * Adds an `event` listener that will be invoked a single
53 * time then automatically removed.
54 *
55 * @param {String} event
56 * @param {Function} fn
57 * @return {Emitter}
58 * @api public
59 */
60
61 Emitter.prototype.once = function(event, fn){
62 function on() {
63 this.off(event, on);
64 fn.apply(this, arguments);
65 }
66
67 on.fn = fn;
68 this.on(event, on);
69 return this;
70 };
71
72 /**
73 * Remove the given callback for `event` or all
74 * registered callbacks.
75 *
76 * @param {String} event
77 * @param {Function} fn
78 * @return {Emitter}
79 * @api public
80 */
81
82 Emitter.prototype.off =
83 Emitter.prototype.removeListener =
84 Emitter.prototype.removeAllListeners =
85 Emitter.prototype.removeEventListener = function(event, fn){
86 this._callbacks = this._callbacks || {};
87
88 // all
89 if (0 == arguments.length) {
90 this._callbacks = {};
91 return this;
92 }
93
94 // specific event
95 var callbacks = this._callbacks['$' + event];
96 if (!callbacks) return this;
97
98 // remove all handlers
99 if (1 == arguments.length) {
100 delete this._callbacks['$' + event];
101 return this;
102 }
103
104 // remove specific handler
105 var cb;
106 for (var i = 0; i < callbacks.length; i++) {
107 cb = callbacks[i];
108 if (cb === fn || cb.fn === fn) {
109 callbacks.splice(i, 1);
110 break;
111 }
112 }
113 return this;
114 };
115
116 /**
117 * Emit `event` with the given args.
118 *
119 * @param {String} event
120 * @param {Mixed} ...
121 * @return {Emitter}
122 */
123
124 Emitter.prototype.emit = function(event){
125 this._callbacks = this._callbacks || {};
126 var args = [].slice.call(arguments, 1)
127 , callbacks = this._callbacks['$' + event];
128
129 if (callbacks) {
130 callbacks = callbacks.slice(0);
131 for (var i = 0, len = callbacks.length; i < len; ++i) {
132 callbacks[i].apply(this, args);
133 }
134 }
135
136 return this;
137 };
138
139 /**
140 * Return array of callbacks for `event`.
141 *
142 * @param {String} event
143 * @return {Array}
144 * @api public
145 */
146
147 Emitter.prototype.listeners = function(event){
148 this._callbacks = this._callbacks || {};
149 return this._callbacks['$' + event] || [];
150 };
151
152 /**
153 * Check if this emitter has `event` handlers.
154 *
155 * @param {String} event
156 * @return {Boolean}
157 * @api public
158 */
159
160 Emitter.prototype.hasListeners = function(event){
161 return !! this.listeners(event).length;
162 };
163
164 },{}],2:[function(require,module,exports){
165
166 /**
167 * Reduce `arr` with `fn`.
168 *
169 * @param {Array} arr
170 * @param {Function} fn
171 * @param {Mixed} initial
172 *
173 * TODO: combatible error handling?
174 */
175
176 module.exports = function(arr, fn, initial){
177 var idx = 0;
178 var len = arr.length;
179 var curr = arguments.length == 3
180 ? initial
181 : arr[idx++];
182
183 while (idx < len) {
184 curr = fn.call(null, curr, arr[idx], ++idx, arr);
185 }
186
187 return curr;
188 };
189 },{}],3:[function(require,module,exports){
190 /**
191 * Module dependencies.
192 */
193
194 var Emitter = require('emitter');
195 var reduce = require('reduce');
196
197 /**
198 * Root reference for iframes.
199 */
200
201 var root;
202 if (typeof window !== 'undefined') { // Browser window
203 root = window;
204 } else if (typeof self !== 'undefined') { // Web Worker
205 root = self;
206 } else { // Other environments
207 root = this;
208 }
209
210 /**
211 * Noop.
212 */
213
214 function noop(){};
215
216 /**
217 * Check if `obj` is a host object,
218 * we don't want to serialize these :)
219 *
220 * TODO: future proof, move to compoent land
221 *
222 * @param {Object} obj
223 * @return {Boolean}
224 * @api private
225 */
226
227 function isHost(obj) {
228 var str = {}.toString.call(obj);
229
230 switch (str) {
231 case '[object File]':
232 case '[object Blob]':
233 case '[object FormData]':
234 return true;
235 default:
236 return false;
237 }
238 }
239
240 /**
241 * Determine XHR.
242 */
243
244 request.getXHR = function () {
245 if (root.XMLHttpRequest
246 && (!root.location || 'file:' != root.location.protocol
247 || !root.ActiveXObject)) {
248 return new XMLHttpRequest;
249 } else {
250 try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
251 try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
252 try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
253 try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
254 }
255 return false;
256 };
257
258 /**
259 * Removes leading and trailing whitespace, added to support IE.
260 *
261 * @param {String} s
262 * @return {String}
263 * @api private
264 */
265
266 var trim = ''.trim
267 ? function(s) { return s.trim(); }
268 : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
269
270 /**
271 * Check if `obj` is an object.
272 *
273 * @param {Object} obj
274 * @return {Boolean}
275 * @api private
276 */
277
278 function isObject(obj) {
279 return obj === Object(obj);
280 }
281
282 /**
283 * Serialize the given `obj`.
284 *
285 * @param {Object} obj
286 * @return {String}
287 * @api private
288 */
289
290 function serialize(obj) {
291 if (!isObject(obj)) return obj;
292 var pairs = [];
293 for (var key in obj) {
294 if (null != obj[key]) {
295 pushEncodedKeyValuePair(pairs, key, obj[key]);
296 }
297 }
298 return pairs.join('&');
299 }
300
301 /**
302 * Helps 'serialize' with serializing arrays.
303 * Mutates the pairs array.
304 *
305 * @param {Array} pairs
306 * @param {String} key
307 * @param {Mixed} val
308 */
309
310 function pushEncodedKeyValuePair(pairs, key, val) {
311 if (Array.isArray(val)) {
312 return val.forEach(function(v) {
313 pushEncodedKeyValuePair(pairs, key, v);
314 });
315 }
316 pairs.push(encodeURIComponent(key)
317 + '=' + encodeURIComponent(val));
318 }
319
320 /**
321 * Expose serialization method.
322 */
323
324 request.serializeObject = serialize;
325
326 /**
327 * Parse the given x-www-form-urlencoded `str`.
328 *
329 * @param {String} str
330 * @return {Object}
331 * @api private
332 */
333
334 function parseString(str) {
335 var obj = {};
336 var pairs = str.split('&');
337 var parts;
338 var pair;
339
340 for (var i = 0, len = pairs.length; i < len; ++i) {
341 pair = pairs[i];
342 parts = pair.split('=');
343 obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
344 }
345
346 return obj;
347 }
348
349 /**
350 * Expose parser.
351 */
352
353 request.parseString = parseString;
354
355 /**
356 * Default MIME type map.
357 *
358 * superagent.types.xml = 'application/xml';
359 *
360 */
361
362 request.types = {
363 html: 'text/html',
364 json: 'application/json',
365 xml: 'application/xml',
366 urlencoded: 'application/x-www-form-urlencoded',
367 'form': 'application/x-www-form-urlencoded',
368 'form-data': 'application/x-www-form-urlencoded'
369 };
370
371 /**
372 * Default serialization map.
373 *
374 * superagent.serialize['application/xml'] = function(obj){
375 * return 'generated xml here';
376 * };
377 *
378 */
379
380 request.serialize = {
381 'application/x-www-form-urlencoded': serialize,
382 'application/json': JSON.stringify
383 };
384
385 /**
386 * Default parsers.
387 *
388 * superagent.parse['application/xml'] = function(str){
389 * return { object parsed from str };
390 * };
391 *
392 */
393
394 request.parse = {
395 'application/x-www-form-urlencoded': parseString,
396 'application/json': JSON.parse
397 };
398
399 /**
400 * Parse the given header `str` into
401 * an object containing the mapped fields.
402 *
403 * @param {String} str
404 * @return {Object}
405 * @api private
406 */
407
408 function parseHeader(str) {
409 var lines = str.split(/\r?\n/);
410 var fields = {};
411 var index;
412 var line;
413 var field;
414 var val;
415
416 lines.pop(); // trailing CRLF
417
418 for (var i = 0, len = lines.length; i < len; ++i) {
419 line = lines[i];
420 index = line.indexOf(':');
421 field = line.slice(0, index).toLowerCase();
422 val = trim(line.slice(index + 1));
423 fields[field] = val;
424 }
425
426 return fields;
427 }
428
429 /**
430 * Check if `mime` is json or has +json structured syntax suffix.
431 *
432 * @param {String} mime
433 * @return {Boolean}
434 * @api private
435 */
436
437 function isJSON(mime) {
438 return /[\/+]json\b/.test(mime);
439 }
440
441 /**
442 * Return the mime type for the given `str`.
443 *
444 * @param {String} str
445 * @return {String}
446 * @api private
447 */
448
449 function type(str){
450 return str.split(/ *; */).shift();
451 };
452
453 /**
454 * Return header field parameters.
455 *
456 * @param {String} str
457 * @return {Object}
458 * @api private
459 */
460
461 function params(str){
462 return reduce(str.split(/ *; */), function(obj, str){
463 var parts = str.split(/ *= */)
464 , key = parts.shift()
465 , val = parts.shift();
466
467 if (key && val) obj[key] = val;
468 return obj;
469 }, {});
470 };
471
472 /**
473 * Initialize a new `Response` with the given `xhr`.
474 *
475 * - set flags (.ok, .error, etc)
476 * - parse header
477 *
478 * Examples:
479 *
480 * Aliasing `superagent` as `request` is nice:
481 *
482 * request = superagent;
483 *
484 * We can use the promise-like API, or pass callbacks:
485 *
486 * request.get('/').end(function(res){});
487 * request.get('/', function(res){});
488 *
489 * Sending data can be chained:
490 *
491 * request
492 * .post('/user')
493 * .send({ name: 'tj' })
494 * .end(function(res){});
495 *
496 * Or passed to `.send()`:
497 *
498 * request
499 * .post('/user')
500 * .send({ name: 'tj' }, function(res){});
501 *
502 * Or passed to `.post()`:
503 *
504 * request
505 * .post('/user', { name: 'tj' })
506 * .end(function(res){});
507 *
508 * Or further reduced to a single call for simple cases:
509 *
510 * request
511 * .post('/user', { name: 'tj' }, function(res){});
512 *
513 * @param {XMLHTTPRequest} xhr
514 * @param {Object} options
515 * @api private
516 */
517
518 function Response(req, options) {
519 options = options || {};
520 this.req = req;
521 this.xhr = this.req.xhr;
522 // responseText is accessible only if responseType is '' or 'text' and on older browsers
523 this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
524 ? this.xhr.responseText
525 : null;
526 this.statusText = this.req.xhr.statusText;
527 this.setStatusProperties(this.xhr.status);
528 this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
529 // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
530 // getResponseHeader still works. so we get content-type even if getting
531 // other headers fails.
532 this.header['content-type'] = this.xhr.getResponseHeader('content-type');
533 this.setHeaderProperties(this.header);
534 this.body = this.req.method != 'HEAD'
535 ? this.parseBody(this.text ? this.text : this.xhr.response)
536 : null;
537 }
538
539 /**
540 * Get case-insensitive `field` value.
541 *
542 * @param {String} field
543 * @return {String}
544 * @api public
545 */
546
547 Response.prototype.get = function(field){
548 return this.header[field.toLowerCase()];
549 };
550
551 /**
552 * Set header related properties:
553 *
554 * - `.type` the content type without params
555 *
556 * A response of "Content-Type: text/plain; charset=utf-8"
557 * will provide you with a `.type` of "text/plain".
558 *
559 * @param {Object} header
560 * @api private
561 */
562
563 Response.prototype.setHeaderProperties = function(header){
564 // content-type
565 var ct = this.header['content-type'] || '';
566 this.type = type(ct);
567
568 // params
569 var obj = params(ct);
570 for (var key in obj) this[key] = obj[key];
571 };
572
573 /**
574 * Parse the given body `str`.
575 *
576 * Used for auto-parsing of bodies. Parsers
577 * are defined on the `superagent.parse` object.
578 *
579 * @param {String} str
580 * @return {Mixed}
581 * @api private
582 */
583
584 Response.prototype.parseBody = function(str){
585 var parse = request.parse[this.type];
586 return parse && str && (str.length || str instanceof Object)
587 ? parse(str)
588 : null;
589 };
590
591 /**
592 * Set flags such as `.ok` based on `status`.
593 *
594 * For example a 2xx response will give you a `.ok` of __true__
595 * whereas 5xx will be __false__ and `.error` will be __true__. The
596 * `.clientError` and `.serverError` are also available to be more
597 * specific, and `.statusType` is the class of error ranging from 1..5
598 * sometimes useful for mapping respond colors etc.
599 *
600 * "sugar" properties are also defined for common cases. Currently providing:
601 *
602 * - .noContent
603 * - .badRequest
604 * - .unauthorized
605 * - .notAcceptable
606 * - .notFound
607 *
608 * @param {Number} status
609 * @api private
610 */
611
612 Response.prototype.setStatusProperties = function(status){
613 // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
614 if (status === 1223) {
615 status = 204;
616 }
617
618 var type = status / 100 | 0;
619
620 // status / class
621 this.status = this.statusCode = status;
622 this.statusType = type;
623
624 // basics
625 this.info = 1 == type;
626 this.ok = 2 == type;
627 this.clientError = 4 == type;
628 this.serverError = 5 == type;
629 this.error = (4 == type || 5 == type)
630 ? this.toError()
631 : false;
632
633 // sugar
634 this.accepted = 202 == status;
635 this.noContent = 204 == status;
636 this.badRequest = 400 == status;
637 this.unauthorized = 401 == status;
638 this.notAcceptable = 406 == status;
639 this.notFound = 404 == status;
640 this.forbidden = 403 == status;
641 };
642
643 /**
644 * Return an `Error` representative of this response.
645 *
646 * @return {Error}
647 * @api public
648 */
649
650 Response.prototype.toError = function(){
651 var req = this.req;
652 var method = req.method;
653 var url = req.url;
654
655 var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
656 var err = new Error(msg);
657 err.status = this.status;
658 err.method = method;
659 err.url = url;
660
661 return err;
662 };
663
664 /**
665 * Expose `Response`.
666 */
667
668 request.Response = Response;
669
670 /**
671 * Initialize a new `Request` with the given `method` and `url`.
672 *
673 * @param {String} method
674 * @param {String} url
675 * @api public
676 */
677
678 function Request(method, url) {
679 var self = this;
680 Emitter.call(this);
681 this._query = this._query || [];
682 this.method = method;
683 this.url = url;
684 this.header = {};
685 this._header = {};
686 this.on('end', function(){
687 var err = null;
688 var res = null;
689
690 try {
691 res = new Response(self);
692 } catch(e) {
693 err = new Error('Parser is unable to parse the response');
694 err.parse = true;
695 err.original = e;
696 // issue #675: return the raw response if the response parsing fails
697 err.rawResponse = self.xhr && self.xhr.responseText ? self.xhr.responseText : null;
698 return self.callback(err);
699 }
700
701 self.emit('response', res);
702
703 if (err) {
704 return self.callback(err, res);
705 }
706
707 if (res.status >= 200 && res.status < 300) {
708 return self.callback(err, res);
709 }
710
711 var new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
712 new_err.original = err;
713 new_err.response = res;
714 new_err.status = res.status;
715
716 self.callback(new_err, res);
717 });
718 }
719
720 /**
721 * Mixin `Emitter`.
722 */
723
724 Emitter(Request.prototype);
725
726 /**
727 * Allow for extension
728 */
729
730 Request.prototype.use = function(fn) {
731 fn(this);
732 return this;
733 }
734
735 /**
736 * Set timeout to `ms`.
737 *
738 * @param {Number} ms
739 * @return {Request} for chaining
740 * @api public
741 */
742
743 Request.prototype.timeout = function(ms){
744 this._timeout = ms;
745 return this;
746 };
747
748 /**
749 * Clear previous timeout.
750 *
751 * @return {Request} for chaining
752 * @api public
753 */
754
755 Request.prototype.clearTimeout = function(){
756 this._timeout = 0;
757 clearTimeout(this._timer);
758 return this;
759 };
760
761 /**
762 * Abort the request, and clear potential timeout.
763 *
764 * @return {Request}
765 * @api public
766 */
767
768 Request.prototype.abort = function(){
769 if (this.aborted) return;
770 this.aborted = true;
771 this.xhr.abort();
772 this.clearTimeout();
773 this.emit('abort');
774 return this;
775 };
776
777 /**
778 * Set header `field` to `val`, or multiple fields with one object.
779 *
780 * Examples:
781 *
782 * req.get('/')
783 * .set('Accept', 'application/json')
784 * .set('X-API-Key', 'foobar')
785 * .end(callback);
786 *
787 * req.get('/')
788 * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })
789 * .end(callback);
790 *
791 * @param {String|Object} field
792 * @param {String} val
793 * @return {Request} for chaining
794 * @api public
795 */
796
797 Request.prototype.set = function(field, val){
798 if (isObject(field)) {
799 for (var key in field) {
800 this.set(key, field[key]);
801 }
802 return this;
803 }
804 this._header[field.toLowerCase()] = val;
805 this.header[field] = val;
806 return this;
807 };
808
809 /**
810 * Remove header `field`.
811 *
812 * Example:
813 *
814 * req.get('/')
815 * .unset('User-Agent')
816 * .end(callback);
817 *
818 * @param {String} field
819 * @return {Request} for chaining
820 * @api public
821 */
822
823 Request.prototype.unset = function(field){
824 delete this._header[field.toLowerCase()];
825 delete this.header[field];
826 return this;
827 };
828
829 /**
830 * Get case-insensitive header `field` value.
831 *
832 * @param {String} field
833 * @return {String}
834 * @api private
835 */
836
837 Request.prototype.getHeader = function(field){
838 return this._header[field.toLowerCase()];
839 };
840
841 /**
842 * Set Content-Type to `type`, mapping values from `request.types`.
843 *
844 * Examples:
845 *
846 * superagent.types.xml = 'application/xml';
847 *
848 * request.post('/')
849 * .type('xml')
850 * .send(xmlstring)
851 * .end(callback);
852 *
853 * request.post('/')
854 * .type('application/xml')
855 * .send(xmlstring)
856 * .end(callback);
857 *
858 * @param {String} type
859 * @return {Request} for chaining
860 * @api public
861 */
862
863 Request.prototype.type = function(type){
864 this.set('Content-Type', request.types[type] || type);
865 return this;
866 };
867
868 /**
869 * Force given parser
870 *
871 * Sets the body parser no matter type.
872 *
873 * @param {Function}
874 * @api public
875 */
876
877 Request.prototype.parse = function(fn){
878 this._parser = fn;
879 return this;
880 };
881
882 /**
883 * Set Accept to `type`, mapping values from `request.types`.
884 *
885 * Examples:
886 *
887 * superagent.types.json = 'application/json';
888 *
889 * request.get('/agent')
890 * .accept('json')
891 * .end(callback);
892 *
893 * request.get('/agent')
894 * .accept('application/json')
895 * .end(callback);
896 *
897 * @param {String} accept
898 * @return {Request} for chaining
899 * @api public
900 */
901
902 Request.prototype.accept = function(type){
903 this.set('Accept', request.types[type] || type);
904 return this;
905 };
906
907 /**
908 * Set Authorization field value with `user` and `pass`.
909 *
910 * @param {String} user
911 * @param {String} pass
912 * @return {Request} for chaining
913 * @api public
914 */
915
916 Request.prototype.auth = function(user, pass){
917 var str = btoa(user + ':' + pass);
918 this.set('Authorization', 'Basic ' + str);
919 return this;
920 };
921
922 /**
923 * Add query-string `val`.
924 *
925 * Examples:
926 *
927 * request.get('/shoes')
928 * .query('size=10')
929 * .query({ color: 'blue' })
930 *
931 * @param {Object|String} val
932 * @return {Request} for chaining
933 * @api public
934 */
935
936 Request.prototype.query = function(val){
937 if ('string' != typeof val) val = serialize(val);
938 if (val) this._query.push(val);
939 return this;
940 };
941
942 /**
943 * Write the field `name` and `val` for "multipart/form-data"
944 * request bodies.
945 *
946 * ``` js
947 * request.post('/upload')
948 * .field('foo', 'bar')
949 * .end(callback);
950 * ```
951 *
952 * @param {String} name
953 * @param {String|Blob|File} val
954 * @return {Request} for chaining
955 * @api public
956 */
957
958 Request.prototype.field = function(name, val){
959 if (!this._formData) this._formData = new root.FormData();
960 this._formData.append(name, val);
961 return this;
962 };
963
964 /**
965 * Queue the given `file` as an attachment to the specified `field`,
966 * with optional `filename`.
967 *
968 * ``` js
969 * request.post('/upload')
970 * .attach(new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"}))
971 * .end(callback);
972 * ```
973 *
974 * @param {String} field
975 * @param {Blob|File} file
976 * @param {String} filename
977 * @return {Request} for chaining
978 * @api public
979 */
980
981 Request.prototype.attach = function(field, file, filename){
982 if (!this._formData) this._formData = new root.FormData();
983 this._formData.append(field, file, filename || file.name);
984 return this;
985 };
986
987 /**
988 * Send `data` as the request body, defaulting the `.type()` to "json" when
989 * an object is given.
990 *
991 * Examples:
992 *
993 * // manual json
994 * request.post('/user')
995 * .type('json')
996 * .send('{"name":"tj"}')
997 * .end(callback)
998 *
999 * // auto json
1000 * request.post('/user')
1001 * .send({ name: 'tj' })
1002 * .end(callback)
1003 *
1004 * // manual x-www-form-urlencoded
1005 * request.post('/user')
1006 * .type('form')
1007 * .send('name=tj')
1008 * .end(callback)
1009 *
1010 * // auto x-www-form-urlencoded
1011 * request.post('/user')
1012 * .type('form')
1013 * .send({ name: 'tj' })
1014 * .end(callback)
1015 *
1016 * // defaults to x-www-form-urlencoded
1017 * request.post('/user')
1018 * .send('name=tobi')
1019 * .send('species=ferret')
1020 * .end(callback)
1021 *
1022 * @param {String|Object} data
1023 * @return {Request} for chaining
1024 * @api public
1025 */
1026
1027 Request.prototype.send = function(data){
1028 var obj = isObject(data);
1029 var type = this.getHeader('Content-Type');
1030
1031 // merge
1032 if (obj && isObject(this._data)) {
1033 for (var key in data) {
1034 this._data[key] = data[key];
1035 }
1036 } else if ('string' == typeof data) {
1037 if (!type) this.type('form');
1038 type = this.getHeader('Content-Type');
1039 if ('application/x-www-form-urlencoded' == type) {
1040 this._data = this._data
1041 ? this._data + '&' + data
1042 : data;
1043 } else {
1044 this._data = (this._data || '') + data;
1045 }
1046 } else {
1047 this._data = data;
1048 }
1049
1050 if (!obj || isHost(data)) return this;
1051 if (!type) this.type('json');
1052 return this;
1053 };
1054
1055 /**
1056 * Invoke the callback with `err` and `res`
1057 * and handle arity check.
1058 *
1059 * @param {Error} err
1060 * @param {Response} res
1061 * @api private
1062 */
1063
1064 Request.prototype.callback = function(err, res){
1065 var fn = this._callback;
1066 this.clearTimeout();
1067 fn(err, res);
1068 };
1069
1070 /**
1071 * Invoke callback with x-domain error.
1072 *
1073 * @api private
1074 */
1075
1076 Request.prototype.crossDomainError = function(){
1077 var err = new Error('Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.');
1078 err.crossDomain = true;
1079
1080 err.status = this.status;
1081 err.method = this.method;
1082 err.url = this.url;
1083
1084 this.callback(err);
1085 };
1086
1087 /**
1088 * Invoke callback with timeout error.
1089 *
1090 * @api private
1091 */
1092
1093 Request.prototype.timeoutError = function(){
1094 var timeout = this._timeout;
1095 var err = new Error('timeout of ' + timeout + 'ms exceeded');
1096 err.timeout = timeout;
1097 this.callback(err);
1098 };
1099
1100 /**
1101 * Enable transmission of cookies with x-domain requests.
1102 *
1103 * Note that for this to work the origin must not be
1104 * using "Access-Control-Allow-Origin" with a wildcard,
1105 * and also must set "Access-Control-Allow-Credentials"
1106 * to "true".
1107 *
1108 * @api public
1109 */
1110
1111 Request.prototype.withCredentials = function(){
1112 this._withCredentials = true;
1113 return this;
1114 };
1115
1116 /**
1117 * Initiate request, invoking callback `fn(res)`
1118 * with an instanceof `Response`.
1119 *
1120 * @param {Function} fn
1121 * @return {Request} for chaining
1122 * @api public
1123 */
1124
1125 Request.prototype.end = function(fn){
1126 var self = this;
1127 var xhr = this.xhr = request.getXHR();
1128 var query = this._query.join('&');
1129 var timeout = this._timeout;
1130 var data = this._formData || this._data;
1131
1132 // store callback
1133 this._callback = fn || noop;
1134
1135 // state change
1136 xhr.onreadystatechange = function(){
1137 if (4 != xhr.readyState) return;
1138
1139 // In IE9, reads to any property (e.g. status) off of an aborted XHR will
1140 // result in the error "Could not complete the operation due to error c00c023f"
1141 var status;
1142 try { status = xhr.status } catch(e) { status = 0; }
1143
1144 if (0 == status) {
1145 if (self.timedout) return self.timeoutError();
1146 if (self.aborted) return;
1147 return self.crossDomainError();
1148 }
1149 self.emit('end');
1150 };
1151
1152 // progress
1153 var handleProgress = function(e){
1154 if (e.total > 0) {
1155 e.percent = e.loaded / e.total * 100;
1156 }
1157 e.direction = 'download';
1158 self.emit('progress', e);
1159 };
1160 if (this.hasListeners('progress')) {
1161 xhr.onprogress = handleProgress;
1162 }
1163 try {
1164 if (xhr.upload && this.hasListeners('progress')) {
1165 xhr.upload.onprogress = handleProgress;
1166 }
1167 } catch(e) {
1168 // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
1169 // Reported here:
1170 // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
1171 }
1172
1173 // timeout
1174 if (timeout && !this._timer) {
1175 this._timer = setTimeout(function(){
1176 self.timedout = true;
1177 self.abort();
1178 }, timeout);
1179 }
1180
1181 // querystring
1182 if (query) {
1183 query = request.serializeObject(query);
1184 this.url += ~this.url.indexOf('?')
1185 ? '&' + query
1186 : '?' + query;
1187 }
1188
1189 // initiate request
1190 xhr.open(this.method, this.url, true);
1191
1192 // CORS
1193 if (this._withCredentials) xhr.withCredentials = true;
1194
1195 // body
1196 if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) {
1197 // serialize stuff
1198 var contentType = this.getHeader('Content-Type');
1199 var serialize = this._parser || request.serialize[contentType ? contentType.split(';')[0] : ''];
1200 if (!serialize && isJSON(contentType)) serialize = request.serialize['application/json'];
1201 if (serialize) data = serialize(data);
1202 }
1203
1204 // set header fields
1205 for (var field in this.header) {
1206 if (null == this.header[field]) continue;
1207 xhr.setRequestHeader(field, this.header[field]);
1208 }
1209
1210 // send stuff
1211 this.emit('request', this);
1212
1213 // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing)
1214 // We need null here if data is undefined
1215 xhr.send(typeof data !== 'undefined' ? data : null);
1216 return this;
1217 };
1218
1219 /**
1220 * Faux promise support
1221 *
1222 * @param {Function} fulfill
1223 * @param {Function} reject
1224 * @return {Request}
1225 */
1226
1227 Request.prototype.then = function (fulfill, reject) {
1228 return this.end(function(err, res) {
1229 err ? reject(err) : fulfill(res);
1230 });
1231 }
1232
1233 /**
1234 * Expose `Request`.
1235 */
1236
1237 request.Request = Request;
1238
1239 /**
1240 * Issue a request:
1241 *
1242 * Examples:
1243 *
1244 * request('GET', '/users').end(callback)
1245 * request('/users').end(callback)
1246 * request('/users', callback)
1247 *
1248 * @param {String} method
1249 * @param {String|Function} url or callback
1250 * @return {Request}
1251 * @api public
1252 */
1253
1254 function request(method, url) {
1255 // callback
1256 if ('function' == typeof url) {
1257 return new Request('GET', method).end(url);
1258 }
1259
1260 // url first
1261 if (1 == arguments.length) {
1262 return new Request('GET', method);
1263 }
1264
1265 return new Request(method, url);
1266 }
1267
1268 /**
1269 * GET `url` with optional callback `fn(res)`.
1270 *
1271 * @param {String} url
1272 * @param {Mixed|Function} data or fn
1273 * @param {Function} fn
1274 * @return {Request}
1275 * @api public
1276 */
1277
1278 request.get = function(url, data, fn){
1279 var req = request('GET', url);
1280 if ('function' == typeof data) fn = data, data = null;
1281 if (data) req.query(data);
1282 if (fn) req.end(fn);
1283 return req;
1284 };
1285
1286 /**
1287 * HEAD `url` with optional callback `fn(res)`.
1288 *
1289 * @param {String} url
1290 * @param {Mixed|Function} data or fn
1291 * @param {Function} fn
1292 * @return {Request}
1293 * @api public
1294 */
1295
1296 request.head = function(url, data, fn){
1297 var req = request('HEAD', url);
1298 if ('function' == typeof data) fn = data, data = null;
1299 if (data) req.send(data);
1300 if (fn) req.end(fn);
1301 return req;
1302 };
1303
1304 /**
1305 * DELETE `url` with optional callback `fn(res)`.
1306 *
1307 * @param {String} url
1308 * @param {Function} fn
1309 * @return {Request}
1310 * @api public
1311 */
1312
1313 function del(url, fn){
1314 var req = request('DELETE', url);
1315 if (fn) req.end(fn);
1316 return req;
1317 };
1318
1319 request['del'] = del;
1320 request['delete'] = del;
1321
1322 /**
1323 * PATCH `url` with optional `data` and callback `fn(res)`.
1324 *
1325 * @param {String} url
1326 * @param {Mixed} data
1327 * @param {Function} fn
1328 * @return {Request}
1329 * @api public
1330 */
1331
1332 request.patch = function(url, data, fn){
1333 var req = request('PATCH', url);
1334 if ('function' == typeof data) fn = data, data = null;
1335 if (data) req.send(data);
1336 if (fn) req.end(fn);
1337 return req;
1338 };
1339
1340 /**
1341 * POST `url` with optional `data` and callback `fn(res)`.
1342 *
1343 * @param {String} url
1344 * @param {Mixed} data
1345 * @param {Function} fn
1346 * @return {Request}
1347 * @api public
1348 */
1349
1350 request.post = function(url, data, fn){
1351 var req = request('POST', url);
1352 if ('function' == typeof data) fn = data, data = null;
1353 if (data) req.send(data);
1354 if (fn) req.end(fn);
1355 return req;
1356 };
1357
1358 /**
1359 * PUT `url` with optional `data` and callback `fn(res)`.
1360 *
1361 * @param {String} url
1362 * @param {Mixed|Function} data or fn
1363 * @param {Function} fn
1364 * @return {Request}
1365 * @api public
1366 */
1367
1368 request.put = function(url, data, fn){
1369 var req = request('PUT', url);
1370 if ('function' == typeof data) fn = data, data = null;
1371 if (data) req.send(data);
1372 if (fn) req.end(fn);
1373 return req;
1374 };
1375
1376 /**
1377 * Expose `request`.
1378 */
1379
1380 module.exports = request;
1381
1382 },{"emitter":1,"reduce":2}]},{},[3])(3)
1383 });