aboutsummaryrefslogtreecommitdiff
path: root/node_modules/superagent/lib/node
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/superagent/lib/node')
-rw-r--r--node_modules/superagent/lib/node/agent.js90
-rw-r--r--node_modules/superagent/lib/node/index.js1053
-rw-r--r--node_modules/superagent/lib/node/parsers/image.js10
-rw-r--r--node_modules/superagent/lib/node/parsers/index.js8
-rw-r--r--node_modules/superagent/lib/node/parsers/json.js19
-rw-r--r--node_modules/superagent/lib/node/parsers/text.js7
-rw-r--r--node_modules/superagent/lib/node/parsers/urlencoded.js19
-rw-r--r--node_modules/superagent/lib/node/response.js123
-rw-r--r--node_modules/superagent/lib/node/unzip.js69
9 files changed, 1398 insertions, 0 deletions
diff --git a/node_modules/superagent/lib/node/agent.js b/node_modules/superagent/lib/node/agent.js
new file mode 100644
index 0000000..ad2a8f6
--- /dev/null
+++ b/node_modules/superagent/lib/node/agent.js
@@ -0,0 +1,90 @@
+
+/**
+ * Module dependencies.
+ */
+
+var CookieJar = require('cookiejar').CookieJar;
+var CookieAccess = require('cookiejar').CookieAccessInfo;
+var parse = require('url').parse;
+var request = require('../..');
+var methods = require('methods');
+
+/**
+ * Expose `Agent`.
+ */
+
+module.exports = Agent;
+
+/**
+ * Initialize a new `Agent`.
+ *
+ * @api public
+ */
+
+function Agent(options) {
+ if (!(this instanceof Agent)) return new Agent(options);
+ if (options) {
+ this._ca = options.ca;
+ this._key = options.key;
+ this._pfx = options.pfx;
+ this._cert = options.cert;
+ }
+ this.jar = new CookieJar;
+}
+
+/**
+ * Save the cookies in the given `res` to
+ * the agent's cookie jar for persistence.
+ *
+ * @param {Response} res
+ * @api private
+ */
+
+Agent.prototype._saveCookies = function(res){
+ var cookies = res.headers['set-cookie'];
+ if (cookies) this.jar.setCookies(cookies);
+};
+
+/**
+ * Attach cookies when available to the given `req`.
+ *
+ * @param {Request} req
+ * @api private
+ */
+
+Agent.prototype._attachCookies = function(req){
+ var url = parse(req.url);
+ var access = CookieAccess(url.hostname, url.pathname, 'https:' == url.protocol);
+ var cookies = this.jar.getCookies(access).toValueString();
+ req.cookies = cookies;
+};
+
+// generate HTTP verb methods
+if (methods.indexOf('del') == -1) {
+ // create a copy so we don't cause conflicts with
+ // other packages using the methods package and
+ // npm 3.x
+ methods = methods.slice(0);
+ methods.push('del');
+}
+methods.forEach(function(method){
+ var name = method;
+ method = 'del' == method ? 'delete' : method;
+
+ method = method.toUpperCase();
+ Agent.prototype[name] = function(url, fn){
+ var req = new request.Request(method, url);
+ req.ca(this._ca);
+ req.key(this._key);
+ req.pfx(this._pfx);
+ req.cert(this._cert);
+
+ req.on('response', this._saveCookies.bind(this));
+ req.on('redirect', this._saveCookies.bind(this));
+ req.on('redirect', this._attachCookies.bind(this, req));
+ this._attachCookies(req);
+
+ fn && req.end(fn);
+ return req;
+ };
+});
diff --git a/node_modules/superagent/lib/node/index.js b/node_modules/superagent/lib/node/index.js
new file mode 100644
index 0000000..ef06689
--- /dev/null
+++ b/node_modules/superagent/lib/node/index.js
@@ -0,0 +1,1053 @@
+
+/**
+ * Module dependencies.
+ */
+
+var debug = require('debug')('superagent');
+var formidable = require('formidable');
+var FormData = require('form-data');
+var Response = require('./response');
+var parse = require('url').parse;
+var format = require('url').format;
+var resolve = require('url').resolve;
+var methods = require('methods');
+var Stream = require('stream');
+var utils = require('../utils');
+var unzip = require('./unzip').unzip;
+var extend = require('extend');
+var mime = require('mime');
+var https = require('https');
+var http = require('http');
+var fs = require('fs');
+var qs = require('qs');
+var zlib = require('zlib');
+var util = require('util');
+var pkg = require('../../package.json');
+var RequestBase = require('../request-base');
+var isFunction = require('../is-function');
+var shouldRetry = require('../should-retry');
+
+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);
+}
+
+/**
+ * Expose `Request`.
+ */
+
+exports.Request = Request;
+
+/**
+ * Expose the agent function
+ */
+
+exports.agent = require('./agent');
+
+/**
+ * Noop.
+ */
+
+function noop(){};
+
+/**
+ * Expose `Response`.
+ */
+
+exports.Response = Response;
+
+/**
+ * Define "form" mime type.
+ */
+
+mime.define({
+ 'application/x-www-form-urlencoded': ['form', 'urlencoded', 'form-data']
+});
+
+/**
+ * Protocol map.
+ */
+
+exports.protocols = {
+ 'http:': http,
+ 'https:': https
+};
+
+/**
+ * Default serialization map.
+ *
+ * superagent.serialize['application/xml'] = function(obj){
+ * return 'generated xml here';
+ * };
+ *
+ */
+
+exports.serialize = {
+ 'application/x-www-form-urlencoded': qs.stringify,
+ 'application/json': JSON.stringify
+};
+
+/**
+ * Default parsers.
+ *
+ * superagent.parse['application/xml'] = function(res, fn){
+ * fn(null, res);
+ * };
+ *
+ */
+
+exports.parse = require('./parsers');
+
+/**
+ * Initialize internal header tracking properties on a request instance.
+ *
+ * @param {Object} req the instance
+ * @api private
+ */
+function _initHeaders(req) {
+ var ua = 'node-superagent/' + pkg.version;
+ req._header = { // coerces header names to lowercase
+ 'user-agent': ua
+ };
+ req.header = { // preserves header name case
+ 'User-Agent': ua
+ };
+}
+
+/**
+ * Initialize a new `Request` with the given `method` and `url`.
+ *
+ * @param {String} method
+ * @param {String|Object} url
+ * @api public
+ */
+
+function Request(method, url) {
+ Stream.call(this);
+ if ('string' != typeof url) url = format(url);
+ this._agent = false;
+ this._formData = null;
+ this.method = method;
+ this.url = url;
+ _initHeaders(this);
+ this.writable = true;
+ this._redirects = 0;
+ this.redirects(method === 'HEAD' ? 0 : 5);
+ this.cookies = '';
+ this.qs = {};
+ this.qsRaw = [];
+ this._redirectList = [];
+ this._streamRequest = false;
+ this.once('end', this.clearTimeout.bind(this));
+}
+
+/**
+ * Inherit from `Stream` (which inherits from `EventEmitter`).
+ * Mixin `RequestBase`.
+ */
+util.inherits(Request, Stream);
+RequestBase(Request.prototype);
+
+/**
+ * Queue the given `file` as an attachment to the specified `field`,
+ * with optional `options` (or filename).
+ *
+ * ``` js
+ * request.post('http://localhost/upload')
+ * .attach(new Buffer('<b>Hello world</b>'), 'hello.html')
+ * .end(callback);
+ * ```
+ *
+ * A filename may also be used:
+ *
+ * ``` js
+ * request.post('http://localhost/upload')
+ * .attach('files', 'image.jpg')
+ * .end(callback);
+ * ```
+ *
+ * @param {String} field
+ * @param {String|fs.ReadStream|Buffer} 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()");
+ }
+
+ var o = options || {};
+ if ('string' == typeof options) {
+ o = { filename: options };
+ }
+
+ if ('string' == typeof file) {
+ if (!o.filename) o.filename = file;
+ debug('creating `fs.ReadStream` instance for file: %s', file);
+ file = fs.createReadStream(file);
+ } else if (!o.filename && file.path) {
+ o.filename = file.path;
+ }
+
+ this._getFormData().append(field, file, o);
+ }
+ return this;
+};
+
+Request.prototype._getFormData = function() {
+ if (!this._formData) {
+ this._formData = new FormData();
+ var that = this;
+ this._formData.on('error', function(err) {
+ that.emit('error', err);
+ that.abort();
+ });
+ }
+ return this._formData;
+};
+
+/**
+ * Gets/sets the `Agent` to use for this HTTP request. The default (if this
+ * function is not called) is to opt out of connection pooling (`agent: false`).
+ *
+ * @param {http.Agent} agent
+ * @return {http.Agent}
+ * @api public
+ */
+
+Request.prototype.agent = function(agent){
+ if (!arguments.length) return this._agent;
+ this._agent = agent;
+ return this;
+};
+
+/**
+ * Set _Content-Type_ response header passed through `mime.lookup()`.
+ *
+ * Examples:
+ *
+ * request.post('/')
+ * .type('xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * request.post('/')
+ * .type('json')
+ * .send(jsonstring)
+ * .end(callback);
+ *
+ * request.post('/')
+ * .type('application/json')
+ * .send(jsonstring)
+ * .end(callback);
+ *
+ * @param {String} type
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.type = function(type){
+ return this.set('Content-Type', ~type.indexOf('/')
+ ? type
+ : mime.lookup(type));
+};
+
+/**
+ * Set _Accept_ response header passed through `mime.lookup()`.
+ *
+ * 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){
+ return this.set('Accept', ~type.indexOf('/')
+ ? type
+ : mime.lookup(type));
+};
+
+/**
+ * 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) {
+ this.qsRaw.push(val);
+ return this;
+ }
+
+ extend(this.qs, val);
+ return this;
+};
+
+/**
+ * Write raw `data` / `encoding` to the socket.
+ *
+ * @param {Buffer|String} data
+ * @param {String} encoding
+ * @return {Boolean}
+ * @api public
+ */
+
+Request.prototype.write = function(data, encoding){
+ var req = this.request();
+ if (!this._streamRequest) {
+ this._streamRequest = true;
+ }
+ return req.write(data, encoding);
+};
+
+/**
+ * Pipe the request body to `stream`.
+ *
+ * @param {Stream} stream
+ * @param {Object} options
+ * @return {Stream}
+ * @api public
+ */
+
+Request.prototype.pipe = function(stream, options){
+ this.piped = true; // HACK...
+ this.buffer(false);
+ this.end();
+ return this._pipeContinue(stream, options);
+};
+
+Request.prototype._pipeContinue = function(stream, options){
+ var self = this;
+ this.req.once('response', function(res){
+ // redirect
+ var redirect = isRedirect(res.statusCode);
+ if (redirect && self._redirects++ != self._maxRedirects) {
+ return self._redirect(res)._pipeContinue(stream, options);
+ }
+
+ self.res = res;
+ self._emitResponse();
+ if (self._aborted) return;
+
+ if (self._shouldUnzip(res)) {
+ res.pipe(zlib.createUnzip()).pipe(stream, options);
+ } else {
+ res.pipe(stream, options);
+ }
+ res.once('end', function(){
+ self.emit('end');
+ });
+ });
+ return stream;
+};
+
+/**
+ * Enable / disable buffering.
+ *
+ * @return {Boolean} [val]
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.buffer = function(val){
+ this._buffer = (false !== val);
+ return this;
+};
+
+/**
+ * Redirect to `url
+ *
+ * @param {IncomingMessage} res
+ * @return {Request} for chaining
+ * @api private
+ */
+
+Request.prototype._redirect = function(res){
+ var url = res.headers.location;
+ if (!url) {
+ return this.callback(new Error('No location header for redirect'), res);
+ }
+
+ debug('redirect %s -> %s', this.url, url);
+
+ // location
+ url = resolve(this.url, url);
+
+ // ensure the response is being consumed
+ // this is required for Node v0.10+
+ res.resume();
+
+ var headers = this.req._headers;
+
+ var shouldStripCookie = parse(url).host !== parse(this.url).host;
+
+ // implementation of 302 following defacto standard
+ if (res.statusCode == 301 || res.statusCode == 302){
+ // strip Content-* related fields
+ // in case of POST etc
+ headers = utils.cleanHeader(this.req._headers, shouldStripCookie);
+
+ // force GET
+ this.method = 'HEAD' == this.method
+ ? 'HEAD'
+ : 'GET';
+
+ // clear data
+ this._data = null;
+ }
+ // 303 is always GET
+ if (res.statusCode == 303) {
+ // strip Content-* related fields
+ // in case of POST etc
+ headers = utils.cleanHeader(this.req._headers, shouldStripCookie);
+
+ // force method
+ this.method = 'GET';
+
+ // clear data
+ this._data = null;
+ }
+ // 307 preserves method
+ // 308 preserves method
+ delete headers.host;
+
+ delete this.req;
+ delete this._formData;
+
+ // remove all add header except User-Agent
+ _initHeaders(this)
+
+ // redirect
+ this._endCalled = false;
+ this.url = url;
+ this.qs = {};
+ this.qsRaw = [];
+ this.set(headers);
+ this.emit('redirect', res);
+ this._redirectList.push(this.url);
+ this.end(this._callback);
+ return this;
+};
+
+/**
+ * Set Authorization field value with `user` and `pass`.
+ *
+ * Examples:
+ *
+ * .auth('tobi', 'learnboost')
+ * .auth('tobi:learnboost')
+ * .auth('tobi')
+ * .auth(accessToken, { type: 'bearer' })
+ *
+ * @param {String} user
+ * @param {String} [pass]
+ * @param {Object} [options] options with authorization type 'basic' or 'bearer' ('basic' is default)
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.auth = function(user, pass, options){
+ if (1 === arguments.length) pass = '';
+ if (2 === arguments.length && typeof pass === 'object') options = pass;
+ if (!options) {
+ options = { type: 'basic' };
+ }
+ switch (options.type) {
+ case 'bearer':
+ return this.set('Authorization', 'Bearer ' + user);
+
+ default: // 'basic'
+ if (!~user.indexOf(':')) user = user + ':';
+ var str = new Buffer(user + pass).toString('base64');
+ return this.set('Authorization', 'Basic ' + str);
+ }
+};
+
+/**
+ * Set the certificate authority option for https request.
+ *
+ * @param {Buffer | Array} cert
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.ca = function(cert){
+ this._ca = cert;
+ return this;
+};
+
+/**
+ * Set the client certificate key option for https request.
+ *
+ * @param {Buffer | String} cert
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.key = function(cert){
+ this._key = cert;
+ return this;
+};
+
+/**
+ * Set the key, certificate, and CA certs of the client in PFX or PKCS12 format.
+ *
+ * @param {Buffer | String} cert
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.pfx = function(cert){
+ this._pfx = cert;
+ return this;
+};
+
+/**
+ * Set the client certificate option for https request.
+ *
+ * @param {Buffer | String} cert
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.cert = function(cert){
+ this._cert = cert;
+ return this;
+};
+
+/**
+ * Return an http[s] request.
+ *
+ * @return {OutgoingMessage}
+ * @api private
+ */
+
+Request.prototype.request = function(){
+ if (this.req) return this.req;
+
+ var self = this;
+ var options = {};
+ var url = this.url;
+ var retries = this._retries;
+
+ // default to http://
+ if (0 != url.indexOf('http')) url = 'http://' + url;
+ url = parse(url);
+
+ // support unix sockets
+ if (/^https?\+unix:/.test(url.protocol) === true) {
+ // get the protocol
+ url.protocol = url.protocol.split('+')[0] + ':';
+
+ // get the socket, path
+ var unixParts = url.path.match(/^([^/]+)(.+)$/);
+ options.socketPath = unixParts[1].replace(/%2F/g, '/');
+ url.pathname = unixParts[2];
+ }
+
+ // options
+ options.method = this.method;
+ options.port = url.port;
+ options.path = url.pathname;
+ options.host = url.hostname;
+ options.ca = this._ca;
+ options.key = this._key;
+ options.pfx = this._pfx;
+ options.cert = this._cert;
+ options.agent = this._agent;
+
+ // initiate request
+ var mod = exports.protocols[url.protocol];
+
+ // request
+ var req = this.req = mod.request(options);
+ if ('HEAD' != options.method) {
+ req.setHeader('Accept-Encoding', 'gzip, deflate');
+ }
+ this.protocol = url.protocol;
+ this.host = url.host;
+
+ // expose events
+ req.once('drain', function(){ self.emit('drain'); });
+
+ req.once('error', function(err){
+ // flag abortion here for out timeouts
+ // because node will emit a faux-error "socket hang up"
+ // when request is aborted before a connection is made
+ if (self._aborted) return;
+ // if not the same, we are in the **old** (cancelled) request,
+ // so need to continue (same as for above)
+ if (self._retries !== retries) return;
+ // if we've received a response then we don't want to let
+ // an error in the request blow up the response
+ if (self.response) return;
+ self.callback(err);
+ });
+
+ // auth
+ if (url.auth) {
+ var auth = url.auth.split(':');
+ this.auth(auth[0], auth[1]);
+ }
+
+ // query
+ if (url.search)
+ this.query(url.search.substr(1));
+
+ // add cookies
+ if (this.cookies) req.setHeader('Cookie', this.cookies);
+
+ for (var key in this.header) {
+ if (this.header.hasOwnProperty(key))
+ req.setHeader(key, this.header[key]);
+ }
+
+ try {
+ this._appendQueryString(req);
+ } catch (e) {
+ return this.emit('error', e);
+ }
+
+ return req;
+};
+
+/**
+ * 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){
+ // console.log(this._retries, this._maxRetries)
+ if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) {
+ return this._retry();
+ }
+
+ // Avoid the error which is emitted from 'socket hang up' to cause the fn undefined error on JS runtime.
+ var fn = this._callback || noop;
+ this.clearTimeout();
+ if (this.called) return console.warn('superagent: double callback bug');
+ this.called = true;
+
+ if (!err) {
+ if (this._isResponseOK(res)) {
+ return fn(err, res);
+ }
+
+ var msg = 'Unsuccessful HTTP response';
+ if (res) {
+ msg = http.STATUS_CODES[res.status] || msg;
+ }
+ err = new Error(msg);
+ err.status = res ? res.status : undefined;
+ }
+
+ err.response = res;
+ if (this._maxRetries) err.retries = this._retries - 1;
+
+ // only emit error event if there is a listener
+ // otherwise we assume the callback to `.end()` will get the error
+ if (err && this.listeners('error').length > 0) {
+ this.emit('error', err);
+ }
+
+ fn(err, res);
+};
+
+/**
+ * Compose querystring to append to req.path
+ *
+ * @return {String} querystring
+ * @api private
+ */
+
+Request.prototype._appendQueryString = function(req){
+ var query = qs.stringify(this.qs, { indices: false, strictNullHandling: true });
+ query += ((query.length && this.qsRaw.length) ? '&' : '') + this.qsRaw.join('&');
+ req.path += query.length ? (~req.path.indexOf('?') ? '&' : '?') + query : '';
+
+ if (this._sort) {
+ var index = req.path.indexOf('?');
+ if (index >= 0) {
+ var queryArr = req.path.substring(index + 1).split('&');
+ if (isFunction(this._sort)) {
+ queryArr.sort(this._sort);
+ } else {
+ queryArr.sort();
+ }
+ req.path = req.path.substring(0, index) + '?' + queryArr.join('&');
+ }
+ }
+};
+
+/**
+ * Check if `obj` is a host object,
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+Request.prototype._isHost = function _isHost(obj) {
+ return Buffer.isBuffer(obj) || obj instanceof Stream || obj instanceof FormData;
+}
+
+/**
+ * Initiate request, invoking callback `fn(err, res)`
+ * with an instanceof `Response`.
+ *
+ * @param {Function} fn
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype._emitResponse = function(body, files){
+ var response = new Response(this);
+ this.response = response;
+ response.redirects = this._redirectList;
+ if (undefined !== body) {
+ response.body = body;
+ }
+ response.files = files;
+ this.emit('response', response);
+ return response;
+};
+
+Request.prototype.end = function(fn){
+ this.request();
+ debug('%s %s', this.method, this.url);
+
+ 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;
+
+ return this._end();
+};
+
+Request.prototype._end = function() {
+ var self = this;
+ var data = this._data;
+ var req = this.req;
+ var buffer = this._buffer;
+ var method = this.method;
+
+ this._setTimeouts();
+
+ // body
+ if ('HEAD' != method && !req._headerSent) {
+ // serialize stuff
+ if ('string' != typeof data) {
+ var contentType = req.getHeader('Content-Type')
+ // Parse out just the content type from the header (ignore the charset)
+ if (contentType) contentType = contentType.split(';')[0]
+ var serialize = exports.serialize[contentType];
+ if (!serialize && isJSON(contentType)) {
+ serialize = exports.serialize['application/json'];
+ }
+ if (serialize) data = serialize(data);
+ }
+
+ // content-length
+ if (data && !req.getHeader('Content-Length')) {
+ req.setHeader('Content-Length', Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data));
+ }
+ }
+
+ // response
+ req.once('response', function(res){
+ debug('%s %s -> %s', self.method, self.url, res.statusCode);
+
+ if (self._responseTimeoutTimer) {
+ clearTimeout(self._responseTimeoutTimer);
+ }
+
+ if (self.piped) {
+ return;
+ }
+
+ var max = self._maxRedirects;
+ var mime = utils.type(res.headers['content-type'] || '') || 'text/plain';
+ var type = mime.split('/')[0];
+ var multipart = 'multipart' == type;
+ var redirect = isRedirect(res.statusCode);
+ var parser = self._parser;
+ var responseType = self._responseType;
+
+ self.res = res;
+
+ // redirect
+ if (redirect && self._redirects++ != max) {
+ return self._redirect(res);
+ }
+
+ if ('HEAD' == self.method) {
+ self.emit('end');
+ self.callback(null, self._emitResponse());
+ return;
+ }
+
+ // zlib support
+ if (self._shouldUnzip(res)) {
+ unzip(req, res);
+ }
+
+ if (!parser) {
+ if (responseType) {
+ parser = exports.parse.image; // It's actually a generic Buffer
+ buffer = true;
+ } else if (multipart) {
+ var form = new formidable.IncomingForm();
+ parser = form.parse.bind(form);
+ buffer = true;
+ } else if (isImageOrVideo(mime)) {
+ parser = exports.parse.image;
+ buffer = true; // For backwards-compatibility buffering default is ad-hoc MIME-dependent
+ } else if (exports.parse[mime]) {
+ parser = exports.parse[mime];
+ } else if ('text' == type) {
+ parser = exports.parse.text;
+ buffer = (buffer !== false);
+
+ // everyone wants their own white-labeled json
+ } else if (isJSON(mime)) {
+ parser = exports.parse['application/json'];
+ buffer = (buffer !== false);
+ } else if (buffer) {
+ parser = exports.parse.text;
+ }
+ }
+
+ // by default only buffer text/*, json and messed up thing from hell
+ if (undefined === buffer && isText(mime) || isJSON(mime)) {
+ buffer = true;
+ }
+
+ var parserHandlesEnd = false;
+ if (parser) {
+ try {
+ // Unbuffered parsers are supposed to emit response early,
+ // which is weird BTW, because response.body won't be there.
+ parserHandlesEnd = buffer;
+
+ parser(res, function(err, obj, files) {
+ if (self.timedout) {
+ // Timeout has already handled all callbacks
+ return;
+ }
+
+ // Intentional (non-timeout) abort is supposed to preserve partial response,
+ // even if it doesn't parse.
+ if (err && !self._aborted) {
+ return self.callback(err);
+ }
+
+ if (parserHandlesEnd) {
+ self.emit('end');
+ self.callback(null, self._emitResponse(obj, files));
+ }
+ });
+ } catch (err) {
+ self.callback(err);
+ return;
+ }
+ }
+
+ self.res = res;
+
+ // unbuffered
+ if (!buffer) {
+ debug('unbuffered %s %s', self.method, self.url);
+ self.callback(null, self._emitResponse());
+ if (multipart) return // allow multipart to handle end event
+ res.once('end', function(){
+ debug('end %s %s', self.method, self.url);
+ self.emit('end');
+ })
+ return;
+ }
+
+ // terminating events
+ res.once('error', function(err){
+ self.callback(err, null);
+ });
+ if (!parserHandlesEnd) res.once('end', function(){
+ debug('end %s %s', self.method, self.url);
+ // TODO: unless buffering emit earlier to stream
+ self.emit('end');
+ self.callback(null, self._emitResponse());
+ });
+ });
+
+ this.emit('request', this);
+
+ // if a FormData instance got created, then we send that as the request body
+ var formData = this._formData;
+ if (formData) {
+
+ // set headers
+ var headers = formData.getHeaders();
+ for (var i in headers) {
+ debug('setting FormData header: "%s: %s"', i, headers[i]);
+ req.setHeader(i, headers[i]);
+ }
+
+ // attempt to get "Content-Length" header
+ formData.getLength(function(err, length) {
+ // TODO: Add chunked encoding when no length (if err)
+
+ debug('got FormData Content-Length: %s', length);
+ if ('number' == typeof length) {
+ req.setHeader('Content-Length', length);
+ }
+
+ var getProgressMonitor = function () {
+ var lengthComputable = true;
+ var total = req.getHeader('Content-Length');
+ var loaded = 0;
+
+ var progress = new Stream.Transform();
+ progress._transform = function (chunk, encoding, cb) {
+ loaded += chunk.length;
+ self.emit('progress', {
+ direction: 'upload',
+ lengthComputable: lengthComputable,
+ loaded: loaded,
+ total: total
+ });
+ cb(null, chunk);
+ };
+ return progress;
+ };
+ formData.pipe(getProgressMonitor()).pipe(req);
+ });
+ } else {
+ req.end(data);
+ }
+
+ return this;
+};
+
+/**
+ * Check whether response has a non-0-sized gzip-encoded body
+ */
+Request.prototype._shouldUnzip = function(res){
+ if (res.statusCode === 204 || res.statusCode === 304) {
+ // These aren't supposed to have any body
+ return false;
+ }
+
+ // header content is a string, and distinction between 0 and no information is crucial
+ if ('0' === res.headers['content-length']) {
+ // We know that the body is empty (unfortunately, this check does not cover chunked encoding)
+ return false;
+ }
+
+ // console.log(res);
+ return /^\s*(?:deflate|gzip)\s*$/.test(res.headers['content-encoding']);
+};
+
+// generate HTTP verb methods
+if (methods.indexOf('del') == -1) {
+ // create a copy so we don't cause conflicts with
+ // other packages using the methods package and
+ // npm 3.x
+ methods = methods.slice(0);
+ methods.push('del');
+}
+methods.forEach(function(method){
+ var name = method;
+ method = 'del' == method ? 'delete' : method;
+
+ method = method.toUpperCase();
+ request[name] = function(url, data, fn){
+ var req = request(method, url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ fn && req.end(fn);
+ return req;
+ };
+});
+
+/**
+ * Check if `mime` is text and should be buffered.
+ *
+ * @param {String} mime
+ * @return {Boolean}
+ * @api public
+ */
+
+function isText(mime) {
+ var parts = mime.split('/');
+ var type = parts[0];
+ var subtype = parts[1];
+
+ return 'text' == type
+ || 'x-www-form-urlencoded' == subtype;
+}
+
+function isImageOrVideo(mime) {
+ var type = mime.split('/')[0];
+
+ return 'image' == type || 'video' == type;
+}
+
+/**
+ * Check if `mime` is json or has +json structured syntax suffix.
+ *
+ * @param {String} mime
+ * @return {Boolean}
+ * @api private
+ */
+
+function isJSON(mime) {
+ return /[\/+]json\b/.test(mime);
+}
+
+/**
+ * Check if we should follow the redirect `code`.
+ *
+ * @param {Number} code
+ * @return {Boolean}
+ * @api private
+ */
+
+function isRedirect(code) {
+ return ~[301, 302, 303, 305, 307, 308].indexOf(code);
+}
diff --git a/node_modules/superagent/lib/node/parsers/image.js b/node_modules/superagent/lib/node/parsers/image.js
new file mode 100644
index 0000000..b3e0ebc
--- /dev/null
+++ b/node_modules/superagent/lib/node/parsers/image.js
@@ -0,0 +1,10 @@
+module.exports = function(res, fn){
+ var data = []; // Binary data needs binary storage
+
+ res.on('data', function(chunk){
+ data.push(chunk);
+ });
+ res.on('end', function () {
+ fn(null, Buffer.concat(data));
+ });
+}; \ No newline at end of file
diff --git a/node_modules/superagent/lib/node/parsers/index.js b/node_modules/superagent/lib/node/parsers/index.js
new file mode 100644
index 0000000..b6f4bf6
--- /dev/null
+++ b/node_modules/superagent/lib/node/parsers/index.js
@@ -0,0 +1,8 @@
+
+exports['application/x-www-form-urlencoded'] = require('./urlencoded');
+exports['application/json'] = require('./json');
+exports.text = require('./text');
+
+var binary = require('./image');
+exports['application/octet-stream'] = binary;
+exports.image = binary;
diff --git a/node_modules/superagent/lib/node/parsers/json.js b/node_modules/superagent/lib/node/parsers/json.js
new file mode 100644
index 0000000..b71662d
--- /dev/null
+++ b/node_modules/superagent/lib/node/parsers/json.js
@@ -0,0 +1,19 @@
+
+module.exports = function parseJSON(res, fn){
+ res.text = '';
+ res.setEncoding('utf8');
+ res.on('data', function(chunk){ res.text += chunk;});
+ res.on('end', function(){
+ try {
+ var body = res.text && JSON.parse(res.text);
+ } catch (e) {
+ var err = e;
+ // issue #675: return the raw response if the response parsing fails
+ err.rawResponse = res.text || null;
+ // issue #876: return the http status code if the response parsing fails
+ err.statusCode = res.statusCode;
+ } finally {
+ fn(err, body);
+ }
+ });
+};
diff --git a/node_modules/superagent/lib/node/parsers/text.js b/node_modules/superagent/lib/node/parsers/text.js
new file mode 100644
index 0000000..03575c6
--- /dev/null
+++ b/node_modules/superagent/lib/node/parsers/text.js
@@ -0,0 +1,7 @@
+
+module.exports = function(res, fn){
+ res.text = '';
+ res.setEncoding('utf8');
+ res.on('data', function(chunk){ res.text += chunk; });
+ res.on('end', fn);
+}; \ No newline at end of file
diff --git a/node_modules/superagent/lib/node/parsers/urlencoded.js b/node_modules/superagent/lib/node/parsers/urlencoded.js
new file mode 100644
index 0000000..245c665
--- /dev/null
+++ b/node_modules/superagent/lib/node/parsers/urlencoded.js
@@ -0,0 +1,19 @@
+
+/**
+ * Module dependencies.
+ */
+
+var qs = require('qs');
+
+module.exports = function(res, fn){
+ res.text = '';
+ res.setEncoding('ascii');
+ res.on('data', function(chunk){ res.text += chunk; });
+ res.on('end', function(){
+ try {
+ fn(null, qs.parse(res.text));
+ } catch (err) {
+ fn(err);
+ }
+ });
+}; \ No newline at end of file
diff --git a/node_modules/superagent/lib/node/response.js b/node_modules/superagent/lib/node/response.js
new file mode 100644
index 0000000..9a9ea15
--- /dev/null
+++ b/node_modules/superagent/lib/node/response.js
@@ -0,0 +1,123 @@
+
+/**
+ * Module dependencies.
+ */
+
+var util = require('util');
+var Stream = require('stream');
+var ResponseBase = require('../response-base');
+
+/**
+ * Expose `Response`.
+ */
+
+module.exports = Response;
+
+/**
+ * Initialize a new `Response` with the given `xhr`.
+ *
+ * - set flags (.ok, .error, etc)
+ * - parse header
+ *
+ * @param {Request} req
+ * @param {Object} options
+ * @constructor
+ * @extends {Stream}
+ * @implements {ReadableStream}
+ * @api private
+ */
+
+function Response(req) {
+ Stream.call(this);
+ var res = this.res = req.res;
+ this.request = req;
+ this.req = req.req;
+ this.text = res.text;
+ this.body = res.body !== undefined ? res.body : {};
+ this.files = res.files || {};
+ this.buffered = 'string' == typeof this.text;
+ this.header = this.headers = res.headers;
+ this._setStatusProperties(res.statusCode);
+ this._setHeaderProperties(this.header);
+ this.setEncoding = res.setEncoding.bind(res);
+ res.on('data', this.emit.bind(this, 'data'));
+ res.on('end', this.emit.bind(this, 'end'));
+ res.on('close', this.emit.bind(this, 'close'));
+ res.on('error', this.emit.bind(this, 'error'));
+}
+
+/**
+ * Inherit from `Stream`.
+ */
+
+util.inherits(Response, Stream);
+ResponseBase(Response.prototype);
+
+
+/**
+ * Implements methods of a `ReadableStream`
+ */
+
+Response.prototype.destroy = function(err){
+ this.res.destroy(err);
+};
+
+/**
+ * Pause.
+ */
+
+Response.prototype.pause = function(){
+ this.res.pause();
+};
+
+/**
+ * Resume.
+ */
+
+Response.prototype.resume = function(){
+ this.res.resume();
+};
+
+/**
+ * Return an `Error` representative of this response.
+ *
+ * @return {Error}
+ * @api public
+ */
+
+Response.prototype.toError = function(){
+ var req = this.req;
+ var method = req.method;
+ var path = req.path;
+
+ var msg = 'cannot ' + method + ' ' + path + ' (' + this.status + ')';
+ var err = new Error(msg);
+ err.status = this.status;
+ err.text = this.text;
+ err.method = method;
+ err.path = path;
+
+ return err;
+};
+
+
+Response.prototype.setStatusProperties = function(status){
+ console.warn("In superagent 2.x setStatusProperties is a private method");
+ return this._setStatusProperties(status);
+};
+
+/**
+ * To json.
+ *
+ * @return {Object}
+ * @api public
+ */
+
+Response.prototype.toJSON = function(){
+ return {
+ req: this.request.toJSON(),
+ header: this.header,
+ status: this.status,
+ text: this.text
+ };
+};
diff --git a/node_modules/superagent/lib/node/unzip.js b/node_modules/superagent/lib/node/unzip.js
new file mode 100644
index 0000000..2911fbc
--- /dev/null
+++ b/node_modules/superagent/lib/node/unzip.js
@@ -0,0 +1,69 @@
+
+/**
+ * Module dependencies.
+ */
+
+var StringDecoder = require('string_decoder').StringDecoder;
+var Stream = require('stream');
+var zlib = require('zlib');
+
+/**
+ * Buffers response data events and re-emits when they're unzipped.
+ *
+ * @param {Request} req
+ * @param {Response} res
+ * @api private
+ */
+
+exports.unzip = function(req, res){
+ var unzip = zlib.createUnzip();
+ var stream = new Stream;
+ var decoder;
+
+ // make node responseOnEnd() happy
+ stream.req = req;
+
+ unzip.on('error', function(err){
+ if (err && err.code === 'Z_BUF_ERROR') { // unexpected end of file is ignored by browsers and curl
+ stream.emit('end');
+ return;
+ }
+ stream.emit('error', err);
+ });
+
+ // pipe to unzip
+ res.pipe(unzip);
+
+ // override `setEncoding` to capture encoding
+ res.setEncoding = function(type){
+ decoder = new StringDecoder(type);
+ };
+
+ // decode upon decompressing with captured encoding
+ unzip.on('data', function(buf){
+ if (decoder) {
+ var str = decoder.write(buf);
+ if (str.length) stream.emit('data', str);
+ } else {
+ stream.emit('data', buf);
+ }
+ });
+
+ unzip.on('end', function(){
+ stream.emit('end');
+ });
+
+ // override `on` to capture data listeners
+ var _on = res.on;
+ res.on = function(type, fn){
+ if ('data' == type || 'end' == type) {
+ stream.on(type, fn);
+ } else if ('error' == type) {
+ stream.on(type, fn);
+ _on.call(res, type, fn);
+ } else {
+ _on.call(res, type, fn);
+ }
+ return this;
+ };
+}; \ No newline at end of file