You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							920 lines
						
					
					
						
							21 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							920 lines
						
					
					
						
							21 KiB
						
					
					
				| /** | |
|  * Root reference for iframes. | |
|  */ | |
| 
 | |
| var root; | |
| if (typeof window !== 'undefined') { // Browser window | |
|   root = window; | |
| } else if (typeof self !== 'undefined') { // Web Worker | |
|   root = self; | |
| } else { // Other environments | |
|   console.warn("Using browser-only version of superagent in non-browser environment"); | |
|   root = this; | |
| } | |
| 
 | |
| var Emitter = require('component-emitter'); | |
| var RequestBase = require('./request-base'); | |
| var isObject = require('./is-object'); | |
| var ResponseBase = require('./response-base'); | |
| var Agent = require('./agent-base'); | |
| 
 | |
| /** | |
|  * Noop. | |
|  */ | |
| 
 | |
| function noop(){}; | |
| 
 | |
| /** | |
|  * Expose `request`. | |
|  */ | |
| 
 | |
| var request = exports = module.exports = function(method, url) { | |
|   // callback | |
|   if ('function' == typeof url) { | |
|     return new exports.Request('GET', method).end(url); | |
|   } | |
| 
 | |
|   // url first | |
|   if (1 == arguments.length) { | |
|     return new exports.Request('GET', method); | |
|   } | |
| 
 | |
|   return new exports.Request(method, url); | |
| } | |
| 
 | |
| exports.Request = Request; | |
| 
 | |
| /** | |
|  * Determine XHR. | |
|  */ | |
| 
 | |
| request.getXHR = function () { | |
|   if (root.XMLHttpRequest | |
|       && (!root.location || 'file:' != root.location.protocol | |
|           || !root.ActiveXObject)) { | |
|     return new XMLHttpRequest; | |
|   } else { | |
|     try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} | |
|     try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} | |
|     try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} | |
|     try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} | |
|   } | |
|   throw Error("Browser-only version of superagent could not find XHR"); | |
| }; | |
| 
 | |
| /** | |
|  * Removes leading and trailing whitespace, added to support IE. | |
|  * | |
|  * @param {String} s | |
|  * @return {String} | |
|  * @api private | |
|  */ | |
| 
 | |
| var trim = ''.trim | |
|   ? function(s) { return s.trim(); } | |
|   : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; | |
| 
 | |
| /** | |
|  * Serialize the given `obj`. | |
|  * | |
|  * @param {Object} obj | |
|  * @return {String} | |
|  * @api private | |
|  */ | |
| 
 | |
| function serialize(obj) { | |
|   if (!isObject(obj)) return obj; | |
|   var pairs = []; | |
|   for (var key in obj) { | |
|     pushEncodedKeyValuePair(pairs, key, obj[key]); | |
|   } | |
|   return pairs.join('&'); | |
| } | |
| 
 | |
| /** | |
|  * Helps 'serialize' with serializing arrays. | |
|  * Mutates the pairs array. | |
|  * | |
|  * @param {Array} pairs | |
|  * @param {String} key | |
|  * @param {Mixed} val | |
|  */ | |
| 
 | |
| function pushEncodedKeyValuePair(pairs, key, val) { | |
|   if (val != null) { | |
|     if (Array.isArray(val)) { | |
|       val.forEach(function(v) { | |
|         pushEncodedKeyValuePair(pairs, key, v); | |
|       }); | |
|     } else if (isObject(val)) { | |
|       for(var subkey in val) { | |
|         pushEncodedKeyValuePair(pairs, key + '[' + subkey + ']', val[subkey]); | |
|       } | |
|     } else { | |
|       pairs.push(encodeURIComponent(key) | |
|         + '=' + encodeURIComponent(val)); | |
|     } | |
|   } else if (val === null) { | |
|     pairs.push(encodeURIComponent(key)); | |
|   } | |
| } | |
| 
 | |
| /** | |
|  * Expose serialization method. | |
|  */ | |
| 
 | |
| request.serializeObject = serialize; | |
| 
 | |
| /** | |
|   * Parse the given x-www-form-urlencoded `str`. | |
|   * | |
|   * @param {String} str | |
|   * @return {Object} | |
|   * @api private | |
|   */ | |
| 
 | |
