3 * Copyright(c) 2014 Jonathan Ong
4 * Copyright(c) 2014 Douglas Christopher Wilson
12 var bytes = require('bytes')
13 var deprecate = require('depd')('body-parser')
14 var read = require('../read')
15 var typer = require('media-typer')
16 var typeis = require('type-is')
22 module.exports = urlencoded
25 * Cache of parser modules.
28 var parsers = Object.create(null)
31 * Create a middleware to parse urlencoded bodies.
33 * @param {object} [options]
38 function urlencoded(options){
39 options = options || {};
41 // notice because option default will flip in next major
42 if (options.extended === undefined) {
43 deprecate('undefined extended: provide extended option')
46 var extended = options.extended !== false
47 var inflate = options.inflate !== false
48 var limit = typeof options.limit !== 'number'
49 ? bytes(options.limit || '100kb')
51 var type = options.type || 'urlencoded'
52 var verify = options.verify || false
54 if (verify !== false && typeof verify !== 'function') {
55 throw new TypeError('option verify must be function')
58 var queryparse = extended
59 ? extendedparser(options)
60 : simpleparser(options)
62 function parse(body) {
68 return function urlencodedParser(req, res, next) {
69 if (req._body) return next();
70 req.body = req.body || {}
72 if (!typeis(req, type)) return next();
74 var charset = (typer.parse(req).parameters.charset || 'utf-8').toLowerCase()
75 if (charset !== 'utf-8') {
76 var err = new Error('unsupported charset "' + charset.toUpperCase() + '"')
84 read(req, res, next, parse, {
94 * Get the extended query parser.
96 * @param {object} options
99 function extendedparser(options) {
100 var parameterLimit = options.parameterLimit !== undefined
101 ? options.parameterLimit
103 var parse = parser('qs')
105 if (isNaN(parameterLimit) || parameterLimit < 1) {
106 throw new TypeError('option parameterLimit must be a positive number')
109 if (isFinite(parameterLimit)) {
110 parameterLimit = parameterLimit | 0
113 return function queryparse(body) {
114 var paramCount = parameterCount(body, parameterLimit)
116 if (paramCount === undefined) {
117 var err = new Error('too many parameters')
122 var arrayLimit = Math.max(100, paramCount)
125 arrayLimit: arrayLimit,
126 parameterLimit: parameterLimit
132 * Count the number of parameters, stopping once limit reached
134 * @param {string} body
135 * @param {number} limit
139 function parameterCount(body, limit) {
143 while ((index = body.indexOf('&', index)) !== -1) {
147 if (count === limit) {
156 * Get parser for module name dynamically.
158 * @param {string} name
163 function parser(name) {
164 var mod = parsers[name]
171 mod = parsers[name] = require(name)
177 * Get the simple query parser.
179 * @param {object} options
182 function simpleparser(options) {
183 var parameterLimit = options.parameterLimit !== undefined
184 ? options.parameterLimit
186 var parse = parser('querystring')
188 if (isNaN(parameterLimit) || parameterLimit < 1) {
189 throw new TypeError('option parameterLimit must be a positive number')
192 if (isFinite(parameterLimit)) {
193 parameterLimit = parameterLimit | 0
196 return function queryparse(body) {
197 var paramCount = parameterCount(body, parameterLimit)
199 if (paramCount === undefined) {
200 var err = new Error('too many parameters')
205 return parse(body, undefined, undefined, {maxKeys: parameterLimit})