1 |
|
2 |
|
3 |
|
4 |
|
5 | var root;
|
6 | if (typeof window !== 'undefined') {
|
7 | root = window;
|
8 | } else if (typeof self !== 'undefined') {
|
9 | root = self;
|
10 | } else {
|
11 | console.warn("Using browser-only version of superagent in non-browser environment");
|
12 | root = this;
|
13 | }
|
14 |
|
15 | var Emitter = require('component-emitter');
|
16 | var RequestBase = require('./request-base');
|
17 | var isObject = require('./is-object');
|
18 | var isFunction = require('./is-function');
|
19 | var ResponseBase = require('./response-base');
|
20 | var shouldRetry = require('./should-retry');
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | function noop(){};
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | var request = exports = module.exports = function(method, url) {
|
33 |
|
34 | if ('function' == typeof url) {
|
35 | return new exports.Request('GET', method).end(url);
|
36 | }
|
37 |
|
38 |
|
39 | if (1 == arguments.length) {
|
40 | return new exports.Request('GET', method);
|
41 | }
|
42 |
|
43 | return new exports.Request(method, url);
|
44 | }
|
45 |
|
46 | exports.Request = Request;
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 | request.getXHR = function () {
|
53 | if (root.XMLHttpRequest
|
54 | && (!root.location || 'file:' != root.location.protocol
|
55 | || !root.ActiveXObject)) {
|
56 | return new XMLHttpRequest;
|
57 | } else {
|
58 | try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
|
59 | try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
|
60 | try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
|
61 | try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
|
62 | }
|
63 | throw Error("Browser-only verison of superagent could not find XHR");
|
64 | };
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | var trim = ''.trim
|
75 | ? function(s) { return s.trim(); }
|
76 | : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 | function serialize(obj) {
|
87 | if (!isObject(obj)) return obj;
|
88 | var pairs = [];
|
89 | for (var key in obj) {
|
90 | pushEncodedKeyValuePair(pairs, key, obj[key]);
|
91 | }
|
92 | return pairs.join('&');
|
93 | }
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 | function pushEncodedKeyValuePair(pairs, key, val) {
|
105 | if (val != null) {
|
106 | if (Array.isArray(val)) {
|
107 | val.forEach(function(v) {
|
108 | pushEncodedKeyValuePair(pairs, key, v);
|
109 | });
|
110 | } else if (isObject(val)) {
|
111 | for(var subkey in val) {
|
112 | pushEncodedKeyValuePair(pairs, key + '[' + subkey + ']', val[subkey]);
|
113 | }
|
114 | } else {
|
115 | pairs.push(encodeURIComponent(key)
|
116 | + '=' + encodeURIComponent(val));
|
117 | }
|
118 | } else if (val === null) {
|
119 | pairs.push(encodeURIComponent(key));
|
120 | }
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | request.serializeObject = serialize;
|
128 |
|
129 | |
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 | function parseString(str) {
|
138 | var obj = {};
|
139 | var pairs = str.split('&');
|
140 | var pair;
|
141 | var pos;
|
142 |
|
143 | for (var i = 0, len = pairs.length; i < len; ++i) {
|
144 | pair = pairs[i];
|
145 | pos = pair.indexOf('=');
|
146 | if (pos == -1) {
|
147 | obj[decodeURIComponent(pair)] = '';
|
148 | } else {
|
149 | obj[decodeURIComponent(pair.slice(0, pos))] =
|
150 | decodeURIComponent(pair.slice(pos + 1));
|
151 | }
|
152 | }
|
153 |
|
154 | return obj;
|
155 | }
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 | request.parseString = parseString;
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 | request.types = {
|
171 | html: 'text/html',
|
172 | json: 'application/json',
|
173 | xml: 'application/xml',
|
174 | urlencoded: 'application/x-www-form-urlencoded',
|
175 | 'form': 'application/x-www-form-urlencoded',
|
176 | 'form-data': 'application/x-www-form-urlencoded'
|
177 | };
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | request.serialize = {
|
189 | 'application/x-www-form-urlencoded': serialize,
|
190 | 'application/json': JSON.stringify
|
191 | };
|
192 |
|
193 | |
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 | request.parse = {
|
203 | 'application/x-www-form-urlencoded': parseString,
|
204 | 'application/json': JSON.parse
|
205 | };
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 | function parseHeader(str) {
|
217 | var lines = str.split(/\r?\n/);
|
218 | var fields = {};
|
219 | var index;
|
220 | var line;
|
221 | var field;
|
222 | var val;
|
223 |
|
224 | lines.pop();
|
225 |
|
226 | for (var i = 0, len = lines.length; i < len; ++i) {
|
227 | line = lines[i];
|
228 | index = line.indexOf(':');
|
229 | field = line.slice(0, index).toLowerCase();
|
230 | val = trim(line.slice(index + 1));
|
231 | fields[field] = val;
|
232 | }
|
233 |
|
234 | return fields;
|
235 | }
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | function isJSON(mime) {
|
246 | return /[\/+]json\b/.test(mime);
|
247 | }
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | function Response(req) {
|
296 | this.req = req;
|
297 | this.xhr = this.req.xhr;
|
298 |
|
299 | this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
|
300 | ? this.xhr.responseText
|
301 | : null;
|
302 | this.statusText = this.req.xhr.statusText;
|
303 | var status = this.xhr.status;
|
304 |
|
305 | if (status === 1223) {
|
306 | status = 204;
|
307 | }
|
308 | this._setStatusProperties(status);
|
309 | this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
|
310 |
|
311 |
|
312 |
|
313 | this.header['content-type'] = this.xhr.getResponseHeader('content-type');
|
314 | this._setHeaderProperties(this.header);
|
315 |
|
316 | if (null === this.text && req._responseType) {
|
317 | this.body = this.xhr.response;
|
318 | } else {
|
319 | this.body = this.req.method != 'HEAD'
|
320 | ? this._parseBody(this.text ? this.text : this.xhr.response)
|
321 | : null;
|
322 | }
|
323 | }
|
324 |
|
325 | ResponseBase(Response.prototype);
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 |
|
335 |
|
336 |
|
337 |
|
338 | Response.prototype._parseBody = function(str){
|
339 | var parse = request.parse[this.type];
|
340 | if(this.req._parser) {
|
341 | return this.req._parser(this, str);
|
342 | }
|
343 | if (!parse && isJSON(this.type)) {
|
344 | parse = request.parse['application/json'];
|
345 | }
|
346 | return parse && str && (str.length || str instanceof Object)
|
347 | ? parse(str)
|
348 | : null;
|
349 | };
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 | Response.prototype.toError = function(){
|
359 | var req = this.req;
|
360 | var method = req.method;
|
361 | var url = req.url;
|
362 |
|
363 | var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
|
364 | var err = new Error(msg);
|
365 | err.status = this.status;
|
366 | err.method = method;
|
367 | err.url = url;
|
368 |
|
369 | return err;
|
370 | };
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 | request.Response = Response;
|
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 |
|
383 |
|
384 |
|
385 |
|
386 | function Request(method, url) {
|
387 | var self = this;
|
388 | this._query = this._query || [];
|
389 | this.method = method;
|
390 | this.url = url;
|
391 | this.header = {};
|
392 | this._header = {};
|
393 | this.on('end', function(){
|
394 | var err = null;
|
395 | var res = null;
|
396 |
|
397 | try {
|
398 | res = new Response(self);
|
399 | } catch(e) {
|
400 | err = new Error('Parser is unable to parse the response');
|
401 | err.parse = true;
|
402 | err.original = e;
|
403 |
|
404 | if (self.xhr) {
|
405 |
|
406 | err.rawResponse = typeof self.xhr.responseType == 'undefined' ? self.xhr.responseText : self.xhr.response;
|
407 |
|
408 | err.status = self.xhr.status ? self.xhr.status : null;
|
409 | err.statusCode = err.status;
|
410 | } else {
|
411 | err.rawResponse = null;
|
412 | err.status = null;
|
413 | }
|
414 |
|
415 | return self.callback(err);
|
416 | }
|
417 |
|
418 | self.emit('response', res);
|
419 |
|
420 | var new_err;
|
421 | try {
|
422 | if (!self._isResponseOK(res)) {
|
423 | new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
|
424 | new_err.original = err;
|
425 | new_err.response = res;
|
426 | new_err.status = res.status;
|
427 | }
|
428 | } catch(e) {
|
429 | new_err = e;
|
430 | }
|
431 |
|
432 |
|
433 | if (new_err) {
|
434 | self.callback(new_err, res);
|
435 | } else {
|
436 | self.callback(null, res);
|
437 | }
|
438 | });
|
439 | }
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 | Emitter(Request.prototype);
|
446 | RequestBase(Request.prototype);
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 |
|
462 |
|
463 |
|
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 | Request.prototype.type = function(type){
|
471 | this.set('Content-Type', request.types[type] || type);
|
472 | return this;
|
473 | };
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 |
|
493 |
|
494 |
|
495 | Request.prototype.accept = function(type){
|
496 | this.set('Accept', request.types[type] || type);
|
497 | return this;
|
498 | };
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 |
|
510 | Request.prototype.auth = function(user, pass, options){
|
511 | if (typeof pass === 'object' && pass !== null) {
|
512 | options = pass;
|
513 | }
|
514 | if (!options) {
|
515 | options = {
|
516 | type: 'function' === typeof btoa ? 'basic' : 'auto',
|
517 | }
|
518 | }
|
519 |
|
520 | switch (options.type) {
|
521 | case 'basic':
|
522 | this.set('Authorization', 'Basic ' + btoa(user + ':' + pass));
|
523 | break;
|
524 |
|
525 | case 'auto':
|
526 | this.username = user;
|
527 | this.password = pass;
|
528 | break;
|
529 |
|
530 | case 'bearer':
|
531 | this.set('Authorization', 'Bearer ' + user);
|
532 | break;
|
533 | }
|
534 | return this;
|
535 | };
|
536 |
|
537 |
|
538 |
|
539 |
|
540 |
|
541 |
|
542 |
|
543 |
|
544 |
|
545 |
|
546 |
|
547 |
|
548 |
|
549 |
|
550 |
|
551 | Request.prototype.query = function(val){
|
552 | if ('string' != typeof val) val = serialize(val);
|
553 | if (val) this._query.push(val);
|
554 | return this;
|
555 | };
|
556 |
|
557 |
|
558 |
|
559 |
|
560 |
|
561 |
|
562 |
|
563 |
|
564 |
|
565 |
|
566 |
|
567 |
|
568 |
|
569 |
|
570 |
|
571 |
|
572 |
|
573 |
|
574 | Request.prototype.attach = function(field, file, options){
|
575 | if (file) {
|
576 | if (this._data) {
|
577 | throw Error("superagent can't mix .send() and .attach()");
|
578 | }
|
579 |
|
580 | this._getFormData().append(field, file, options || file.name);
|
581 | }
|
582 | return this;
|
583 | };
|
584 |
|
585 | Request.prototype._getFormData = function(){
|
586 | if (!this._formData) {
|
587 | this._formData = new root.FormData();
|
588 | }
|
589 | return this._formData;
|
590 | };
|
591 |
|
592 |
|
593 |
|
594 |
|
595 |
|
596 |
|
597 |
|
598 |
|
599 |
|
600 |
|
601 | Request.prototype.callback = function(err, res){
|
602 |
|
603 | if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) {
|
604 | return this._retry();
|
605 | }
|
606 |
|
607 | var fn = this._callback;
|
608 | this.clearTimeout();
|
609 |
|
610 | if (err) {
|
611 | if (this._maxRetries) err.retries = this._retries - 1;
|
612 | this.emit('error', err);
|
613 | }
|
614 |
|
615 | fn(err, res);
|
616 | };
|
617 |
|
618 | /**
|
619 | * Invoke callback with x-domain error.
|
620 | *
|
621 | * @api private
|
622 | */
|
623 |
|
624 | Request.prototype.crossDomainError = function(){
|
625 | 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.');
|
626 | err.crossDomain = true;
|
627 |
|
628 | err.status = this.status;
|
629 | err.method = this.method;
|
630 | err.url = this.url;
|
631 |
|
632 | this.callback(err);
|
633 | };
|
634 |
|
635 | // This only warns, because the request is still likely to work
|
636 | Request.prototype.buffer = Request.prototype.ca = Request.prototype.agent = function(){
|
637 | console.warn("This is not supported in browser version of superagent");
|
638 | return this;
|
639 | };
|
640 |
|
641 | // This throws, because it can't send/receive data as expected
|
642 | Request.prototype.pipe = Request.prototype.write = function(){
|
643 | throw Error("Streaming is not supported in browser version of superagent");
|
644 | };
|
645 |
|
646 | /**
|
647 | * Compose querystring to append to req.url
|
648 | *
|
649 | * @api private
|
650 | */
|
651 |
|
652 | Request.prototype._appendQueryString = function(){
|
653 | var query = this._query.join('&');
|
654 | if (query) {
|
655 | this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') + query;
|
656 | }
|
657 |
|
658 | if (this._sort) {
|
659 | var index = this.url.indexOf('?');
|
660 | if (index >= 0) {
|
661 | var queryArr = this.url.substring(index + 1).split('&');
|
662 | if (isFunction(this._sort)) {
|
663 | queryArr.sort(this._sort);
|
664 | } else {
|
665 | queryArr.sort();
|
666 | }
|
667 | this.url = this.url.substring(0, index) + '?' + queryArr.join('&');
|
668 | }
|
669 | }
|
670 | };
|
671 |
|
672 | /**
|
673 | * Check if `obj` is a host object,
|
674 | * we don't want to serialize these :)
|
675 | *
|
676 | * @param {Object} obj
|
677 | * @return {Boolean}
|
678 | * @api private
|
679 | */
|
680 | Request.prototype._isHost = function _isHost(obj) {
|
681 | // Native objects stringify to [object File], [object Blob], [object FormData], etc.
|
682 | return obj && 'object' === typeof obj && !Array.isArray(obj) && Object.prototype.toString.call(obj) !== '[object Object]';
|
683 | }
|
684 |
|
685 | /**
|
686 | * Initiate request, invoking callback `fn(res)`
|
687 | * with an instanceof `Response`.
|
688 | *
|
689 | * @param {Function} fn
|
690 | * @return {Request} for chaining
|
691 | * @api public
|
692 | */
|
693 |
|
694 | Request.prototype.end = function(fn){
|
695 | if (this._endCalled) {
|
696 | console.warn("Warning: .end() was called twice. This is not supported in superagent");
|
697 | }
|
698 | this._endCalled = true;
|
699 |
|
700 | // store callback
|
701 | this._callback = fn || noop;
|
702 |
|
703 | // querystring
|
704 | this._appendQueryString();
|
705 |
|
706 | return this._end();
|
707 | };
|
708 |
|
709 | Request.prototype._end = function() {
|
710 | var self = this;
|
711 | var xhr = this.xhr = request.getXHR();
|
712 | var data = this._formData || this._data;
|
713 |
|
714 | this._setTimeouts();
|
715 |
|
716 | // state change
|
717 | xhr.onreadystatechange = function(){
|
718 | var readyState = xhr.readyState;
|
719 | if (readyState >= 2 && self._responseTimeoutTimer) {
|
720 | clearTimeout(self._responseTimeoutTimer);
|
721 | }
|
722 | if (4 != readyState) {
|
723 | return;
|
724 | }
|
725 |
|
726 | // In IE9, reads to any property (e.g. status) off of an aborted XHR will
|
727 | // result in the error "Could not complete the operation due to error c00c023f"
|
728 | var status;
|
729 | try { status = xhr.status } catch(e) { status = 0; }
|
730 |
|
731 | if (!status) {
|
732 | if (self.timedout || self._aborted) return;
|
733 | return self.crossDomainError();
|
734 | }
|
735 | self.emit('end');
|
736 | };
|
737 |
|
738 | // progress
|
739 | var handleProgress = function(direction, e) {
|
740 | if (e.total > 0) {
|
741 | e.percent = e.loaded / e.total * 100;
|
742 | }
|
743 | e.direction = direction;
|
744 | self.emit('progress', e);
|
745 | }
|
746 | if (this.hasListeners('progress')) {
|
747 | try {
|
748 | xhr.onprogress = handleProgress.bind(null, 'download');
|
749 | if (xhr.upload) {
|
750 | xhr.upload.onprogress = handleProgress.bind(null, 'upload');
|
751 | }
|
752 | } catch(e) {
|
753 | // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
|
754 | // Reported here:
|
755 | // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
|
756 | }
|
757 | }
|
758 |
|
759 | // initiate request
|
760 | try {
|
761 | if (this.username && this.password) {
|
762 | xhr.open(this.method, this.url, true, this.username, this.password);
|
763 | } else {
|
764 | xhr.open(this.method, this.url, true);
|
765 | }
|
766 | } catch (err) {
|
767 | // see #1149
|
768 | return this.callback(err);
|
769 | }
|
770 |
|
771 | // CORS
|
772 | if (this._withCredentials) xhr.withCredentials = true;
|
773 |
|
774 | // body
|
775 | if (!this._formData && 'GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !this._isHost(data)) {
|
776 | // serialize stuff
|
777 | var contentType = this._header['content-type'];
|
778 | var serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : ''];
|
779 | if (!serialize && isJSON(contentType)) {
|
780 | serialize = request.serialize['application/json'];
|
781 | }
|
782 | if (serialize) data = serialize(data);
|
783 | }
|
784 |
|
785 | // set header fields
|
786 | for (var field in this.header) {
|
787 | if (null == this.header[field]) continue;
|
788 |
|
789 | if (this.header.hasOwnProperty(field))
|
790 | xhr.setRequestHeader(field, this.header[field]);
|
791 | }
|
792 |
|
793 | if (this._responseType) {
|
794 | xhr.responseType = this._responseType;
|
795 | }
|
796 |
|
797 | // send stuff
|
798 | this.emit('request', this);
|
799 |
|
800 | // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing)
|
801 | // We need null here if data is undefined
|
802 | xhr.send(typeof data !== 'undefined' ? data : null);
|
803 | return this;
|
804 | };
|
805 |
|
806 | /**
|
807 | * GET `url` with optional callback `fn(res)`.
|
808 | *
|
809 | * @param {String} url
|
810 | * @param {Mixed|Function} [data] or fn
|
811 | * @param {Function} [fn]
|
812 | * @return {Request}
|
813 | * @api public
|
814 | */
|
815 |
|
816 | request.get = function(url, data, fn){
|
817 | var req = request('GET', url);
|
818 | if ('function' == typeof data) fn = data, data = null;
|
819 | if (data) req.query(data);
|
820 | if (fn) req.end(fn);
|
821 | return req;
|
822 | };
|
823 |
|
824 | /**
|
825 | * HEAD `url` with optional callback `fn(res)`.
|
826 | *
|
827 | * @param {String} url
|
828 | * @param {Mixed|Function} [data] or fn
|
829 | * @param {Function} [fn]
|
830 | * @return {Request}
|
831 | * @api public
|
832 | */
|
833 |
|
834 | request.head = function(url, data, fn){
|
835 | var req = request('HEAD', url);
|
836 | if ('function' == typeof data) fn = data, data = null;
|
837 | if (data) req.send(data);
|
838 | if (fn) req.end(fn);
|
839 | return req;
|
840 | };
|
841 |
|
842 | /**
|
843 | * OPTIONS query to `url` with optional callback `fn(res)`.
|
844 | *
|
845 | * @param {String} url
|
846 | * @param {Mixed|Function} [data] or fn
|
847 | * @param {Function} [fn]
|
848 | * @return {Request}
|
849 | * @api public
|
850 | */
|
851 |
|
852 | request.options = function(url, data, fn){
|
853 | var req = request('OPTIONS', url);
|
854 | if ('function' == typeof data) fn = data, data = null;
|
855 | if (data) req.send(data);
|
856 | if (fn) req.end(fn);
|
857 | return req;
|
858 | };
|
859 |
|
860 | /**
|
861 | * DELETE `url` with optional `data` and callback `fn(res)`.
|
862 | *
|
863 | * @param {String} url
|
864 | * @param {Mixed} [data]
|
865 | * @param {Function} [fn]
|
866 | * @return {Request}
|
867 | * @api public
|
868 | */
|
869 |
|
870 | function del(url, data, fn){
|
871 | var req = request('DELETE', url);
|
872 | if ('function' == typeof data) fn = data, data = null;
|
873 | if (data) req.send(data);
|
874 | if (fn) req.end(fn);
|
875 | return req;
|
876 | };
|
877 |
|
878 | request['del'] = del;
|
879 | request['delete'] = del;
|
880 |
|
881 | /**
|
882 | * PATCH `url` with optional `data` and callback `fn(res)`.
|
883 | *
|
884 | * @param {String} url
|
885 | * @param {Mixed} [data]
|
886 | * @param {Function} [fn]
|
887 | * @return {Request}
|
888 | * @api public
|
889 | */
|
890 |
|
891 | request.patch = function(url, data, fn){
|
892 | var req = request('PATCH', url);
|
893 | if ('function' == typeof data) fn = data, data = null;
|
894 | if (data) req.send(data);
|
895 | if (fn) req.end(fn);
|
896 | return req;
|
897 | };
|
898 |
|
899 | /**
|
900 | * POST `url` with optional `data` and callback `fn(res)`.
|
901 | *
|
902 | * @param {String} url
|
903 | * @param {Mixed} [data]
|
904 | * @param {Function} [fn]
|
905 | * @return {Request}
|
906 | * @api public
|
907 | */
|
908 |
|
909 | request.post = function(url, data, fn){
|
910 | var req = request('POST', url);
|
911 | if ('function' == typeof data) fn = data, data = null;
|
912 | if (data) req.send(data);
|
913 | if (fn) req.end(fn);
|
914 | return req;
|
915 | };
|
916 |
|
917 | /**
|
918 | * PUT `url` with optional `data` and callback `fn(res)`.
|
919 | *
|
920 | * @param {String} url
|
921 | * @param {Mixed|Function} [data] or fn
|
922 | * @param {Function} [fn]
|
923 | * @return {Request}
|
924 | * @api public
|
925 | */
|
926 |
|
927 | request.put = function(url, data, fn){
|
928 | var req = request('PUT', url);
|
929 | if ('function' == typeof data) fn = data, data = null;
|
930 | if (data) req.send(data);
|
931 | if (fn) req.end(fn);
|
932 | return req;
|
933 | };
|
934 |
|
\ | No newline at end of file |