| function parseString(str) { | |
|   var obj = {}; | |
|   var pairs = str.split('&'); | |
|   var pair; | |
|   var pos; | |
| 
 | |
|   for (var i = 0, len = pairs.length; i < len; ++i) { | |
|     pair = pairs[i]; | |
|     pos = pair.indexOf('='); | |
|     if (pos == -1) { | |
|       obj[decodeURIComponent(pair)] = ''; | |
|     } else { | |
|       obj[decodeURIComponent(pair.slice(0, pos))] = | |
|         decodeURIComponent(pair.slice(pos + 1)); | |
|     } | |
|   } | |
| 
 | |
|   return obj; | |
| } | |
| 
 | |
| /** | |
|  * Expose parser. | |
|  */ | |
| 
 | |
| request.parseString = parseString; | |
| 
 | |
| /** | |
|  * Default MIME type map. | |
|  * | |
|  *     superagent.types.xml = 'application/xml'; | |
|  * | |
|  */ | |
| 
 | |
| request.types = { | |
|   html: 'text/html', | |
|   json: 'application/json', | |
|   xml: 'text/xml', | |
|   urlencoded: 'application/x-www-form-urlencoded', | |
|   'form': 'application/x-www-form-urlencoded', | |
|   'form-data': 'application/x-www-form-urlencoded' | |
| }; | |
| 
 | |
| /** | |
|  * Default serialization map. | |
|  * | |
|  *     superagent.serialize['application/xml'] = function(obj){ | |
|  *       return 'generated xml here'; | |
|  *     }; | |
|  * | |
|  */ | |
| 
 | |
| request.serialize = { | |
|   'application/x-www-form-urlencoded': serialize, | |
|   'application/json': JSON.stringify | |
| }; | |
| 
 | |
| /** | |
|   * Default parsers. | |
|   * | |
|   *     superagent.parse['application/xml'] = function(str){ | |
|   *       return { object parsed from str }; | |
|   *     }; | |
|   * | |
|   */ | |
| 
 | |
| request.parse = { | |
|   'application/x-www-form-urlencoded': parseString, | |
|   'application/json': JSON.parse | |
| }; | |
| 
 | |
| /** | |
|  * Parse the given header `str` into | |
|  * an object containing the mapped fields. | |
|  * | |
|  * @param {String} str | |
|  * @return {Object} | |
|  * @api private | |
|  */ | |
| 
 | |
| function parseHeader(str) { | |
|   var lines = str.split(/\r?\n/); | |
|   var fields = {}; | |
|   var index; | |
|   var line; | |
|   var field; | |
|   var val; | |
| 
 | |
|   for (var i = 0, len = lines.length; i < len; ++i) { | |
|     line = lines[i]; | |
|     index = line.indexOf(':'); | |
|     if (index === -1) { // could be empty line, just skip it | |
|       continue; | |
|     } | |
|     field = line.slice(0, index).toLowerCase(); | |
|     val = trim(line.slice(index + 1)); | |
|     fields[field] = val; | |
|   } | |
| 
 | |
|   return fields; | |
| } | |
| 
 | |
| /** | |
|  * Check if `mime` is json or has +json structured syntax suffix. | |
|  * | |
|  * @param {String} mime | |
|  * @return {Boolean} | |
|  * @api private | |
|  */ | |
| 
 | |
| function isJSON(mime) { | |
|   // should match /json or +json | |
|   // but not /json-seq | |
|   return /[\/+]json($|[^-\w])/.test(mime); | |
| } | |
| 
 | |
| /** | |
|  * Initialize a new `Response` with the given `xhr`. | |
|  * | |
|  *  - set flags (.ok, .error, etc) | |
|  *  - parse header | |
|  * | |
|  * Examples: | |
|  * | |
|  *  Aliasing `superagent` as `request` is nice: | |
|  * | |
|  *      request = superagent; | |
|  * | |
|  *  We can use the promise-like API, or pass callbacks: | |
|  * | |
|  *      request.get('/').end(function(res){}); | |
|  *      request.get('/', function(res){}); | |
|  * | |
|  *  Sending data can be chained: | |
|  * | |
|  *      request | |
|  *        .post('/user') | |
|  *        .send({ name: 'tj' }) | |
|  *        .end(function(res){}); | |
|  * | |
|  *  Or passed to `.send()`: | |
|  * | |
|  *      request | |
|  *        .post('/user') | |
|  *        .send({ name: 'tj' }, function(res){}); | |
|  * | |
|  *  Or passed to `.post()`: | |
|  * | |
|  *      request | |
|  *        .post('/user', { name: 'tj' }) | |
|  *        .end(function(res){}); | |
|  * | |
|  * Or further reduced to a single call for simple cases: | |
|  * | |
|  *      request | |
|  *        .post('/user', { name: 'tj' }, function(res){}); | |
|  * | |
|  * @param {XMLHTTPRequest} xhr | |
|  * @param {Object} options | |
|  * @api private | |
|  */ | |
| 
 | |
