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.
196 lines
4.3 KiB
196 lines
4.3 KiB
|
|
/*! |
|
* 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); |
|
}; |