/*! * Connect - bodyParser * Copyright(c) 2010 Sencha Inc. * Copyright(c) 2011 TJ Holowaychuk * MIT Licensed */ /** * Module dependencies. */ var qs = require('qs') , formidable = require('formidable'); /** * Extract the mime type from the given request's * _Content-Type_ header. * * @param {IncomingMessage} req * @return {String} * @api private */ function mime(req) { var str = req.headers['content-type'] || ''; return str.split(';')[0]; } /** * Parse request bodies. * * By default _application/json_, _application/x-www-form-urlencoded_, * and _multipart/form-data_ are supported, however you may map `connect.bodyParser.parse[contentType]` * to a function receiving `(req, options, callback)`. * * Examples: * * connect.createServer( * connect.bodyParser() * , function(req, res) { * res.end('viewing user ' + req.body.user.name); * } * ); * * $ curl -d 'user[name]=tj' http://localhost/ * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://localhost/ * * Multipart req.files: * * As a security measure files are stored in a separate object, stored * as `req.files`. This prevents attacks that may potentially alter * filenames, and depending on the application gain access to restricted files. * * Multipart configuration: * * The `options` passed are provided to each parser function. * The _multipart/form-data_ parser merges these with formidable's * IncomingForm object, allowing you to tweak the upload directory, * size limits, etc. For example you may wish to retain the file extension * and change the upload directory: * * server.use(bodyParser({ uploadDir: '/www/mysite.com/uploads' })); * * View [node-formidable](https://github.com/felixge/node-formidable) for more information. * * If you wish to use formidable directly within your app, and do not * desire this behaviour for multipart requests simply remove the * parser: * * delete connect.bodyParser.parse['multipart/form-data']; * * Or * * delete express.bodyParser.parse['multipart/form-data']; * * @param {Object} options * @return {Function} * @api public */ exports = module.exports = function bodyParser(options){ options = options || {}; return function bodyParser(req, res, next) { if (req.body) return next(); req.body = {}; if ('GET' == req.method || 'HEAD' == req.method) return next(); var parser = exports.parse[mime(req)]; if (parser) { parser(req, options, next); } else { next(); } } }; /** * Parsers. */ exports.parse = {}; /** * Parse application/x-www-form-urlencoded. */ exports.parse['application/x-www-form-urlencoded'] = function(req, options, fn){ var buf = ''; req.setEncoding('utf8'); req.on('data', function(chunk){ buf += chunk }); req.on('end', function(){ try { req.body = buf.length ? qs.parse(buf) : {}; fn(); } catch (err){ fn(err); } }); }; /** * Parse application/json. */ exports.parse['application/json'] = function(req, options, fn){ var buf = ''; req.setEncoding('utf8'); req.on('data', function(chunk){ buf += chunk }); req.on('end', function(){ try { req.body = buf.length ? JSON.parse(buf) : {}; fn(); } catch (err){ fn(err); } }); }; /** * Parse multipart/form-data. * * TODO: make multiple support optional * TODO: revisit "error" flag if it's a formidable bug */ exports.parse['multipart/form-data'] = function(req, options, fn){ var form = new formidable.IncomingForm , data = {} , files = {} , done; Object.keys(options).forEach(function(key){ form[key] = options[key]; }); function ondata(name, val, data){ if (Array.isArray(data[name])) { data[name].push(val); } else if (data[name]) { data[name] = [data[name], val]; } else { data[name] = val; } } form.on('field', function(name, val){ ondata(name, val, data); }); form.on('file', function(name, val){ ondata(name, val, files); }); form.on('error', function(err){ fn(err); done = true; }); form.on('end', function(){ if (done) return; try { req.body = qs.parse(data); req.files = qs.parse(files); fn(); } catch (err) { fn(err); } }); form.parse(req); };