| function Response(req) { | |
|   this.req = req; | |
|   this.xhr = this.req.xhr; | |
|   // responseText is accessible only if responseType is '' or 'text' and on older browsers | |
|   this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined') | |
|      ? this.xhr.responseText | |
|      : null; | |
|   this.statusText = this.req.xhr.statusText; | |
|   var status = this.xhr.status; | |
|   // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request | |
|   if (status === 1223) { | |
|     status = 204; | |
|   } | |
|   this._setStatusProperties(status); | |
|   this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); | |
|   // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but | |
|   // getResponseHeader still works. so we get content-type even if getting | |
|   // other headers fails. | |
|   this.header['content-type'] = this.xhr.getResponseHeader('content-type'); | |
|   this._setHeaderProperties(this.header); | |
| 
 | |
|   if (null === this.text && req._responseType) { | |
|     this.body = this.xhr.response; | |
|   } else { | |
|     this.body = this.req.method != 'HEAD' | |
|       ? this._parseBody(this.text ? this.text : this.xhr.response) | |
|       : null; | |
|   } | |
| } | |
| 
 | |
| ResponseBase(Response.prototype); | |
| 
 | |
| /** | |
|  * Parse the given body `str`. | |
|  * | |
|  * Used for auto-parsing of bodies. Parsers | |
|  * are defined on the `superagent.parse` object. | |
|  * | |
|  * @param {String} str | |
|  * @return {Mixed} | |
|  * @api private | |
|  */ | |
| 
 | |
| Response.prototype._parseBody = function(str) { | |
|   var parse = request.parse[this.type]; | |
|   if (this.req._parser) { | |
|     return this.req._parser(this, str); | |
|   } | |
|   if (!parse && isJSON(this.type)) { | |
|     parse = request.parse['application/json']; | |
|   } | |
|   return parse && str && (str.length || str instanceof Object) | |
|     ? parse(str) | |
|     : null; | |
| }; | |
| 
 | |
| /** | |
|  * Return an `Error` representative of this response. | |
|  * | |
|  * @return {Error} | |
|  * @api public | |
|  */ | |
| 
 | |
| Response.prototype.toError = function(){ | |
|   var req = this.req; | |
|   var method = req.method; | |
|   var url = req.url; | |
| 
 | |
|   var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')'; | |
|   var err = new Error(msg); | |
|   err.status = this.status; | |
|   err.method = method; | |
|   err.url = url; | |
| 
 | |
|   return err; | |
| }; | |
| 
 | |
| /** | |
|  * Expose `Response`. | |
|  */ | |
| 
 | |
| request.Response = Response; | |
| 
 | |
| /** | |
|  * Initialize a new `Request` with the given `method` and `url`. | |
|  * | |
|  * @param {String} method | |
|  * @param {String} url | |
|  * @api public | |
|  */ | |
| 
 | |
