superagent
Advanced tools
Comparing version 0.2.0 to 0.3.0
0.3.0 / 2012-01-24 | ||
================== | ||
* Added deflate/gzip support [guillermo] | ||
* Added `res.type` (Content-Type void of params) | ||
* Added `res.statusCode` to mirror node | ||
* Added `res.headers` to mirror node | ||
* Changed: parsers take callbacks | ||
* Fixed optional schema support. Closes #49 | ||
0.2.0 / 2012-01-05 | ||
@@ -3,0 +13,0 @@ ================== |
@@ -0,1 +1,2 @@ | ||
/*! | ||
@@ -14,2 +15,3 @@ * superagent | ||
, format = require('url').format | ||
, utils = require('./utils') | ||
, Part = require('./part') | ||
@@ -30,3 +32,3 @@ , https = require('https') | ||
exports.version = '0.2.0'; | ||
exports.version = '0.3.0'; | ||
@@ -96,4 +98,4 @@ /** | ||
* | ||
* superagent.parse['application/xml'] = function(str){ | ||
* return { object parsed from str }; | ||
* superagent.parse['application/xml'] = function(req, fn){ | ||
* fn(null, result); | ||
* }; | ||
@@ -104,4 +106,27 @@ * | ||
exports.parse = { | ||
'application/x-www-form-urlencoded': qs.parse | ||
, 'application/json': JSON.parse | ||
'application/x-www-form-urlencoded': function(req, fn){ | ||
var buf = ''; | ||
req.setEncoding('ascii'); | ||
req.on('data', function(chunk){ buf += chunk; }); | ||
req.on('end', function(){ | ||
try { | ||
fn(null, qs.parse(buf)); | ||
} catch (err) { | ||
fn(err); | ||
} | ||
}); | ||
}, | ||
'application/json': function(req, fn){ | ||
var buf = ''; | ||
req.setEncoding('utf8'); | ||
req.on('data', function(chunk){ buf += chunk; }); | ||
req.on('end', function(){ | ||
try { | ||
fn(null, JSON.parse(buf)); | ||
} catch (err) { | ||
fn(err); | ||
} | ||
}); | ||
} | ||
}; | ||
@@ -125,7 +150,7 @@ | ||
this.res = res; | ||
this.text = res.text | ||
this.header = res.headers; | ||
this.text = res.text; | ||
this.body = res.body; | ||
this.header = this.headers = res.headers; | ||
this.setStatusProperties(res.statusCode); | ||
this.setHeaderProperties(this.header); | ||
this.body = this.parseBody(this.text); | ||
} | ||
@@ -147,44 +172,14 @@ | ||
// TODO: moar! | ||
var params = (this.header['content-type'] || '').split(/ *; */); | ||
this.contentType = params.shift(); | ||
this.setParams(params); | ||
}; | ||
// TODO: make this a util | ||
/** | ||
* Create properties from `params`. | ||
* | ||
* For example "Content-Type: text/plain; charset=utf-8" | ||
* would provide `.charset` "utf-8". | ||
* | ||
* @param {Array} params | ||
* @api private | ||
*/ | ||
// content-type | ||
var ct = this.header['content-type'] || ''; | ||
this.type = utils.type(ct); | ||
Response.prototype.setParams = function(params){ | ||
var param; | ||
for (var i = 0, len = params.length; i < len; ++i) { | ||
param = params[i].split(/ *= */); | ||
this[param[0]] = param[1]; | ||
} | ||
// params | ||
var params = utils.params(ct); | ||
for (var key in params) this[key] = params[key]; | ||
}; | ||
/** | ||
* 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 = exports.parse[this.contentType]; | ||
return parse | ||
? parse(str) | ||
: null; | ||
}; | ||
/** | ||
* Set flags such as `.ok` based on `status`. | ||
@@ -214,3 +209,3 @@ * | ||
// status / class | ||
this.status = status; | ||
this.status = this.statusCode = status; | ||
this.statusType = type; | ||
@@ -498,8 +493,11 @@ | ||
if (this.req) return this.req; | ||
var self = this | ||
, options = this.options || {} | ||
, data = this._data || null | ||
, url = parse(this.url); | ||
, url = this.url; | ||
// default to http:// | ||
if (0 != url.indexOf('http')) url = 'http://' + url; | ||
url = parse(url); | ||
// options | ||
@@ -518,3 +516,3 @@ options.method = this.method; | ||
// initiate request | ||
var mod = exports.protocols[url.protocol || 'http:']; | ||
var mod = exports.protocols[url.protocol]; | ||
@@ -586,2 +584,7 @@ // request | ||
// zlib support | ||
if (/^(deflate|gzip)$/.test(res.headers['content-encoding'])) { | ||
utils.unzip(res); | ||
} | ||
// buffered response | ||
@@ -595,2 +598,11 @@ // TODO: optional | ||
// parser | ||
var parse = exports.parse[utils.type(res.headers['content-type'] || '')]; | ||
if (parse) { | ||
parse(res, function(err, obj){ | ||
// TODO: handle error | ||
res.body = obj; | ||
}); | ||
} | ||
// end event | ||
@@ -597,0 +609,0 @@ self.res = res; |
@@ -50,5 +50,4 @@ | ||
Part.prototype.assignBoundary = function(){ | ||
var boundary = utils.uid(32) | ||
, type = this.req.get('Content-Type') || 'multipart/mixed'; | ||
this.req.set('Content-Type', type + '; boundary="' + boundary + '"'); | ||
var boundary = utils.uid(32); | ||
this.req.set('Content-Type', 'multipart/form-data; boundary="' + boundary + '"'); | ||
this.req._boundary = boundary; | ||
@@ -55,0 +54,0 @@ }; |
/** | ||
* Module dependencies. | ||
*/ | ||
var Stream = require('stream').Stream | ||
, StringDecoder = require('string_decoder').StringDecoder | ||
, zlib; | ||
/** | ||
* Require zlib module for Node 0.6+ | ||
*/ | ||
try { | ||
zlib = require('zlib'); | ||
} catch (e) { } | ||
/** | ||
* Generate a UID with the given `len`. | ||
@@ -14,7 +30,78 @@ * | ||
, nchars = chars.length; | ||
while (len--) { | ||
buf += chars[Math.random() * nchars | 0]; | ||
} | ||
while (len--) buf += chars[Math.random() * nchars | 0]; | ||
return buf; | ||
}; | ||
/** | ||
* Return the mime type for the given `str`. | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
* @api private | ||
*/ | ||
exports.type = function(str){ | ||
return str.split(/ *; */).shift(); | ||
}; | ||
/** | ||
* Return header field parameters. | ||
* | ||
* @param {String} str | ||
* @return {Object} | ||
* @api private | ||
*/ | ||
exports.params = function(str){ | ||
return str.split(/ *; */).reduce(function(obj, str){ | ||
var parts = str.split(/ *= */) | ||
, key = parts.shift() | ||
, val = parts.shift(); | ||
if (key && val) obj[key] = val; | ||
return obj; | ||
}, {}); | ||
}; | ||
/** | ||
* Buffers response data events and re-emits when they're unzipped. | ||
* | ||
* @param {http.ServerResponse} response stream | ||
* @api private | ||
*/ | ||
exports.unzip = function(res){ | ||
if (!zlib) return; | ||
var unzip = zlib.createUnzip() | ||
, decodedStream = new Stream | ||
, decoder; | ||
// 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){ | ||
var str = decoder.write(buf); | ||
if (str.length) decodedStream.emit('data', str); | ||
}); | ||
unzip.on('end', function(){ | ||
decodedStream.emit('end'); | ||
}); | ||
// override `on` to capture data listeners | ||
var oldOn = res.on; | ||
res.on = function(type, fn){ | ||
if ('data' == type || 'end' == type) { | ||
decodedStream.on(type, fn); | ||
} else { | ||
oldOn.call(res, type, fn); | ||
} | ||
}; | ||
}; |
@@ -20,3 +20,3 @@ | ||
exports.version = '0.2.0'; | ||
exports.version = '0.3.0'; | ||
@@ -23,0 +23,0 @@ /** |
{ | ||
"name": "superagent" | ||
, "version": "0.2.0" | ||
, "version": "0.3.0" | ||
, "description": "elegant progressive ajax client" | ||
@@ -5,0 +5,0 @@ , "keywords": ["http", "ajax", "request", "agent"] |
@@ -195,3 +195,3 @@ | ||
exports.version = '0.2.0'; | ||
exports.version = '0.3.0'; | ||
@@ -198,0 +198,0 @@ /** |
@@ -5,2 +5,2 @@ /** | ||
* Check if `obj` is an array. | ||
*/function isArray(obj){return"[object Array]"=={}.toString.call(obj)}function EventEmitter(){}EventEmitter.prototype.on=function(name,fn){this.$events||(this.$events={}),this.$events[name]?isArray(this.$events[name])?this.$events[name].push(fn):this.$events[name]=[this.$events[name],fn]:this.$events[name]=fn;return this},EventEmitter.prototype.addListener=EventEmitter.prototype.on,EventEmitter.prototype.once=function(name,fn){var self=this;function on(){self.removeListener(name,on),fn.apply(this,arguments)}on.listener=fn,this.on(name,on);return this},EventEmitter.prototype.removeListener=function(name,fn){if(this.$events&&this.$events[name]){var list=this.$events[name];if(isArray(list)){var pos=-1;for(var i=0,l=list.length;i<l;i++)if(list[i]===fn||list[i].listener&&list[i].listener===fn){pos=i;break}if(pos<0)return this;list.splice(pos,1),list.length||delete this.$events[name]}else(list===fn||list.listener&&list.listener===fn)&&delete this.$events[name]}return this},EventEmitter.prototype.removeAllListeners=function(name){if(name===undefined){this.$events={};return this}this.$events&&this.$events[name]&&(this.$events[name]=null);return this},EventEmitter.prototype.listeners=function(name){this.$events||(this.$events={}),this.$events[name]||(this.$events[name]=[]),isArray(this.$events[name])||(this.$events[name]=[this.$events[name]]);return this.$events[name]},EventEmitter.prototype.emit=function(name){if(!this.$events)return!1;var handler=this.$events[name];if(!handler)return!1;var args=[].slice.call(arguments,1);if("function"==typeof handler)handler.apply(this,args);else{if(!isArray(handler))return!1;var listeners=handler.slice();for(var i=0,l=listeners.length;i<l;i++)listeners[i].apply(this,args)}return!0};var superagent=function(exports){exports=request,exports.version="0.2.0";var noop=function(){};function getXHR(){if(window.XMLHttpRequest&&("file:"!=window.location.protocol||!window.ActiveXObject))return new XMLHttpRequest;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){}return!1}var trim="".trim?function(s){return s.trim()}:function(s){return s.replace(/(^\s*|\s*$)/g,"")};function isFunction(obj){return"function"==typeof obj}function isObject(obj){return null!=obj&&"object"==typeof obj}function serialize(obj){if(!isObject(obj))return obj;var pairs=[];for(var key in obj)pairs.push(encodeURIComponent(key)+"="+encodeURIComponent(obj[key]));return pairs.join("&")}exports.serializeObject=serialize;function parseString(str){var obj={},pairs=str.split("&"),parts,pair;for(var i=0,len=pairs.length;i<len;++i)pair=pairs[i],parts=pair.split("="),obj[decodeURIComponent(parts[0])]=decodeURIComponent(parts[1]);return obj}exports.parseString=parseString,exports.types={html:"text/html",json:"application/json",urlencoded:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},exports.serialize={"application/x-www-form-urlencoded":serialize,"application/json":JSON.stringify},exports.parse={"application/x-www-form-urlencoded":parseString,"application/json":JSON.parse};function parseHeader(str){var lines=str.split(/\r?\n/),fields={},index,line,field,val;lines.pop();for(var i=0,len=lines.length;i<len;++i)line=lines[i],index=line.indexOf(":"),field=line.slice(0,index).toLowerCase(),val=trim(line.slice(index+1)),fields[field]=val;return fields}function Response(xhr,options){options=options||{},this.xhr=xhr,this.text=xhr.responseText,this.setStatusProperties(xhr.status),this.header=parseHeader(xhr.getAllResponseHeaders()),this.setHeaderProperties(this.header),this.body=this.parseBody(this.text)}Response.prototype.setHeaderProperties=function(header){var params=(this.header["content-type"]||"").split(/ *; */);this.contentType=params.shift(),this.setParams(params)},Response.prototype.setParams=function(params){var param;for(var i=0,len=params.length;i<len;++i)param=params[i].split(/ *= */),this[param[0]]=param[1]},Response.prototype.parseBody=function(str){var parse=exports.parse[this.contentType];return parse?parse(str):null},Response.prototype.setStatusProperties=function(status){var type=status/100|0;this.status=status,this.statusType=type,this.info=1==type,this.ok=2==type,this.clientError=4==type,this.serverError=5==type,this.error=4==type||5==type,this.accepted=202==status,this.noContent=204==status||1223==status,this.badRequest=400==status,this.unauthorized=401==status,this.notAcceptable=406==status,this.notFound=404==status},exports.Response=Response;function Request(method,url){var self=this;EventEmitter.call(this),this.method=method,this.url=url,this.header={},this.set("X-Requested-With","XMLHttpRequest"),this.on("end",function(){self.callback(new Response(self.xhr))})}Request.prototype=new EventEmitter,Request.prototype.constructor=Request,Request.prototype.set=function(field,val){if(isObject(field)){for(var key in field)this.set(key,field[key]);return this}this.header[field.toLowerCase()]=val;return this},Request.prototype.type=function(type){this.set("Content-Type",exports.types[type]||type);return this},Request.prototype.send=function(data){var obj=isObject(data);if(obj&&isObject(this._data))for(var key in data)this._data[key]=data[key];else this._data=data;if("GET"==this.method)return this;if(!obj)return this;if(this.header["content-type"])return this;this.type("json");return this},Request.prototype.end=function(fn){var self=this,xhr=this.xhr=getXHR(),data=this._data||null;this.callback=fn||noop,xhr.onreadystatechange=function(){4==xhr.readyState&&self.emit("end")},"GET"==this.method&&null!=data&&(this.url+="?"+exports.serializeObject(data),data=null),xhr.open(this.method,this.url,!0);if("GET"!=this.method&&"HEAD"!=this.method){var serialize=exports.serialize[this.header["content-type"]];serialize&&(data=serialize(data))}for(var field in this.header)xhr.setRequestHeader(field,this.header[field]);xhr.send(data);return this},exports.Request=Request;function request(method,url){if("function"==typeof url)return(new Request("GET",method)).end(url);if(1==arguments.length)return new Request("GET",method);return new Request(method,url)}request.get=function(url,data,fn){var req=request("GET",url);isFunction(data)&&(fn=data,data=null),data&&req.send(data),fn&&req.end(fn);return req},request.del=function(url,fn){var req=request("DELETE",url);fn&&req.end(fn);return req},request.post=function(url,data,fn){var req=request("POST",url);data&&req.send(data),fn&&req.end(fn);return req},request.put=function(url,data,fn){var req=request("PUT",url);data&&req.send(data),fn&&req.end(fn);return req};return exports}({}) | ||
*/function isArray(obj){return"[object Array]"=={}.toString.call(obj)}function EventEmitter(){}EventEmitter.prototype.on=function(name,fn){this.$events||(this.$events={}),this.$events[name]?isArray(this.$events[name])?this.$events[name].push(fn):this.$events[name]=[this.$events[name],fn]:this.$events[name]=fn;return this},EventEmitter.prototype.addListener=EventEmitter.prototype.on,EventEmitter.prototype.once=function(name,fn){var self=this;function on(){self.removeListener(name,on),fn.apply(this,arguments)}on.listener=fn,this.on(name,on);return this},EventEmitter.prototype.removeListener=function(name,fn){if(this.$events&&this.$events[name]){var list=this.$events[name];if(isArray(list)){var pos=-1;for(var i=0,l=list.length;i<l;i++)if(list[i]===fn||list[i].listener&&list[i].listener===fn){pos=i;break}if(pos<0)return this;list.splice(pos,1),list.length||delete this.$events[name]}else(list===fn||list.listener&&list.listener===fn)&&delete this.$events[name]}return this},EventEmitter.prototype.removeAllListeners=function(name){if(name===undefined){this.$events={};return this}this.$events&&this.$events[name]&&(this.$events[name]=null);return this},EventEmitter.prototype.listeners=function(name){this.$events||(this.$events={}),this.$events[name]||(this.$events[name]=[]),isArray(this.$events[name])||(this.$events[name]=[this.$events[name]]);return this.$events[name]},EventEmitter.prototype.emit=function(name){if(!this.$events)return!1;var handler=this.$events[name];if(!handler)return!1;var args=[].slice.call(arguments,1);if("function"==typeof handler)handler.apply(this,args);else{if(!isArray(handler))return!1;var listeners=handler.slice();for(var i=0,l=listeners.length;i<l;i++)listeners[i].apply(this,args)}return!0};var superagent=function(exports){exports=request,exports.version="0.3.0";var noop=function(){};function getXHR(){if(window.XMLHttpRequest&&("file:"!=window.location.protocol||!window.ActiveXObject))return new XMLHttpRequest;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){}return!1}var trim="".trim?function(s){return s.trim()}:function(s){return s.replace(/(^\s*|\s*$)/g,"")};function isFunction(obj){return"function"==typeof obj}function isObject(obj){return null!=obj&&"object"==typeof obj}function serialize(obj){if(!isObject(obj))return obj;var pairs=[];for(var key in obj)pairs.push(encodeURIComponent(key)+"="+encodeURIComponent(obj[key]));return pairs.join("&")}exports.serializeObject=serialize;function parseString(str){var obj={},pairs=str.split("&"),parts,pair;for(var i=0,len=pairs.length;i<len;++i)pair=pairs[i],parts=pair.split("="),obj[decodeURIComponent(parts[0])]=decodeURIComponent(parts[1]);return obj}exports.parseString=parseString,exports.types={html:"text/html",json:"application/json",urlencoded:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},exports.serialize={"application/x-www-form-urlencoded":serialize,"application/json":JSON.stringify},exports.parse={"application/x-www-form-urlencoded":parseString,"application/json":JSON.parse};function parseHeader(str){var lines=str.split(/\r?\n/),fields={},index,line,field,val;lines.pop();for(var i=0,len=lines.length;i<len;++i)line=lines[i],index=line.indexOf(":"),field=line.slice(0,index).toLowerCase(),val=trim(line.slice(index+1)),fields[field]=val;return fields}function Response(xhr,options){options=options||{},this.xhr=xhr,this.text=xhr.responseText,this.setStatusProperties(xhr.status),this.header=parseHeader(xhr.getAllResponseHeaders()),this.setHeaderProperties(this.header),this.body=this.parseBody(this.text)}Response.prototype.setHeaderProperties=function(header){var params=(this.header["content-type"]||"").split(/ *; */);this.contentType=params.shift(),this.setParams(params)},Response.prototype.setParams=function(params){var param;for(var i=0,len=params.length;i<len;++i)param=params[i].split(/ *= */),this[param[0]]=param[1]},Response.prototype.parseBody=function(str){var parse=exports.parse[this.contentType];return parse?parse(str):null},Response.prototype.setStatusProperties=function(status){var type=status/100|0;this.status=status,this.statusType=type,this.info=1==type,this.ok=2==type,this.clientError=4==type,this.serverError=5==type,this.error=4==type||5==type,this.accepted=202==status,this.noContent=204==status||1223==status,this.badRequest=400==status,this.unauthorized=401==status,this.notAcceptable=406==status,this.notFound=404==status},exports.Response=Response;function Request(method,url){var self=this;EventEmitter.call(this),this.method=method,this.url=url,this.header={},this.set("X-Requested-With","XMLHttpRequest"),this.on("end",function(){self.callback(new Response(self.xhr))})}Request.prototype=new EventEmitter,Request.prototype.constructor=Request,Request.prototype.set=function(field,val){if(isObject(field)){for(var key in field)this.set(key,field[key]);return this}this.header[field.toLowerCase()]=val;return this},Request.prototype.type=function(type){this.set("Content-Type",exports.types[type]||type);return this},Request.prototype.send=function(data){var obj=isObject(data);if(obj&&isObject(this._data))for(var key in data)this._data[key]=data[key];else this._data=data;if("GET"==this.method)return this;if(!obj)return this;if(this.header["content-type"])return this;this.type("json");return this},Request.prototype.end=function(fn){var self=this,xhr=this.xhr=getXHR(),data=this._data||null;this.callback=fn||noop,xhr.onreadystatechange=function(){4==xhr.readyState&&self.emit("end")},"GET"==this.method&&null!=data&&(this.url+="?"+exports.serializeObject(data),data=null),xhr.open(this.method,this.url,!0);if("GET"!=this.method&&"HEAD"!=this.method){var serialize=exports.serialize[this.header["content-type"]];serialize&&(data=serialize(data))}for(var field in this.header)xhr.setRequestHeader(field,this.header[field]);xhr.send(data);return this},exports.Request=Request;function request(method,url){if("function"==typeof url)return(new Request("GET",method)).end(url);if(1==arguments.length)return new Request("GET",method);return new Request(method,url)}request.get=function(url,data,fn){var req=request("GET",url);isFunction(data)&&(fn=data,data=null),data&&req.send(data),fn&&req.end(fn);return req},request.del=function(url,fn){var req=request("DELETE",url);fn&&req.end(fn);return req},request.post=function(url,data,fn){var req=request("POST",url);data&&req.send(data),fn&&req.end(fn);return req},request.put=function(url,data,fn){var req=request("PUT",url);data&&req.send(data),fn&&req.end(fn);return req};return exports}({}) |
@@ -54,2 +54,13 @@ | ||
describe('without a schema', function(){ | ||
it('should default to http', function(done){ | ||
request | ||
.get('localhost:3000/login') | ||
.end(function(res){ | ||
assert(res.status == 200); | ||
done(); | ||
}) | ||
}) | ||
}) | ||
describe('.end()', function(){ | ||
@@ -100,2 +111,14 @@ it('should issue a request', function(done){ | ||
describe('res.type', function(){ | ||
it('should provide the mime-type void of params', function(done){ | ||
request | ||
.get('http://localhost:3000/login') | ||
.end(function(res){ | ||
res.type.should.equal('text/html'); | ||
res.charset.should.equal('utf-8'); | ||
done(); | ||
}); | ||
}) | ||
}) | ||
describe('req.set(field, val)', function(){ | ||
@@ -102,0 +125,0 @@ it('should set the header field', function(done){ |
@@ -45,3 +45,3 @@ | ||
var ct = res.header['content-type']; | ||
ct.should.include.string('multipart/mixed; boundary="'); | ||
ct.should.include('multipart/form-data; boundary="'); | ||
@@ -79,3 +79,3 @@ var body = '\r\n'; | ||
var ct = res.header['content-type']; | ||
ct.should.include.string('multipart/mixed; boundary="'); | ||
ct.should.include('multipart/form-data; boundary="'); | ||
@@ -112,3 +112,3 @@ var body = ''; | ||
var ct = res.header['content-type']; | ||
ct.should.include.string('multipart/form-data; boundary="'); | ||
ct.should.include('multipart/form-data; boundary="'); | ||
@@ -115,0 +115,0 @@ var body = '\r\n'; |
Sorry, the diff of this file is not supported yet
352571
37
10758