avancement planning
This commit is contained in:
+60
-23
@@ -16,6 +16,8 @@ var getBody = require('raw-body')
|
||||
var iconv = require('iconv-lite')
|
||||
var onFinished = require('on-finished')
|
||||
var zlib = require('node:zlib')
|
||||
var hasBody = require('type-is').hasBody
|
||||
var { getCharset } = require('./utils')
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
@@ -26,24 +28,61 @@ module.exports = read
|
||||
/**
|
||||
* Read a request into a buffer and parse.
|
||||
*
|
||||
* @param {object} req
|
||||
* @param {object} res
|
||||
* @param {function} next
|
||||
* @param {function} parse
|
||||
* @param {function} debug
|
||||
* @param {object} options
|
||||
* @param {Object} req
|
||||
* @param {Object} res
|
||||
* @param {Function} next
|
||||
* @param {Function} parse
|
||||
* @param {Function} debug
|
||||
* @param {Object} options
|
||||
* @private
|
||||
*/
|
||||
|
||||
function read (req, res, next, parse, debug, options) {
|
||||
if (onFinished.isFinished(req)) {
|
||||
debug('body already parsed')
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
if (!('body' in req)) {
|
||||
req.body = undefined
|
||||
}
|
||||
|
||||
// skip requests without bodies
|
||||
if (!hasBody(req)) {
|
||||
debug('skip empty body')
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
debug('content-type %j', req.headers['content-type'])
|
||||
|
||||
// determine if request should be parsed
|
||||
if (!options.shouldParse(req)) {
|
||||
debug('skip parsing')
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
var encoding = null
|
||||
if (options?.skipCharset !== true) {
|
||||
encoding = getCharset(req) || options.defaultCharset
|
||||
|
||||
// validate charset
|
||||
if (!!options?.isValidCharset && !options.isValidCharset(encoding)) {
|
||||
debug('invalid charset')
|
||||
next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
|
||||
charset: encoding,
|
||||
type: 'charset.unsupported'
|
||||
}))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var length
|
||||
var opts = options
|
||||
var stream
|
||||
|
||||
// read options
|
||||
var encoding = opts.encoding !== null
|
||||
? opts.encoding
|
||||
: null
|
||||
var verify = opts.verify
|
||||
|
||||
try {
|
||||
@@ -136,13 +175,12 @@ function read (req, res, next, parse, debug, options) {
|
||||
/**
|
||||
* Get the content stream of the request.
|
||||
*
|
||||
* @param {object} req
|
||||
* @param {function} debug
|
||||
* @param {boolean} [inflate=true]
|
||||
* @return {object}
|
||||
* @api private
|
||||
* @param {Object} req
|
||||
* @param {Function} debug
|
||||
* @param {boolean} inflate
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function contentstream (req, debug, inflate) {
|
||||
var encoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
|
||||
var length = req.headers['content-length']
|
||||
@@ -169,9 +207,9 @@ function contentstream (req, debug, inflate) {
|
||||
/**
|
||||
* Create a decompression stream for the given encoding.
|
||||
* @param {string} encoding
|
||||
* @param {function} debug
|
||||
* @return {object}
|
||||
* @api private
|
||||
* @param {Function} debug
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
function createDecompressionStream (encoding, debug) {
|
||||
switch (encoding) {
|
||||
@@ -195,11 +233,10 @@ function createDecompressionStream (encoding, debug) {
|
||||
/**
|
||||
* Dump the contents of a request.
|
||||
*
|
||||
* @param {object} req
|
||||
* @param {function} callback
|
||||
* @api private
|
||||
* @param {Object} req
|
||||
* @param {Function} callback
|
||||
* @private
|
||||
*/
|
||||
|
||||
function dump (req, callback) {
|
||||
if (onFinished.isFinished(req)) {
|
||||
callback(null)
|
||||
|
||||
+16
-64
@@ -12,12 +12,9 @@
|
||||
* @private
|
||||
*/
|
||||
|
||||
var createError = require('http-errors')
|
||||
var debug = require('debug')('body-parser:json')
|
||||
var isFinished = require('on-finished').isFinished
|
||||
var read = require('../read')
|
||||
var typeis = require('type-is')
|
||||
var { getCharset, normalizeOptions } = require('../utils')
|
||||
var { normalizeOptions } = require('../utils')
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
@@ -36,7 +33,6 @@ module.exports = json
|
||||
* %x0A / ; Line feed or New line
|
||||
* %x0D ) ; Carriage return
|
||||
*/
|
||||
|
||||
var FIRST_CHAR_REGEXP = /^[\x20\x09\x0a\x0d]*([^\x20\x09\x0a\x0d])/ // eslint-disable-line no-control-regex
|
||||
|
||||
var JSON_SYNTAX_CHAR = '#'
|
||||
@@ -45,13 +41,12 @@ var JSON_SYNTAX_REGEXP = /#+/g
|
||||
/**
|
||||
* Create a middleware to parse JSON bodies.
|
||||
*
|
||||
* @param {object} [options]
|
||||
* @return {function}
|
||||
* @param {Object} [options]
|
||||
* @returns {Function}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function json (options) {
|
||||
var { inflate, limit, verify, shouldParse } = normalizeOptions(options, 'application/json')
|
||||
const normalizedOptions = normalizeOptions(options, 'application/json')
|
||||
|
||||
var reviver = options?.reviver
|
||||
var strict = options?.strict !== false
|
||||
@@ -83,51 +78,14 @@ function json (options) {
|
||||
}
|
||||
}
|
||||
|
||||
return function jsonParser (req, res, next) {
|
||||
if (isFinished(req)) {
|
||||
debug('body already parsed')
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
if (!('body' in req)) {
|
||||
req.body = undefined
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
const readOptions = {
|
||||
...normalizedOptions,
|
||||
// assert charset per RFC 7159 sec 8.1
|
||||
var charset = getCharset(req) || 'utf-8'
|
||||
if (charset.slice(0, 4) !== 'utf-') {
|
||||
debug('invalid charset')
|
||||
next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
|
||||
charset: charset,
|
||||
type: 'charset.unsupported'
|
||||
}))
|
||||
return
|
||||
}
|
||||
isValidCharset: (charset) => charset.slice(0, 4) === 'utf-'
|
||||
}
|
||||
|
||||
// read
|
||||
read(req, res, next, parse, debug, {
|
||||
encoding: charset,
|
||||
inflate,
|
||||
limit,
|
||||
verify
|
||||
})
|
||||
return function jsonParser (req, res, next) {
|
||||
read(req, res, next, parse, debug, readOptions)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,20 +94,15 @@ function json (options) {
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {string} char
|
||||
* @return {Error}
|
||||
* @returns {Error}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function createStrictSyntaxError (str, char) {
|
||||
var index = str.indexOf(char)
|
||||
var partial = ''
|
||||
|
||||
if (index !== -1) {
|
||||
partial = str.substring(0, index) + JSON_SYNTAX_CHAR
|
||||
|
||||
for (var i = index + 1; i < str.length; i++) {
|
||||
partial += JSON_SYNTAX_CHAR
|
||||
}
|
||||
partial = str.substring(0, index) + JSON_SYNTAX_CHAR.repeat(str.length - index)
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -168,10 +121,9 @@ function createStrictSyntaxError (str, char) {
|
||||
* Get the first non-whitespace character in a string.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {function}
|
||||
* @returns {string|undefined}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function firstchar (str) {
|
||||
var match = FIRST_CHAR_REGEXP.exec(str)
|
||||
|
||||
@@ -184,10 +136,10 @@ function firstchar (str) {
|
||||
* Normalize a SyntaxError for JSON.parse.
|
||||
*
|
||||
* @param {SyntaxError} error
|
||||
* @param {object} obj
|
||||
* @return {SyntaxError}
|
||||
* @param {Object} obj
|
||||
* @returns {SyntaxError}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function normalizeJsonSyntaxError (error, obj) {
|
||||
var keys = Object.getOwnPropertyNames(error)
|
||||
|
||||
|
||||
+10
-43
@@ -11,10 +11,8 @@
|
||||
*/
|
||||
|
||||
var debug = require('debug')('body-parser:raw')
|
||||
var isFinished = require('on-finished').isFinished
|
||||
var read = require('../read')
|
||||
var typeis = require('type-is')
|
||||
var { normalizeOptions } = require('../utils')
|
||||
var { normalizeOptions, passthrough } = require('../utils')
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
@@ -25,51 +23,20 @@ module.exports = raw
|
||||
/**
|
||||
* Create a middleware to parse raw bodies.
|
||||
*
|
||||
* @param {object} [options]
|
||||
* @return {function}
|
||||
* @api public
|
||||
* @param {Object} [options]
|
||||
* @returns {Function}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function raw (options) {
|
||||
var { inflate, limit, verify, shouldParse } = normalizeOptions(options, 'application/octet-stream')
|
||||
const normalizedOptions = normalizeOptions(options, 'application/octet-stream')
|
||||
|
||||
function parse (buf) {
|
||||
return buf
|
||||
const readOptions = {
|
||||
...normalizedOptions,
|
||||
// Skip charset validation and parse the body as is
|
||||
skipCharset: true
|
||||
}
|
||||
|
||||
return function rawParser (req, res, next) {
|
||||
if (isFinished(req)) {
|
||||
debug('body already parsed')
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
if (!('body' in req)) {
|
||||
req.body = undefined
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// read
|
||||
read(req, res, next, parse, debug, {
|
||||
encoding: null,
|
||||
inflate,
|
||||
limit,
|
||||
verify
|
||||
})
|
||||
read(req, res, next, passthrough, debug, readOptions)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-50
@@ -11,10 +11,8 @@
|
||||
*/
|
||||
|
||||
var debug = require('debug')('body-parser:text')
|
||||
var isFinished = require('on-finished').isFinished
|
||||
var read = require('../read')
|
||||
var typeis = require('type-is')
|
||||
var { getCharset, normalizeOptions } = require('../utils')
|
||||
var { normalizeOptions, passthrough } = require('../utils')
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
@@ -25,56 +23,14 @@ module.exports = text
|
||||
/**
|
||||
* Create a middleware to parse text bodies.
|
||||
*
|
||||
* @param {object} [options]
|
||||
* @return {function}
|
||||
* @api public
|
||||
* @param {Object} [options]
|
||||
* @returns {Function}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function text (options) {
|
||||
var { inflate, limit, verify, shouldParse } = normalizeOptions(options, 'text/plain')
|
||||
|
||||
var defaultCharset = options?.defaultCharset || 'utf-8'
|
||||
|
||||
function parse (buf) {
|
||||
return buf
|
||||
}
|
||||
const normalizedOptions = normalizeOptions(options, 'text/plain')
|
||||
|
||||
return function textParser (req, res, next) {
|
||||
if (isFinished(req)) {
|
||||
debug('body already parsed')
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
if (!('body' in req)) {
|
||||
req.body = undefined
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// get charset
|
||||
var charset = getCharset(req) || defaultCharset
|
||||
|
||||
// read
|
||||
read(req, res, next, parse, debug, {
|
||||
encoding: charset,
|
||||
inflate,
|
||||
limit,
|
||||
verify
|
||||
})
|
||||
read(req, res, next, passthrough, debug, normalizedOptions)
|
||||
}
|
||||
}
|
||||
|
||||
+25
-60
@@ -14,11 +14,9 @@
|
||||
|
||||
var createError = require('http-errors')
|
||||
var debug = require('debug')('body-parser:urlencoded')
|
||||
var isFinished = require('on-finished').isFinished
|
||||
var read = require('../read')
|
||||
var typeis = require('type-is')
|
||||
var qs = require('qs')
|
||||
var { getCharset, normalizeOptions } = require('../utils')
|
||||
var { normalizeOptions } = require('../utils')
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
@@ -29,16 +27,14 @@ module.exports = urlencoded
|
||||
/**
|
||||
* Create a middleware to parse urlencoded bodies.
|
||||
*
|
||||
* @param {object} [options]
|
||||
* @return {function}
|
||||
* @param {Object} [options]
|
||||
* @returns {Function}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function urlencoded (options) {
|
||||
var { inflate, limit, verify, shouldParse } = normalizeOptions(options, 'application/x-www-form-urlencoded')
|
||||
const normalizedOptions = normalizeOptions(options, 'application/x-www-form-urlencoded')
|
||||
|
||||
var defaultCharset = options?.defaultCharset || 'utf-8'
|
||||
if (defaultCharset !== 'utf-8' && defaultCharset !== 'iso-8859-1') {
|
||||
if (normalizedOptions.defaultCharset !== 'utf-8' && normalizedOptions.defaultCharset !== 'iso-8859-1') {
|
||||
throw new TypeError('option defaultCharset must be either utf-8 or iso-8859-1')
|
||||
}
|
||||
|
||||
@@ -51,60 +47,24 @@ function urlencoded (options) {
|
||||
: {}
|
||||
}
|
||||
|
||||
return function urlencodedParser (req, res, next) {
|
||||
if (isFinished(req)) {
|
||||
debug('body already parsed')
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
if (!('body' in req)) {
|
||||
req.body = undefined
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
const readOptions = {
|
||||
...normalizedOptions,
|
||||
// assert charset
|
||||
var charset = getCharset(req) || defaultCharset
|
||||
if (charset !== 'utf-8' && charset !== 'iso-8859-1') {
|
||||
debug('invalid charset')
|
||||
next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
|
||||
charset: charset,
|
||||
type: 'charset.unsupported'
|
||||
}))
|
||||
return
|
||||
}
|
||||
isValidCharset: (charset) => charset === 'utf-8' || charset === 'iso-8859-1'
|
||||
}
|
||||
|
||||
// read
|
||||
read(req, res, next, parse, debug, {
|
||||
encoding: charset,
|
||||
inflate,
|
||||
limit,
|
||||
verify
|
||||
})
|
||||
return function urlencodedParser (req, res, next) {
|
||||
read(req, res, next, parse, debug, readOptions)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extended query parser.
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {Object} options
|
||||
* @returns {Function}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function createQueryParser (options) {
|
||||
var extended = Boolean(options?.extended)
|
||||
var parameterLimit = options?.parameterLimit !== undefined
|
||||
@@ -136,7 +96,7 @@ function createQueryParser (options) {
|
||||
})
|
||||
}
|
||||
|
||||
var arrayLimit = extended ? Math.max(100, paramCount) : 0
|
||||
var arrayLimit = extended ? Math.max(100, paramCount) : paramCount
|
||||
|
||||
debug('parse ' + (extended ? 'extended ' : '') + 'urlencoding')
|
||||
try {
|
||||
@@ -167,11 +127,16 @@ function createQueryParser (options) {
|
||||
*
|
||||
* @param {string} body
|
||||
* @param {number} limit
|
||||
* @api private
|
||||
* @returns {number|undefined} Returns undefined if limit exceeded
|
||||
* @private
|
||||
*/
|
||||
|
||||
function parameterCount (body, limit) {
|
||||
var len = body.split('&').length
|
||||
|
||||
return len > limit ? undefined : len - 1
|
||||
let count = 0
|
||||
let index = -1
|
||||
do {
|
||||
count++
|
||||
if (count > limit) return undefined // Early exit if limit exceeded
|
||||
index = body.indexOf('&', index + 1)
|
||||
} while (index !== -1)
|
||||
return count
|
||||
}
|
||||
|
||||
+25
-10
@@ -11,19 +11,19 @@ var typeis = require('type-is')
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
getCharset,
|
||||
normalizeOptions
|
||||
normalizeOptions,
|
||||
passthrough
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the charset of a request.
|
||||
*
|
||||
* @param {object} req
|
||||
* @api private
|
||||
* @param {Object} req
|
||||
* @returns {string | undefined}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function getCharset (req) {
|
||||
try {
|
||||
return (contentType.parse(req).parameters.charset || '').toLowerCase()
|
||||
@@ -36,9 +36,9 @@ function getCharset (req) {
|
||||
* Get the simple type checker.
|
||||
*
|
||||
* @param {string | string[]} type
|
||||
* @return {function}
|
||||
* @returns {Function}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function typeChecker (type) {
|
||||
return function checkType (req) {
|
||||
return Boolean(typeis(req, type))
|
||||
@@ -48,9 +48,10 @@ function typeChecker (type) {
|
||||
/**
|
||||
* Normalizes the common options for all parsers.
|
||||
*
|
||||
* @param {object} options options to normalize
|
||||
* @param {string | string[] | function} defaultType default content type(s) or a function to determine it
|
||||
* @returns {object}
|
||||
* @param {Object} options options to normalize
|
||||
* @param {string | string[] | Function} defaultType default content type(s) or a function to determine it
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
function normalizeOptions (options, defaultType) {
|
||||
if (!defaultType) {
|
||||
@@ -64,6 +65,7 @@ function normalizeOptions (options, defaultType) {
|
||||
: options?.limit
|
||||
var type = options?.type || defaultType
|
||||
var verify = options?.verify || false
|
||||
var defaultCharset = options?.defaultCharset || 'utf-8'
|
||||
|
||||
if (verify !== false && typeof verify !== 'function') {
|
||||
throw new TypeError('option verify must be function')
|
||||
@@ -78,6 +80,19 @@ function normalizeOptions (options, defaultType) {
|
||||
inflate,
|
||||
limit,
|
||||
verify,
|
||||
defaultCharset,
|
||||
shouldParse
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passthrough function that returns input unchanged.
|
||||
* Used by parsers that don't need to transform the data.
|
||||
*
|
||||
* @param {*} value
|
||||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
function passthrough (value) {
|
||||
return value
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user