| /*! | 
|  * body-parser | 
|  * Copyright(c) 2014 Jonathan Ong | 
|  * Copyright(c) 2014-2015 Douglas Christopher Wilson | 
|  * MIT Licensed | 
|  */ | 
|   | 
| 'use strict' | 
|   | 
| /** | 
|  * Module dependencies. | 
|  * @private | 
|  */ | 
|   | 
| var bytes = require('bytes') | 
| var contentType = require('content-type') | 
| var createError = require('http-errors') | 
| var debug = require('debug')('body-parser:urlencoded') | 
| var deprecate = require('depd')('body-parser') | 
| var read = require('../read') | 
| var typeis = require('type-is') | 
|   | 
| /** | 
|  * Module exports. | 
|  */ | 
|   | 
| module.exports = urlencoded | 
|   | 
| /** | 
|  * Cache of parser modules. | 
|  */ | 
|   | 
| var parsers = Object.create(null) | 
|   | 
| /** | 
|  * Create a middleware to parse urlencoded bodies. | 
|  * | 
|  * @param {object} [options] | 
|  * @return {function} | 
|  * @public | 
|  */ | 
|   | 
| function urlencoded (options) { | 
|   var opts = options || {} | 
|   | 
|   // notice because option default will flip in next major | 
|   if (opts.extended === undefined) { | 
|     deprecate('undefined extended: provide extended option') | 
|   } | 
|   | 
|   var extended = opts.extended !== false | 
|   var inflate = opts.inflate !== false | 
|   var limit = typeof opts.limit !== 'number' | 
|     ? bytes.parse(opts.limit || '100kb') | 
|     : opts.limit | 
|   var type = opts.type || 'application/x-www-form-urlencoded' | 
|   var verify = opts.verify || false | 
|   | 
|   if (verify !== false && typeof verify !== 'function') { | 
|     throw new TypeError('option verify must be function') | 
|   } | 
|   | 
|   // create the appropriate query parser | 
|   var queryparse = extended | 
|     ? extendedparser(opts) | 
|     : simpleparser(opts) | 
|   | 
|   // create the appropriate type checking function | 
|   var shouldParse = typeof type !== 'function' | 
|     ? typeChecker(type) | 
|     : type | 
|   | 
|   function parse (body) { | 
|     return body.length | 
|       ? queryparse(body) | 
|       : {} | 
|   } | 
|   | 
|   return function urlencodedParser (req, res, next) { | 
|     if (req._body) { | 
|       debug('body already parsed') | 
|       next() | 
|       return | 
|     } | 
|   | 
|     req.body = req.body || {} | 
|   | 
|     // skip requests without bodies | 
|     if (!typeis.hasBody(req)) { | 
|       debug('skip empty body') | 
|       next() | 
|       return | 
|     } | 
|   | 
|     debug('content-type %j', req.headers['content-type']) | 
|   | 
|     // determine if request should be parsed | 
|     if (!shouldParse(req)) { | 
|       debug('skip parsing') | 
|       next() | 
|       return | 
|     } | 
|   | 
|     // assert charset | 
|     var charset = getCharset(req) || 'utf-8' | 
|     if (charset !== 'utf-8') { | 
|       debug('invalid charset') | 
|       next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', { | 
|         charset: charset, | 
|         type: 'charset.unsupported' | 
|       })) | 
|       return | 
|     } | 
|   | 
|     // read | 
|     read(req, res, next, parse, debug, { | 
|       debug: debug, | 
|       encoding: charset, | 
|       inflate: inflate, | 
|       limit: limit, | 
|       verify: verify | 
|     }) | 
|   } | 
| } | 
|   | 
| /** | 
|  * Get the extended query parser. | 
|  * | 
|  * @param {object} options | 
|  */ | 
|   | 
| function extendedparser (options) { | 
|   var parameterLimit = options.parameterLimit !== undefined | 
|     ? options.parameterLimit | 
|     : 1000 | 
|   var parse = parser('qs') | 
|   | 
|   if (isNaN(parameterLimit) || parameterLimit < 1) { | 
|     throw new TypeError('option parameterLimit must be a positive number') | 
|   } | 
|   | 
|   if (isFinite(parameterLimit)) { | 
|     parameterLimit = parameterLimit | 0 | 
|   } | 
|   | 
|   return function queryparse (body) { | 
|     var paramCount = parameterCount(body, parameterLimit) | 
|   | 
|     if (paramCount === undefined) { | 
|       debug('too many parameters') | 
|       throw createError(413, 'too many parameters', { | 
|         type: 'parameters.too.many' | 
|       }) | 
|     } | 
|   | 
|     var arrayLimit = Math.max(100, paramCount) | 
|   | 
|     debug('parse extended urlencoding') | 
|     return parse(body, { | 
|       allowPrototypes: true, | 
|       arrayLimit: arrayLimit, | 
|       depth: Infinity, | 
|       parameterLimit: parameterLimit | 
|     }) | 
|   } | 
| } | 
|   | 
| /** | 
|  * Get the charset of a request. | 
|  * | 
|  * @param {object} req | 
|  * @api private | 
|  */ | 
|   | 
| function getCharset (req) { | 
|   try { | 
|     return (contentType.parse(req).parameters.charset || '').toLowerCase() | 
|   } catch (e) { | 
|     return undefined | 
|   } | 
| } | 
|   | 
| /** | 
|  * Count the number of parameters, stopping once limit reached | 
|  * | 
|  * @param {string} body | 
|  * @param {number} limit | 
|  * @api private | 
|  */ | 
|   | 
| function parameterCount (body, limit) { | 
|   var count = 0 | 
|   var index = 0 | 
|   | 
|   while ((index = body.indexOf('&', index)) !== -1) { | 
|     count++ | 
|     index++ | 
|   | 
|     if (count === limit) { | 
|       return undefined | 
|     } | 
|   } | 
|   | 
|   return count | 
| } | 
|   | 
| /** | 
|  * Get parser for module name dynamically. | 
|  * | 
|  * @param {string} name | 
|  * @return {function} | 
|  * @api private | 
|  */ | 
|   | 
| function parser (name) { | 
|   var mod = parsers[name] | 
|   | 
|   if (mod !== undefined) { | 
|     return mod.parse | 
|   } | 
|   | 
|   // this uses a switch for static require analysis | 
|   switch (name) { | 
|     case 'qs': | 
|       mod = require('qs') | 
|       break | 
|     case 'querystring': | 
|       mod = require('querystring') | 
|       break | 
|   } | 
|   | 
|   // store to prevent invoking require() | 
|   parsers[name] = mod | 
|   | 
|   return mod.parse | 
| } | 
|   | 
| /** | 
|  * Get the simple query parser. | 
|  * | 
|  * @param {object} options | 
|  */ | 
|   | 
| function simpleparser (options) { | 
|   var parameterLimit = options.parameterLimit !== undefined | 
|     ? options.parameterLimit | 
|     : 1000 | 
|   var parse = parser('querystring') | 
|   | 
|   if (isNaN(parameterLimit) || parameterLimit < 1) { | 
|     throw new TypeError('option parameterLimit must be a positive number') | 
|   } | 
|   | 
|   if (isFinite(parameterLimit)) { | 
|     parameterLimit = parameterLimit | 0 | 
|   } | 
|   | 
|   return function queryparse (body) { | 
|     var paramCount = parameterCount(body, parameterLimit) | 
|   | 
|     if (paramCount === undefined) { | 
|       debug('too many parameters') | 
|       throw createError(413, 'too many parameters', { | 
|         type: 'parameters.too.many' | 
|       }) | 
|     } | 
|   | 
|     debug('parse urlencoding') | 
|     return parse(body, undefined, undefined, { maxKeys: parameterLimit }) | 
|   } | 
| } | 
|   | 
| /** | 
|  * Get the simple type checker. | 
|  * | 
|  * @param {string} type | 
|  * @return {function} | 
|  */ | 
|   | 
| function typeChecker (type) { | 
|   return function checkType (req) { | 
|     return Boolean(typeis(req, type)) | 
|   } | 
| } |