| function Request(method, url) { | |
|   var self = this; | |
|   this._query = this._query || []; | |
|   this.method = method; | |
|   this.url = url; | |
|   this.header = {}; // preserves header name case | |
|   this._header = {}; // coerces header names to lowercase | |
|   this.on('end', function(){ | |
|     var err = null; | |
|     var res = null; | |
| 
 | |
|     try { | |
|       res = new Response(self); | |
|     } catch(e) { | |
|       err = new Error('Parser is unable to parse the response'); | |
|       err.parse = true; | |
|       err.original = e; | |
|       // issue #675: return the raw response if the response parsing fails | |
|       if (self.xhr) { | |
|         // ie9 doesn't have 'response' property | |
|         err.rawResponse = typeof self.xhr.responseType == 'undefined' ? self.xhr.responseText : self.xhr.response; | |
|         // issue #876: return the http status code if the response parsing fails | |
|         err.status = self.xhr.status ? self.xhr.status : null; | |
|         err.statusCode = err.status; // backwards-compat only | |
|       } else { | |
|         err.rawResponse = null; | |
|         err.status = null; | |
|       } | |
| 
 | |
|       return self.callback(err); | |
|     } | |
| 
 | |
|     self.emit('response', res); | |
| 
 | |
|     var new_err; | |
|     try { | |
|       if (!self._isResponseOK(res)) { | |
|         new_err = new Error(res.statusText || 'Unsuccessful HTTP response'); | |
|       } | |
|     } catch(custom_err) { | |
|       new_err = custom_err; // ok() callback can throw | |
|     } | |
| 
 | |
|     // #1000 don't catch errors from the callback to avoid double calling it | |
|     if (new_err) { | |
|       new_err.original = err; | |
|       new_err.response = res; | |
|       new_err.status = res.status; | |
|       self.callback(new_err, res); | |
|     } else { | |
|       self.callback(null, res); | |
|     } | |
|   }); | |
| } | |
| 
 | |
| /** | |
|  * Mixin `Emitter` and `RequestBase`. | |
|  */ | |
| 
 | |
| Emitter(Request.prototype); | |
| RequestBase(Request.prototype); | |
| 
 | |
| /** | |
|  * Set Content-Type to `type`, mapping values from `request.types`. | |
|  * | |
|  * Examples: | |
|  * | |
|  *      superagent.types.xml = 'application/xml'; | |
|  * | |
|  *      request.post('/') | |
|  *        .type('xml') | |
|  *        .send(xmlstring) | |
|  *        .end(callback); | |
|  * | |
|  *      request.post('/') | |
|  *        .type('application/xml') | |
|  *        .send(xmlstring) | |
|  *        .end(callback); | |
|  * | |
|  * @param {String} type | |
|  * @return {Request} for chaining | |
|  * @api public | |
|  */ | |
| 
 | |
| Request.prototype.type = function(type){ | |
|   this.set('Content-Type', request.types[type] || type); | |
|   return this; | |
| }; | |
| 
 | |
| /** | |
|  * Set Accept to `type`, mapping values from `request.types`. | |
|  * | |
|  * Examples: | |
|  * | |
|  *      superagent.types.json = 'application/json'; | |
|  * | |
|  *      request.get('/agent') | |
|  *        .accept('json') | |
|  *        .end(callback); | |
|  * | |
|  *      request.get('/agent') | |
|  *        .accept('application/json') | |
|  *        .end(callback); | |
|  * | |
|  * @param {String} accept | |
|  * @return {Request} for chaining | |
|  * @api public | |
|  */ | |
| 
 | |
| Request.prototype.accept = function(type){ | |
|   this.set('Accept', request.types[type] || type); | |
|   return this; | |
| }; | |
| 
 | |
| /** | |
|  * Set Authorization field value with `user` and `pass`. | |
|  * | |
|  * @param {String} user | |
|  * @param {String} [pass] optional in case of using 'bearer' as type | |
|  * @param {Object} options with 'type' property 'auto', 'basic' or 'bearer' (default 'basic') | |
|  * @return {Request} for chaining | |
|  * @api public | |
|  */ | |
| 
 | |
| Request.prototype.auth = function(user, pass, options){ | |
|   if (1 === arguments.length) pass = ''; | |
|   if (typeof pass === 'object' && pass !== null) { // pass is optional and can be replaced with options | |
|     options = pass; | |
|     pass = ''; | |
|   } | |
|   if (!options) { | |
|     options = { | |
|       type: 'function' === typeof btoa ? 'basic' : 'auto', | |
|     }; | |
|   } | |
| 
 | |
|   var encoder = function(string) { | |
|     if ('function' === typeof btoa) { | |
|       return btoa(string); | |
|     } | |
|     throw new Error('Cannot use basic auth, btoa is not a function'); | |
|   }; | |
| 
 | |
|   return this._auth(user, pass, options, encoder); | |
| }; | |
| 
 | |
