3 * Copyright(c) 2014 Jonathan Ong
4 * Copyright(c) 2014-2015 Douglas Christopher Wilson
11 * Module dependencies.
15 var bytes = require('bytes')
16 var contentType = require('content-type')
17 var createError = require('http-errors')
18 var debug = require('debug')('body-parser:urlencoded')
19 var deprecate = require('depd')('body-parser')
20 var read = require('../read')
21 var typeis = require('type-is')
27 module.exports = urlencoded
30 * Cache of parser modules.
33 var parsers = Object.create(null)
36 * Create a middleware to parse urlencoded bodies.
38 * @param {object} [options]
43 function urlencoded (options) {
44 var opts = options || {}
46 // notice because option default will flip in next major
47 if (opts.extended === undefined) {
48 deprecate('undefined extended: provide extended option')
51 var extended = opts.extended !== false
52 var inflate = opts.inflate !== false
53 var limit = typeof opts.limit !== 'number'
54 ? bytes.parse(opts.limit || '100kb')
56 var type = opts.type || 'application/x-www-form-urlencoded'
57 var verify = opts.verify || false
59 if (verify !== false && typeof verify !== 'function') {
60 throw new TypeError('option verify must be function')
63 // create the appropriate query parser
64 var queryparse = extended
65 ? extendedparser(opts)
68 // create the appropriate type checking function
69 var shouldParse = typeof type !== 'function'
73 function parse (body) {
79 return function urlencodedParser (req, res, next) {
81 debug('body already parsed')
86 req.body = req.body || {}
88 // skip requests without bodies
89 if (!typeis.hasBody(req)) {
90 debug('skip empty body')
95 debug('content-type %j', req.headers['content-type'])
97 // determine if request should be parsed
98 if (!shouldParse(req)) {
105 var charset = getCharset(req) || 'utf-8'
106 if (charset !== 'utf-8') {
107 debug('invalid charset')
108 next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
110 type: 'charset.unsupported'
116 read(req, res, next, parse, debug, {
127 * Get the extended query parser.
129 * @param {object} options
132 function extendedparser (options) {
133 var parameterLimit = options.parameterLimit !== undefined
134 ? options.parameterLimit
136 var parse = parser('qs')
138 if (isNaN(parameterLimit) || parameterLimit < 1) {
139 throw new TypeError('option parameterLimit must be a positive number')
142 if (isFinite(parameterLimit)) {
143 parameterLimit = parameterLimit | 0
146 return function queryparse (body) {
147 var paramCount = parameterCount(body, parameterLimit)
149 if (paramCount === undefined) {
150 debug('too many parameters')
151 throw createError(413, 'too many parameters', {
152 type: 'parameters.too.many'
156 var arrayLimit = Math.max(100, paramCount)
158 debug('parse extended urlencoding')
160 allowPrototypes: true,
161 arrayLimit: arrayLimit,
163 parameterLimit: parameterLimit
169 * Get the charset of a request.
171 * @param {object} req
175 function getCharset (req) {
177 return (contentType.parse(req).parameters.charset || '').toLowerCase()
184 * Count the number of parameters, stopping once limit reached
186 * @param {string} body
187 * @param {number} limit
191 function parameterCount (body, limit) {
195 while ((index = body.indexOf('&', index)) !== -1) {
199 if (count === limit) {
208 * Get parser for module name dynamically.
210 * @param {string} name
215 function parser (name) {
216 var mod = parsers[name]
218 if (mod !== undefined) {
222 // this uses a switch for static require analysis
228 mod = require('querystring')
232 // store to prevent invoking require()
239 * Get the simple query parser.
241 * @param {object} options
244 function simpleparser (options) {
245 var parameterLimit = options.parameterLimit !== undefined
246 ? options.parameterLimit
248 var parse = parser('querystring')
250 if (isNaN(parameterLimit) || parameterLimit < 1) {
251 throw new TypeError('option parameterLimit must be a positive number')
254 if (isFinite(parameterLimit)) {
255 parameterLimit = parameterLimit | 0
258 return function queryparse (body) {
259 var paramCount = parameterCount(body, parameterLimit)
261 if (paramCount === undefined) {
262 debug('too many parameters')
263 throw createError(413, 'too many parameters', {
264 type: 'parameters.too.many'
268 debug('parse urlencoding')
269 return parse(body, undefined, undefined, { maxKeys: parameterLimit })
274 * Get the simple type checker.
276 * @param {string} type
280 function typeChecker (type) {
281 return function checkType (req) {
282 return Boolean(typeis(req, type))