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