| /** | |
|  * Add query-string `val`. | |
|  * | |
|  * Examples: | |
|  * | |
|  *   request.get('/shoes') | |
|  *     .query('size=10') | |
|  *     .query({ color: 'blue' }) | |
|  * | |
|  * @param {Object|String} val | |
|  * @return {Request} for chaining | |
|  * @api public | |
|  */ | |
| 
 | |
| Request.prototype.query = function(val){ | |
|   if ('string' != typeof val) val = serialize(val); | |
|   if (val) this._query.push(val); | |
|   return this; | |
| }; | |
| 
 | |
| /** | |
|  * Queue the given `file` as an attachment to the specified `field`, | |
|  * with optional `options` (or filename). | |
|  * | |
|  * ``` js | |
|  * request.post('/upload') | |
|  *   .attach('content', new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"})) | |
|  *   .end(callback); | |
|  * ``` | |
|  * | |
|  * @param {String} field | |
|  * @param {Blob|File} file | |
|  * @param {String|Object} options | |
|  * @return {Request} for chaining | |
|  * @api public | |
|  */ | |
| 
 | |
| Request.prototype.attach = function(field, file, options){ | |
|   if (file) { | |
|     if (this._data) { | |
|       throw Error("superagent can't mix .send() and .attach()"); | |
|     } | |
| 
 | |
|     this._getFormData().append(field, file, options || file.name); | |
|   } | |
|   return this; | |
| }; | |
| 
 | |
| Request.prototype._getFormData = function(){ | |
|   if (!this._formData) { | |
|     this._formData = new root.FormData(); | |
|   } | |
|   return this._formData; | |
| }; | |
| 
 | |
| /** | |
|  * Invoke the callback with `err` and `res` | |
|  * and handle arity check. | |
|  * | |
|  * @param {Error} err | |
|  * @param {Response} res | |
|  * @api private | |
|  */ | |
| 
 | |
| Request.prototype.callback = function(err, res){ | |
|   if (this._shouldRetry(err, res)) { | |
|     return this._retry(); | |
|   } | |
| 
 | |
|   var fn = this._callback; | |
|   this.clearTimeout(); | |
| 
 | |
|   if (err) { | |
|     if (this._maxRetries) err.retries = this._retries - 1; | |
|     this.emit('error', err); | |
|   } | |
| 
 | |
|   fn(err, res); | |
| }; | |
| 
 | |
| /** | |
|  * Invoke callback with x-domain error. | |
|  * | |
|  * @api private | |
|  */ | |
| 
 | |
| Request.prototype.crossDomainError = function(){ | |
|   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.'); | |
|   err.crossDomain = true; | |
| 
 | |
|   err.status = this.status; | |
|   err.method = this.method; | |
|   err.url = this.url; | |
| 
 | |
|   this.callback(err); | |
| }; | |
| 
 | |
| // This only warns, because the request is still likely to work | |
| Request.prototype.buffer = Request.prototype.ca = Request.prototype.agent = function(){ | |
|   console.warn("This is not supported in browser version of superagent"); | |
|   return this; | |
| }; | |
| 
 | |
| // This throws, because it can't send/receive data as expected | |
| Request.prototype.pipe = Request.prototype.write = function(){ | |
|   throw Error("Streaming is not supported in browser version of superagent"); | |
| }; | |
| 
 | |
| /** | |
|  * Check if `obj` is a host object, | |
|  * we don't want to serialize these :) | |
|  * | |
|  * @param {Object} obj | |
|  * @return {Boolean} | |
|  * @api private | |
|  */ | |
| Request.prototype._isHost = function _isHost(obj) { | |
|   // Native objects stringify to [object File], [object Blob], [object FormData], etc. | |
|   return obj && 'object' === typeof obj && !Array.isArray(obj) && Object.prototype.toString.call(obj) !== '[object Object]'; | |
| } | |
| 
 | |
| /** | |
|  * Initiate request, invoking callback `fn(res)` | |
|  * with an instanceof `Response`. | |
|  * | |
|  * @param {Function} fn | |
|  * @return {Request} for chaining | |
|  * @api public | |
|  */ | |
| 
 | |
