Permalink
Browse files

text middleware, tests, and refactoring of json & urlencoded to make use

of it
  • Loading branch information...
1 parent 62ebde1 commit 8d2797a04b3d334f196822bfc2f1cb09a52d5023 @focusaurus committed Jan 6, 2013
Showing with 226 additions and 93 deletions.
  1. +1 −1 lib/middleware/bodyParser.js
  2. +27 −47 lib/middleware/json.js
  3. +81 −0 lib/middleware/text.js
  4. +24 −43 lib/middleware/urlencoded.js
  5. +1 −1 test/bodyParser.js
  6. +1 −1 test/shared/index.js
  7. +91 −0 test/text.js
@@ -58,4 +58,4 @@ exports = module.exports = function bodyParser(options){
});
});
}
-};
+};
View
@@ -11,15 +11,8 @@
*/
var utils = require('../utils')
- , _limit = require('./limit');
+ , text = require('./text');
-/**
- * noop middleware.
- */
-
-function noop(req, res, next) {
- next();
-}
/**
* JSON:
@@ -42,45 +35,32 @@ exports = module.exports = function(options){
var options = options || {}
, strict = options.strict !== false;
- var limit = options.limit
- ? _limit(options.limit)
- : noop;
-
return function json(req, res, next) {
- if (req._body) return next();
- req.body = req.body || {};
-
- if (!utils.hasBody(req)) return next();
-
- // check Content-Type
- if ('application/json' != utils.mime(req)) return next();
-
- // flag as parsed
- req._body = true;
-
- // parse
- limit(req, res, function(err){
- if (err) return next(err);
- var buf = '';
- req.setEncoding('utf8');
- req.on('data', function(chunk){ buf += chunk });
- req.on('end', function(){
- var first = buf.trim()[0];
-
- if (0 == buf.length) {
- return next(400, 'invalid json, empty body');
- }
-
- if (strict && '{' != first && '[' != first) return next(400, 'invalid json');
- try {
- req.body = JSON.parse(buf, options.reviver);
- next();
- } catch (err){
- err.body = buf;
- err.status = 400;
- next(err);
- }
- });
+ text(options)(req, res, function (error) {
+ if (error) return next(error);
+ if (typeof req.body == 'undefined') {
+ req.body = {};
+ return next();
+ }
+ if (typeof req.body != 'string') return next();
+ // check Content-Type
+ if ('application/json' != utils.mime(req)) return next();
+ //OK to establish our defaults here
+ var json = req.body;
+ req.body = {};
+ if (0 == json.length) {
+ return next(400, 'invalid json, empty body');
+ }
+ var first = json.trim()[0];
+ if (strict && '{' != first && '[' != first) return next(400, 'invalid json');
+ try {
+ req.body = JSON.parse(json, options.reviver);
+ next();
+ } catch (err){
+ err.body = json;
+ err.status = 400;
+ next(err);
+ }
});
- }
+ };
};
View
@@ -0,0 +1,81 @@
+
+/*!
+ * Connect - text
+ * Copyright(c) 2010 Sencha Inc.
+ * Copyright(c) 2011 TJ Holowaychuk
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var utils = require('../utils')
+ , _limit = require('./limit');
+
+var DEFAULT_MIME_TYPES = [
+ 'application/json',
+ 'application/x-www-form-urlencoded'
+];
+
+/**
+ * noop middleware.
+ */
+
+function noop(req, res, next) {
+ next();
+}
+
+function relevantMIMEType(req, mimeTypes) {
+ var mime = utils.mime(req);
+ return (mimeTypes.indexOf(mime) >= 0) ||
+ (0 == mime.indexOf('text/'));
+}
+/**
+ * text:
+ *
+ * Assemble text request bodies,
+ * providing the combined String object as `req.body`.
+ *
+ * By default requests with any `text/*` MIME type as well as
+ * `application/json` and `application/x-www-form-urlencoded`
+ * will be assembled into `req.body`.
+ *
+ * Options:
+ *
+ * - `limit` byte limit disabled by default
+ * - `mimeTypes` list of MIME strings to treat as text
+ *
+ * @param {Object} options
+ * @return {Function}
+ * @api public
+ */
+
+exports = module.exports = function(options){
+ options = options || {mimeTypes: DEFAULT_MIME_TYPES};
+
+ options.mimeTypes = options.mimeTypes || DEFAULT_MIME_TYPES;
+ var limit = options.limit
+ ? _limit(options.limit)
+ : noop;
+
+ return function text(req, res, next) {
+ if (req._body) return next();
+ if (!utils.hasBody(req)) return next();
+ if (!relevantMIMEType(req, options.mimeTypes)) return next();
+
+ limit(req, res, function(err){
+ if (err) return next(err);
+ req.body = req.body || '';
+ //mark as assembled/buffered
+ req._body = true;
+ var buf = '';
+ req.setEncoding('utf8');
+ req.on('data', function(chunk){ buf += chunk });
+ req.on('end', function(){
+ req.body = buf;
+ next();
+ });
+ });
+ }
+};
@@ -11,20 +11,12 @@
*/
var utils = require('../utils')
- , _limit = require('./limit')
+ , text = require('./text')
, qs = require('qs');
/**
- * noop middleware.
- */
-
-function noop(req, res, next) {
- next();
-}
-
-/**
* Urlencoded:
- *
+ *
* Parse x-ww-form-urlencoded request bodies,
* providing the parsed object as `req.body`.
*
@@ -40,39 +32,28 @@ function noop(req, res, next) {
exports = module.exports = function(options){
options = options || {};
- var limit = options.limit
- ? _limit(options.limit)
- : noop;
-
return function urlencoded(req, res, next) {
- if (req._body) return next();
- req.body = req.body || {};
-
- if (!utils.hasBody(req)) return next();
-
- // check Content-Type
- if ('application/x-www-form-urlencoded' != utils.mime(req)) return next();
-
- // flag as parsed
- req._body = true;
-
- // parse
- limit(req, res, function(err){
- if (err) return next(err);
- var buf = '';
- req.setEncoding('utf8');
- req.on('data', function(chunk){ buf += chunk });
- req.on('end', function(){
- try {
- req.body = buf.length
- ? qs.parse(buf, options)
- : {};
- next();
- } catch (err){
- err.body = buf;
- next(err);
- }
- });
+ text(options)(req, res, function (error) {
+ if (error) return next(error);
+ if (typeof req.body == 'undefined') {
+ req.body = {};
+ return next();
+ }
+ if (typeof req.body != 'string') return next();
+ // check Content-Type
+ if ('application/x-www-form-urlencoded' != utils.mime(req)) return next();
+ //OK to establish our defaults here
+ var encoded = req.body;
+ req.body = {};
+ if (0 == encoded.length) return next();
+ try {
+ req.body = qs.parse(encoded, options);
+ next();
+ } catch (err){
+ err.body = encoded;
+ err.status = 400;
+ next(err);
+ }
});
- }
+ };
};
View
@@ -261,4 +261,4 @@ describe('connect.bodyParser()', function(){
})
})
-})
+})
View
@@ -23,4 +23,4 @@ exports['limit body to'] = function(size, type, app){
done();
})
})
-}
+}
View
@@ -0,0 +1,91 @@
+
+var connect = require('../')
+ , should = require('./shared');
+
+var app = connect();
+
+app.use(connect.text({ limit: '1mb' }));
+
+app.use(function(req, res){
+ res.end(req.body);
+});
+
+describe('connect.text()', function(){
+ should['limit body to']('1mb', 'text/plain', app);
+ var body = 'this is the request body';
+
+ it('should default to empty string', function(done){
+ app.request()
+ .post('/')
+ .end(function(res){
+ res.body.should.equal('');
+ done();
+ })
+ })
+
+ it('should support all http methods', function(done){
+ app.request()
+ .get('/')
+ .set('Content-Type', 'text/plain')
+ .set('Content-Length', body.length)
+ .write(body)
+ .end(function(res){
+ res.body.should.equal(body);
+ done();
+ });
+ })
+
+ it('should assemble text/plain', function(done){
+ app.request()
+ .post('/')
+ .set('Content-Type', 'text/plain')
+ .write(body)
+ .end(function(res){
+ res.body.should.equal(body);
+ done();
+ });
+ })
+
+ it('should assemble application/json', function(done){
+ var body = '{"user":"tobi"}';
+ app.request()
+ .post('/')
+ .set('Content-Type', 'application/json')
+ .write(body)
+ .end(function(res){
+ res.body.should.equal(body);
+ done();
+ });
+ })
+
+ it('should assemble application/x-www-form-urlencoded', function(done){
+ var body = 'user=tobi';
+ app.request()
+ .post('/')
+ .set('Content-Type', 'application/x-www-form-urlencoded')
+ .write(body)
+ .end(function(res){
+ res.body.should.equal(body);
+ done();
+ });
+ })
+
+ it('should take other MIME types as an option', function(done){
+ var app = connect();
+
+ app.use(connect.text({mimeTypes: ['application/x-whatever']}));
+
+ app.use(function(req, res){
+ res.end(req.body);
+ });
+ var body = 'java.properties = baloney';
+ app.request()
+ .post('/')
+ .set('Content-Type', 'application/x-whatever')
+ .write(body)
+ .end(function(res){
+ res.body.should.equal(body);
+ done();
+ });
+ })
+})

0 comments on commit 8d2797a

Please sign in to comment.