Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic Body Parser #561

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6e3cbbd
Added support for external parsers to bodyParser.json()
Nov 21, 2017
81bcdb8
removed test dependency on json-bigint
Nov 21, 2017
c1ed1bc
reworked doc to describe json parser() func better
Nov 21, 2017
36fdeee
added parser() option and doc for .text()
Nov 21, 2017
e0c6d1a
added parser() option and doc for .raw()
Nov 21, 2017
0007807
added parser() option and doc for .urlencoded()
Nov 21, 2017
38c1c3f
cleanup to satisfy linter
Nov 21, 2017
3057444
added generic parser
Nov 21, 2017
825a78b
converted json parser to use generic parser
Nov 21, 2017
bd0601b
converted raw parser to use generic parser
Nov 21, 2017
149966b
converted text parser to use generic parser
Nov 21, 2017
7d7ab1d
converted urlencoded parser to use generic parser
Nov 21, 2017
eb881ef
cleanup / fix linter warnings
Nov 21, 2017
07def41
removed items from README
Nov 21, 2017
b4c3c52
fixed tests after rebase
sdellysse Apr 17, 2020
1e59337
satisfying linter
sdellysse Apr 17, 2020
3526aff
Ref'd genParser via the bodyparser getter to signal how third party p…
sdellysse Apr 17, 2020
12dcaaf
removed dep on object-assign, which didnt support node < 0.10
sdellysse Apr 17, 2020
6f5ff23
minor text cleanup
sdellysse Apr 17, 2020
4978bab
🔧 add debug script
ctcpip May 24, 2024
e1e629b
🐛 fix object merging
ctcpip May 24, 2024
d574f61
🔥 clean up
ctcpip May 24, 2024
6f3dae1
Fix rebase
Phillip9587 Nov 19, 2024
c166e6d
Remove added npm script
Phillip9587 Nov 19, 2024
debe0a3
Fix rebase
Phillip9587 Nov 19, 2024
96fada8
Fix charset validation for urlencoded
Phillip9587 Nov 19, 2024
b83814b
Refactor
Phillip9587 Nov 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,27 @@ specifies the number of bytes; if it is a string, the value is passed to the
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
to `'100kb'`.

##### parser

The `parser` option is the function called against the request body to convert
it to a JavaScript object. If a `reviver` is supplied, it is supplied as the
second argument to this function.

```
parser(body, reviver) -> req.body
```

Defaults to `JSON.parse`.

##### reviver

The `reviver` option is passed directly to `JSON.parse` as the second
argument. You can find more information on this argument
You can find more information on this argument
[in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter).

##### strict

When set to `true`, will only accept arrays and objects; when `false` will
accept anything `JSON.parse` accepts. Defaults to `true`.
accept anything the `parser` accepts. Defaults to `true`.

##### type

Expand Down Expand Up @@ -295,6 +306,16 @@ form. Defaults to `false`.

The `depth` option is used to configure the maximum depth of the `qs` library when `extended` is `true`. This allows you to limit the amount of keys that are parsed and can be useful to prevent certain types of abuse. Defaults to `32`. It is recommended to keep this value as low as possible.

##### parser

The `parser` option, if supplied, is used to in place of the default parser to
convert the request body into a JavaScript object. If this option is supplied,
both the `extended` and `parameterLimit` options are ignored.

```
parser(body) -> req.body
```

## Errors

The middlewares provided by this module create errors using the
Expand Down
156 changes: 156 additions & 0 deletions lib/factory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*!
* 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:generic')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest passing the debug function as a parameter to createBodyParser(). This will allows the created middlewares to use their namespaces, such as body-parser:json, for debug messages.

var isFinished = require('on-finished').isFinished
var read = require('./read')
var typeis = require('type-is')

/**
* Module exports.
*/

module.exports = createBodyParser

/**
* Use this to create a middleware that parses request bodies
*
* @param {function} parse
* @param {object} options
* @param {object} defaultOptions
* @return {function}
* @public
*/

function createBodyParser (parse, options, defaultOptions) {
// Squash the options and the overrides down into one object
var opts = { ...defaultOptions || {}, ...options }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var opts = { ...defaultOptions || {}, ...options }
var opts = { ...defaultOptions, ...options }


var limit = typeof opts.limit !== 'number'
? bytes.parse(opts.limit || '100kb')
: opts.limit
var charset = opts.charset
var inflate = opts.inflate !== false
var verify = opts.verify || false
var defaultReqCharset = opts.defaultCharset || 'utf-8'
var type = opts.type

if (verify !== false && typeof verify !== 'function') {
throw new TypeError('option verify must be function')
}

// create the appropriate type checking function
var shouldParse = typeof type !== 'function'
? typeChecker(type)
: type

// create the appropriate charset validating function
var validCharset = typeof charset !== 'function'
? charsetValidator(charset)
: charset

return function (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
}

// assert charset per RFC 7159 sec 8.1
var reqCharset = null
if (charset !== undefined) {
reqCharset = getCharset(req) || defaultReqCharset
if (!validCharset(reqCharset)) {
debug('invalid charset')
next(createError(415, 'unsupported charset "' + reqCharset.toUpperCase() + '"', {
charset: reqCharset,
type: 'charset.unsupported'
}))
return
}
}

// read
read(req, res, next, parse, debug, {
encoding: reqCharset,
inflate: inflate,
limit: limit,
verify: verify
})
}
}

/**
* 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
}
}

/**
* Get the simple type checker.
*
* @param {string} type
* @return {function}
*/

function typeChecker (type) {
return function checkType (req) {
return Boolean(typeis(req, type))
}
}

/**
* Get the simple charset validator.
*
* @param {string} type
* @return {function}
*/

function charsetValidator (charset) {
return function validateCharset (reqCharset) {
return charset === reqCharset
}
}
Loading
Loading