| Request.prototype.end = function(fn){ | |
|   if (this._endCalled) { | |
|     console.warn("Warning: .end() was called twice. This is not supported in superagent"); | |
|   } | |
|   this._endCalled = true; | |
| 
 | |
|   // store callback | |
|   this._callback = fn || noop; | |
| 
 | |
|   // querystring | |
|   this._finalizeQueryString(); | |
| 
 | |
|   return this._end(); | |
| }; | |
| 
 | |
| Request.prototype._end = function() { | |
|   var self = this; | |
|   var xhr = (this.xhr = request.getXHR()); | |
|   var data = this._formData || this._data; | |
| 
 | |
|   this._setTimeouts(); | |
| 
 | |
|   // state change | |
|   xhr.onreadystatechange = function(){ | |
|     var readyState = xhr.readyState; | |
|     if (readyState >= 2 && self._responseTimeoutTimer) { | |
|       clearTimeout(self._responseTimeoutTimer); | |
|     } | |
|     if (4 != readyState) { | |
|       return; | |
|     } | |
| 
 | |
|     // In IE9, reads to any property (e.g. status) off of an aborted XHR will | |
|     // result in the error "Could not complete the operation due to error c00c023f" | |
|     var status; | |
|     try { status = xhr.status } catch(e) { status = 0; } | |
| 
 | |
|     if (!status) { | |
|       if (self.timedout || self._aborted) return; | |
|       return self.crossDomainError(); | |
|     } | |
|     self.emit('end'); | |
|   }; | |
| 
 | |
|   // progress | |
|   var handleProgress = function(direction, e) { | |
|     if (e.total > 0) { | |
|       e.percent = e.loaded / e.total * 100; | |
|     } | |
|     e.direction = direction; | |
|     self.emit('progress', e); | |
|   }; | |
|   if (this.hasListeners('progress')) { | |
|     try { | |
|       xhr.onprogress = handleProgress.bind(null, 'download'); | |
|       if (xhr.upload) { | |
|         xhr.upload.onprogress = handleProgress.bind(null, 'upload'); | |
|       } | |
|     } catch(e) { | |
|       // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist. | |
|       // Reported here: | |
|       // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context | |
|     } | |
|   } | |
| 
 | |
|   // initiate request | |
|   try { | |
|     if (this.username && this.password) { | |
|       xhr.open(this.method, this.url, true, this.username, this.password); | |
|     } else { | |
|       xhr.open(this.method, this.url, true); | |
|     } | |
|   } catch (err) { | |
|     // see #1149 | |
|     return this.callback(err); | |
|   } | |
| 
 | |
|   // CORS | |
|   if (this._withCredentials) xhr.withCredentials = true; | |
| 
 | |
|   // body | |
|   if (!this._formData && 'GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !this._isHost(data)) { | |
|     // serialize stuff | |
|     var contentType = this._header['content-type']; | |
|     var serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : '']; | |
|     if (!serialize && isJSON(contentType)) { | |
|       serialize = request.serialize['application/json']; | |
|     } | |
|     if (serialize) data = serialize(data); | |
|   } | |
| 
 | |
|   // set header fields | |
|   for (var field in this.header) { | |
|     if (null == this.header[field]) continue; | |
| 
 | |
|     if (this.header.hasOwnProperty(field)) | |
|       xhr.setRequestHeader(field, this.header[field]); | |
|   } | |
| 
 | |
|   if (this._responseType) { | |
|     xhr.responseType = this._responseType; | |
|   } | |
| 
 | |
|   // send stuff | |
|   this.emit('request', this); | |
| 
 | |
|   // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing) | |
|   // We need null here if data is undefined | |
|   xhr.send(typeof data !== 'undefined' ? data : null); | |
|   return this; | |
| }; | |
| 
 | |
| request.agent = function() { | |
|   return new Agent(); | |
| }; | |
| 
 | |
| ["GET", "POST", "OPTIONS", "PATCH", "PUT", "DELETE"].forEach(function(method) { | |
|   Agent.prototype[method.toLowerCase()] = function(url, fn) { | |
|     var req = new request.Request(method, url); | |
|     this._setDefaults(req); | |
|     if (fn) { | |
|       req.end(fn); | |
|     } | |
|     return req; | |
|   }; | |
| }); | |
| 
 | |
| Agent.prototype.del = Agent.prototype['delete']; | |
| 
 | |
| /** | |
|  * GET `url` with optional callback `fn(res)`. | |
|  * | |
|  * @param {String} url | |
|  * @param {Mixed|Function} [data] or fn | |
|  * @param {Function} [fn] | |
|  * @return {Request} | |
|  * @api public | |
|  */ | |
| 
 | |
| request.get = function(url, data, fn) { | |
|   var req = request('GET', url); | |
|   if ('function' == typeof data) (fn = data), (data = null); | |
|   if (data) req.query(data); | |
|   if (fn) req.end(fn); | |
|   return req; | |
| }; | |
| 
 | |
| /** | |
|  * HEAD `url` with optional callback `fn(res)`. | |
|  * | |
|  * @param {String} url | |
|  * @param {Mixed|Function} [data] or fn | |
|  * @param {Function} [fn] | |
|  * @return {Request} | |
|  * @api public | |
|  */ | |
| 
 | |
| request.head = function(url, data, fn) { | |
|   var req = request('HEAD', url); | |
|   if ('function' == typeof data) (fn = data), (data = null); | |
|   if (data) req.query(data); | |
|   if (fn) req.end(fn); | |
|   return req; | |
| }; | |
| 
 | |
| /** | |
|  * OPTIONS query to `url` with optional callback `fn(res)`. | |
|  * | |
|  * @param {String} url | |
|  * @param {Mixed|Function} [data] or fn | |
|  * @param {Function} [fn] | |
|  * @return {Request} | |
|  * @api public | |
|  */ | |
| 
 | |
| request.options = function(url, data, fn) { | |
|   var req = request('OPTIONS', url); | |
|   if ('function' == typeof data) (fn = data), (data = null); | |
|   if (data) req.send(data); | |
|   if (fn) req.end(fn); | |
|   return req; | |
| }; | |
| 
 | |
| /** | |
|  * DELETE `url` with optional `data` and callback `fn(res)`. | |
|  * | |
|  * @param {String} url | |
|  * @param {Mixed} [data] | |
|  * @param {Function} [fn] | |
|  * @return {Request} | |
|  * @api public | |
|  */ | |
| 
 | |
| function del(url, data, fn) { | |
|   var req = request('DELETE', url); | |
|   if ('function' == typeof data) (fn = data), (data = null); | |
|   if (data) req.send(data); | |
|   if (fn) req.end(fn); | |
|   return req; | |
| } | |
| 
 | |
| request['del'] = del; | |
| request['delete'] = del; | |
| 
 | |
| /** | |
|  * PATCH `url` with optional `data` and callback `fn(res)`. | |
|  * | |
|  * @param {String} url | |
|  * @param {Mixed} [data] | |
|  * @param {Function} [fn] | |
|  * @return {Request} | |
|  * @api public | |
|  */ | |
| 
 | |
| request.patch = function(url, data, fn) { | |
|   var req = request('PATCH', url); | |
|   if ('function' == typeof data) (fn = data), (data = null); | |
|   if (data) req.send(data); | |
|   if (fn) req.end(fn); | |
|   return req; | |
| }; | |
| 
 | |
| /** | |
|  * POST `url` with optional `data` and callback `fn(res)`. | |
|  * | |
|  * @param {String} url | |
|  * @param {Mixed} [data] | |
|  * @param {Function} [fn] | |
|  * @return {Request} | |
|  * @api public | |
|  */ | |
| 
 | |
| request.post = function(url, data, fn) { | |
|   var req = request('POST', url); | |
|   if ('function' == typeof data) (fn = data), (data = null); | |
|   if (data) req.send(data); | |
|   if (fn) req.end(fn); | |
|   return req; | |
| }; | |
| 
 | |
| /** | |
|  * PUT `url` with optional `data` and callback `fn(res)`. | |
|  * | |
|  * @param {String} url | |
|  * @param {Mixed|Function} [data] or fn | |
|  * @param {Function} [fn] | |
|  * @return {Request} | |
|  * @api public | |
|  */ | |
| 
 | |
| request.put = function(url, data, fn) { | |
|   var req = request('PUT', url); | |
|   if ('function' == typeof data) (fn = data), (data = null); | |
|   if (data) req.send(data); | |
|   if (fn) req.end(fn); | |
|   return req; | |
| };
 | |
| 
 |