pax_global_header00006660000000000000000000000064134604743750014527gustar00rootroot0000000000000052 comment=998b265db57a80ae75ea51c55f6a191e2d168a60 body-parser-1.19.0/000077500000000000000000000000001346047437500140465ustar00rootroot00000000000000body-parser-1.19.0/.eslintignore000066400000000000000000000000261346047437500165470ustar00rootroot00000000000000coverage node_modules body-parser-1.19.0/.eslintrc.yml000066400000000000000000000000771346047437500164760ustar00rootroot00000000000000root: true extends: standard rules: no-param-reassign: error body-parser-1.19.0/.gitignore000066400000000000000000000000701346047437500160330ustar00rootroot00000000000000coverage/ node_modules/ npm-debug.log package-lock.json body-parser-1.19.0/.travis.yml000066400000000000000000000057761346047437500161760ustar00rootroot00000000000000language: node_js node_js: - "0.8" - "0.10" - "0.12" - "1.8" - "2.5" - "3.3" - "4.9" - "5.12" - "6.17" - "7.10" - "8.16" - "9.11" - "10.15" - "11.14" - "12.0" sudo: false cache: directories: - node_modules before_install: - | # Setup utility functions function node_version_lt () { [[ "$(v "$TRAVIS_NODE_VERSION")" -lt "$(v "${1}")" ]] } function npm_module_installed () { npm -lsp ls | grep -Fq "$(pwd)/node_modules/${1}:${1}@" } function npm_remove_module_re () { node -e ' fs = require("fs"); p = JSON.parse(fs.readFileSync("package.json", "utf8")); r = RegExp(process.argv[1]); for (k in p.devDependencies) { if (r.test(k)) delete p.devDependencies[k]; } fs.writeFileSync("package.json", JSON.stringify(p, null, 2) + "\n"); ' "$@" } function npm_use_module () { node -e ' fs = require("fs"); p = JSON.parse(fs.readFileSync("package.json", "utf8")); p.devDependencies[process.argv[1]] = process.argv[2]; fs.writeFileSync("package.json", JSON.stringify(p, null, 2) + "\n"); ' "$@" } function v () { tr '.' '\n' <<< "${1}" \ | awk '{ printf "%03d", $0 }' \ | sed 's/^0*//' } # Configure npm - | # Skip updating shrinkwrap / lock npm config set shrinkwrap false # Remove all non-test dependencies - | # Remove benchmark dependencies npm_remove_module_re '(^|-)benchmark$' npm_remove_module_re '^fast-url-parser$' # Setup Node.js version-specific dependencies - | # Configure eslint for linting if node_version_lt '6.0'; then npm_remove_module_re '^eslint(-|$)' fi - | # Configure istanbul for coverage if node_version_lt '0.10'; then npm_remove_module_re '^istanbul$' fi - | # Configure mocha for testing if node_version_lt '0.10'; then npm_use_module 'mocha' '2.5.3' elif node_version_lt '4.0' ; then npm_use_module 'mocha' '3.5.3' elif node_version_lt '6.0' ; then npm_use_module 'mocha' '5.2.0' fi - | # Configure supertest for http calls if node_version_lt '0.10'; then npm_use_module 'supertest' '1.1.0' elif node_version_lt '4.0' ; then npm_use_module 'supertest' '2.0.0' elif node_version_lt '6.0' ; then npm_use_module 'supertest' '3.4.2' fi # Update Node.js modules - | # Prune & rebuild node_modules if [[ -d node_modules ]]; then npm prune npm rebuild fi before_scrpt: - | # Contents of node_modules npm -s ls ||: script: - | # Run test script, depending on istanbul install if npm_module_installed 'istanbul'; then npm run-script test-travis else npm test fi - | # Run linting, if eslint exists if npm_module_installed 'eslint'; then npm run-script lint fi after_script: - | # Upload coverage to coveralls if exists if [[ -e ./coverage/lcov.info ]]; then npm install --save-dev coveralls@2 coveralls < ./coverage/lcov.info fi body-parser-1.19.0/HISTORY.md000066400000000000000000000354111346047437500155350ustar00rootroot000000000000001.19.0 / 2019-04-25 =================== * deps: bytes@3.1.0 - Add petabyte (`pb`) support * deps: http-errors@1.7.2 - Set constructor name when possible - deps: setprototypeof@1.1.1 - deps: statuses@'>= 1.5.0 < 2' * deps: iconv-lite@0.4.24 - Added encoding MIK * deps: qs@6.7.0 - Fix parsing array brackets after index * deps: raw-body@2.4.0 - deps: bytes@3.1.0 - deps: http-errors@1.7.2 - deps: iconv-lite@0.4.24 * deps: type-is@~1.6.17 - deps: mime-types@~2.1.24 - perf: prevent internal `throw` on invalid type 1.18.3 / 2018-05-14 =================== * Fix stack trace for strict json parse error * deps: depd@~1.1.2 - perf: remove argument reassignment * deps: http-errors@~1.6.3 - deps: depd@~1.1.2 - deps: setprototypeof@1.1.0 - deps: statuses@'>= 1.3.1 < 2' * deps: iconv-lite@0.4.23 - Fix loading encoding with year appended - Fix deprecation warnings on Node.js 10+ * deps: qs@6.5.2 * deps: raw-body@2.3.3 - deps: http-errors@1.6.3 - deps: iconv-lite@0.4.23 * deps: type-is@~1.6.16 - deps: mime-types@~2.1.18 1.18.2 / 2017-09-22 =================== * deps: debug@2.6.9 * perf: remove argument reassignment 1.18.1 / 2017-09-12 =================== * deps: content-type@~1.0.4 - perf: remove argument reassignment - perf: skip parameter parsing when no parameters * deps: iconv-lite@0.4.19 - Fix ISO-8859-1 regression - Update Windows-1255 * deps: qs@6.5.1 - Fix parsing & compacting very deep objects * deps: raw-body@2.3.2 - deps: iconv-lite@0.4.19 1.18.0 / 2017-09-08 =================== * Fix JSON strict violation error to match native parse error * Include the `body` property on verify errors * Include the `type` property on all generated errors * Use `http-errors` to set status code on errors * deps: bytes@3.0.0 * deps: debug@2.6.8 * deps: depd@~1.1.1 - Remove unnecessary `Buffer` loading * deps: http-errors@~1.6.2 - deps: depd@1.1.1 * deps: iconv-lite@0.4.18 - Add support for React Native - Add a warning if not loaded as utf-8 - Fix CESU-8 decoding in Node.js 8 - Improve speed of ISO-8859-1 encoding * deps: qs@6.5.0 * deps: raw-body@2.3.1 - Use `http-errors` for standard emitted errors - deps: bytes@3.0.0 - deps: iconv-lite@0.4.18 - perf: skip buffer decoding on overage chunk * perf: prevent internal `throw` when missing charset 1.17.2 / 2017-05-17 =================== * deps: debug@2.6.7 - Fix `DEBUG_MAX_ARRAY_LENGTH` - deps: ms@2.0.0 * deps: type-is@~1.6.15 - deps: mime-types@~2.1.15 1.17.1 / 2017-03-06 =================== * deps: qs@6.4.0 - Fix regression parsing keys starting with `[` 1.17.0 / 2017-03-01 =================== * deps: http-errors@~1.6.1 - Make `message` property enumerable for `HttpError`s - deps: setprototypeof@1.0.3 * deps: qs@6.3.1 - Fix compacting nested arrays 1.16.1 / 2017-02-10 =================== * deps: debug@2.6.1 - Fix deprecation messages in WebStorm and other editors - Undeprecate `DEBUG_FD` set to `1` or `2` 1.16.0 / 2017-01-17 =================== * deps: debug@2.6.0 - Allow colors in workers - Deprecated `DEBUG_FD` environment variable - Fix error when running under React Native - Use same color for same namespace - deps: ms@0.7.2 * deps: http-errors@~1.5.1 - deps: inherits@2.0.3 - deps: setprototypeof@1.0.2 - deps: statuses@'>= 1.3.1 < 2' * deps: iconv-lite@0.4.15 - Added encoding MS-31J - Added encoding MS-932 - Added encoding MS-936 - Added encoding MS-949 - Added encoding MS-950 - Fix GBK/GB18030 handling of Euro character * deps: qs@6.2.1 - Fix array parsing from skipping empty values * deps: raw-body@~2.2.0 - deps: iconv-lite@0.4.15 * deps: type-is@~1.6.14 - deps: mime-types@~2.1.13 1.15.2 / 2016-06-19 =================== * deps: bytes@2.4.0 * deps: content-type@~1.0.2 - perf: enable strict mode * deps: http-errors@~1.5.0 - Use `setprototypeof` module to replace `__proto__` setting - deps: statuses@'>= 1.3.0 < 2' - perf: enable strict mode * deps: qs@6.2.0 * deps: raw-body@~2.1.7 - deps: bytes@2.4.0 - perf: remove double-cleanup on happy path * deps: type-is@~1.6.13 - deps: mime-types@~2.1.11 1.15.1 / 2016-05-05 =================== * deps: bytes@2.3.0 - Drop partial bytes on all parsed units - Fix parsing byte string that looks like hex * deps: raw-body@~2.1.6 - deps: bytes@2.3.0 * deps: type-is@~1.6.12 - deps: mime-types@~2.1.10 1.15.0 / 2016-02-10 =================== * deps: http-errors@~1.4.0 - Add `HttpError` export, for `err instanceof createError.HttpError` - deps: inherits@2.0.1 - deps: statuses@'>= 1.2.1 < 2' * deps: qs@6.1.0 * deps: type-is@~1.6.11 - deps: mime-types@~2.1.9 1.14.2 / 2015-12-16 =================== * deps: bytes@2.2.0 * deps: iconv-lite@0.4.13 * deps: qs@5.2.0 * deps: raw-body@~2.1.5 - deps: bytes@2.2.0 - deps: iconv-lite@0.4.13 * deps: type-is@~1.6.10 - deps: mime-types@~2.1.8 1.14.1 / 2015-09-27 =================== * Fix issue where invalid charset results in 400 when `verify` used * deps: iconv-lite@0.4.12 - Fix CESU-8 decoding in Node.js 4.x * deps: raw-body@~2.1.4 - Fix masking critical errors from `iconv-lite` - deps: iconv-lite@0.4.12 * deps: type-is@~1.6.9 - deps: mime-types@~2.1.7 1.14.0 / 2015-09-16 =================== * Fix JSON strict parse error to match syntax errors * Provide static `require` analysis in `urlencoded` parser * deps: depd@~1.1.0 - Support web browser loading * deps: qs@5.1.0 * deps: raw-body@~2.1.3 - Fix sync callback when attaching data listener causes sync read * deps: type-is@~1.6.8 - Fix type error when given invalid type to match against - deps: mime-types@~2.1.6 1.13.3 / 2015-07-31 =================== * deps: type-is@~1.6.6 - deps: mime-types@~2.1.4 1.13.2 / 2015-07-05 =================== * deps: iconv-lite@0.4.11 * deps: qs@4.0.0 - Fix dropping parameters like `hasOwnProperty` - Fix user-visible incompatibilities from 3.1.0 - Fix various parsing edge cases * deps: raw-body@~2.1.2 - Fix error stack traces to skip `makeError` - deps: iconv-lite@0.4.11 * deps: type-is@~1.6.4 - deps: mime-types@~2.1.2 - perf: enable strict mode - perf: remove argument reassignment 1.13.1 / 2015-06-16 =================== * deps: qs@2.4.2 - Downgraded from 3.1.0 because of user-visible incompatibilities 1.13.0 / 2015-06-14 =================== * Add `statusCode` property on `Error`s, in addition to `status` * Change `type` default to `application/json` for JSON parser * Change `type` default to `application/x-www-form-urlencoded` for urlencoded parser * Provide static `require` analysis * Use the `http-errors` module to generate errors * deps: bytes@2.1.0 - Slight optimizations * deps: iconv-lite@0.4.10 - The encoding UTF-16 without BOM now defaults to UTF-16LE when detection fails - Leading BOM is now removed when decoding * deps: on-finished@~2.3.0 - Add defined behavior for HTTP `CONNECT` requests - Add defined behavior for HTTP `Upgrade` requests - deps: ee-first@1.1.1 * deps: qs@3.1.0 - Fix dropping parameters like `hasOwnProperty` - Fix various parsing edge cases - Parsed object now has `null` prototype * deps: raw-body@~2.1.1 - Use `unpipe` module for unpiping requests - deps: iconv-lite@0.4.10 * deps: type-is@~1.6.3 - deps: mime-types@~2.1.1 - perf: reduce try block size - perf: remove bitwise operations * perf: enable strict mode * perf: remove argument reassignment * perf: remove delete call 1.12.4 / 2015-05-10 =================== * deps: debug@~2.2.0 * deps: qs@2.4.2 - Fix allowing parameters like `constructor` * deps: on-finished@~2.2.1 * deps: raw-body@~2.0.1 - Fix a false-positive when unpiping in Node.js 0.8 - deps: bytes@2.0.1 * deps: type-is@~1.6.2 - deps: mime-types@~2.0.11 1.12.3 / 2015-04-15 =================== * Slight efficiency improvement when not debugging * deps: depd@~1.0.1 * deps: iconv-lite@0.4.8 - Add encoding alias UNICODE-1-1-UTF-7 * deps: raw-body@1.3.4 - Fix hanging callback if request aborts during read - deps: iconv-lite@0.4.8 1.12.2 / 2015-03-16 =================== * deps: qs@2.4.1 - Fix error when parameter `hasOwnProperty` is present 1.12.1 / 2015-03-15 =================== * deps: debug@~2.1.3 - Fix high intensity foreground color for bold - deps: ms@0.7.0 * deps: type-is@~1.6.1 - deps: mime-types@~2.0.10 1.12.0 / 2015-02-13 =================== * add `debug` messages * accept a function for the `type` option * use `content-type` to parse `Content-Type` headers * deps: iconv-lite@0.4.7 - Gracefully support enumerables on `Object.prototype` * deps: raw-body@1.3.3 - deps: iconv-lite@0.4.7 * deps: type-is@~1.6.0 - fix argument reassignment - fix false-positives in `hasBody` `Transfer-Encoding` check - support wildcard for both type and subtype (`*/*`) - deps: mime-types@~2.0.9 1.11.0 / 2015-01-30 =================== * make internal `extended: true` depth limit infinity * deps: type-is@~1.5.6 - deps: mime-types@~2.0.8 1.10.2 / 2015-01-20 =================== * deps: iconv-lite@0.4.6 - Fix rare aliases of single-byte encodings * deps: raw-body@1.3.2 - deps: iconv-lite@0.4.6 1.10.1 / 2015-01-01 =================== * deps: on-finished@~2.2.0 * deps: type-is@~1.5.5 - deps: mime-types@~2.0.7 1.10.0 / 2014-12-02 =================== * make internal `extended: true` array limit dynamic 1.9.3 / 2014-11-21 ================== * deps: iconv-lite@0.4.5 - Fix Windows-31J and X-SJIS encoding support * deps: qs@2.3.3 - Fix `arrayLimit` behavior * deps: raw-body@1.3.1 - deps: iconv-lite@0.4.5 * deps: type-is@~1.5.3 - deps: mime-types@~2.0.3 1.9.2 / 2014-10-27 ================== * deps: qs@2.3.2 - Fix parsing of mixed objects and values 1.9.1 / 2014-10-22 ================== * deps: on-finished@~2.1.1 - Fix handling of pipelined requests * deps: qs@2.3.0 - Fix parsing of mixed implicit and explicit arrays * deps: type-is@~1.5.2 - deps: mime-types@~2.0.2 1.9.0 / 2014-09-24 ================== * include the charset in "unsupported charset" error message * include the encoding in "unsupported content encoding" error message * deps: depd@~1.0.0 1.8.4 / 2014-09-23 ================== * fix content encoding to be case-insensitive 1.8.3 / 2014-09-19 ================== * deps: qs@2.2.4 - Fix issue with object keys starting with numbers truncated 1.8.2 / 2014-09-15 ================== * deps: depd@0.4.5 1.8.1 / 2014-09-07 ================== * deps: media-typer@0.3.0 * deps: type-is@~1.5.1 1.8.0 / 2014-09-05 ================== * make empty-body-handling consistent between chunked requests - empty `json` produces `{}` - empty `raw` produces `new Buffer(0)` - empty `text` produces `''` - empty `urlencoded` produces `{}` * deps: qs@2.2.3 - Fix issue where first empty value in array is discarded * deps: type-is@~1.5.0 - fix `hasbody` to be true for `content-length: 0` 1.7.0 / 2014-09-01 ================== * add `parameterLimit` option to `urlencoded` parser * change `urlencoded` extended array limit to 100 * respond with 413 when over `parameterLimit` in `urlencoded` 1.6.7 / 2014-08-29 ================== * deps: qs@2.2.2 - Remove unnecessary cloning 1.6.6 / 2014-08-27 ================== * deps: qs@2.2.0 - Array parsing fix - Performance improvements 1.6.5 / 2014-08-16 ================== * deps: on-finished@2.1.0 1.6.4 / 2014-08-14 ================== * deps: qs@1.2.2 1.6.3 / 2014-08-10 ================== * deps: qs@1.2.1 1.6.2 / 2014-08-07 ================== * deps: qs@1.2.0 - Fix parsing array of objects 1.6.1 / 2014-08-06 ================== * deps: qs@1.1.0 - Accept urlencoded square brackets - Accept empty values in implicit array notation 1.6.0 / 2014-08-05 ================== * deps: qs@1.0.2 - Complete rewrite - Limits array length to 20 - Limits object depth to 5 - Limits parameters to 1,000 1.5.2 / 2014-07-27 ================== * deps: depd@0.4.4 - Work-around v8 generating empty stack traces 1.5.1 / 2014-07-26 ================== * deps: depd@0.4.3 - Fix exception when global `Error.stackTraceLimit` is too low 1.5.0 / 2014-07-20 ================== * deps: depd@0.4.2 - Add `TRACE_DEPRECATION` environment variable - Remove non-standard grey color from color output - Support `--no-deprecation` argument - Support `--trace-deprecation` argument * deps: iconv-lite@0.4.4 - Added encoding UTF-7 * deps: raw-body@1.3.0 - deps: iconv-lite@0.4.4 - Added encoding UTF-7 - Fix `Cannot switch to old mode now` error on Node.js 0.10+ * deps: type-is@~1.3.2 1.4.3 / 2014-06-19 ================== * deps: type-is@1.3.1 - fix global variable leak 1.4.2 / 2014-06-19 ================== * deps: type-is@1.3.0 - improve type parsing 1.4.1 / 2014-06-19 ================== * fix urlencoded extended deprecation message 1.4.0 / 2014-06-19 ================== * add `text` parser * add `raw` parser * check accepted charset in content-type (accepts utf-8) * check accepted encoding in content-encoding (accepts identity) * deprecate `bodyParser()` middleware; use `.json()` and `.urlencoded()` as needed * deprecate `urlencoded()` without provided `extended` option * lazy-load urlencoded parsers * parsers split into files for reduced mem usage * support gzip and deflate bodies - set `inflate: false` to turn off * deps: raw-body@1.2.2 - Support all encodings from `iconv-lite` 1.3.1 / 2014-06-11 ================== * deps: type-is@1.2.1 - Switch dependency from mime to mime-types@1.0.0 1.3.0 / 2014-05-31 ================== * add `extended` option to urlencoded parser 1.2.2 / 2014-05-27 ================== * deps: raw-body@1.1.6 - assert stream encoding on node.js 0.8 - assert stream encoding on node.js < 0.10.6 - deps: bytes@1 1.2.1 / 2014-05-26 ================== * invoke `next(err)` after request fully read - prevents hung responses and socket hang ups 1.2.0 / 2014-05-11 ================== * add `verify` option * deps: type-is@1.2.0 - support suffix matching 1.1.2 / 2014-05-11 ================== * improve json parser speed 1.1.1 / 2014-05-11 ================== * fix repeated limit parsing with every request 1.1.0 / 2014-05-10 ================== * add `type` option * deps: pin for safety and consistency 1.0.2 / 2014-04-14 ================== * use `type-is` module 1.0.1 / 2014-03-20 ================== * lower default limits to 100kb body-parser-1.19.0/LICENSE000066400000000000000000000022241346047437500150530ustar00rootroot00000000000000(The MIT License) Copyright (c) 2014 Jonathan Ong Copyright (c) 2014-2015 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. body-parser-1.19.0/README.md000066400000000000000000000413141346047437500153300ustar00rootroot00000000000000# body-parser [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Build Status][travis-image]][travis-url] [![Test Coverage][coveralls-image]][coveralls-url] Node.js body parsing middleware. Parse incoming request bodies in a middleware before your handlers, available under the `req.body` property. **Note** As `req.body`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.body.foo.toString()` may fail in multiple ways, for example the `foo` property may not be there or may not be a string, and `toString` may not be a function and instead a string or other user input. [Learn about the anatomy of an HTTP transaction in Node.js](https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/). _This does not handle multipart bodies_, due to their complex and typically large nature. For multipart bodies, you may be interested in the following modules: * [busboy](https://www.npmjs.org/package/busboy#readme) and [connect-busboy](https://www.npmjs.org/package/connect-busboy#readme) * [multiparty](https://www.npmjs.org/package/multiparty#readme) and [connect-multiparty](https://www.npmjs.org/package/connect-multiparty#readme) * [formidable](https://www.npmjs.org/package/formidable#readme) * [multer](https://www.npmjs.org/package/multer#readme) This module provides the following parsers: * [JSON body parser](#bodyparserjsonoptions) * [Raw body parser](#bodyparserrawoptions) * [Text body parser](#bodyparsertextoptions) * [URL-encoded form body parser](#bodyparserurlencodedoptions) Other body parsers you might be interested in: - [body](https://www.npmjs.org/package/body#readme) - [co-body](https://www.npmjs.org/package/co-body#readme) ## Installation ```sh $ npm install body-parser ``` ## API ```js var bodyParser = require('body-parser') ``` The `bodyParser` object exposes various factories to create middlewares. All middlewares will populate the `req.body` property with the parsed body when the `Content-Type` request header matches the `type` option, or an empty object (`{}`) if there was no body to parse, the `Content-Type` was not matched, or an error occurred. The various errors returned by this module are described in the [errors section](#errors). ### bodyParser.json([options]) Returns middleware that only parses `json` and only looks at requests where the `Content-Type` header matches the `type` option. This parser accepts any Unicode encoding of the body and supports automatic inflation of `gzip` and `deflate` encodings. A new `body` object containing the parsed data is populated on the `request` object after the middleware (i.e. `req.body`). #### Options The `json` function takes an optional `options` object that may contain any of the following keys: ##### inflate When set to `true`, then deflated (compressed) bodies will be inflated; when `false`, deflated bodies are rejected. Defaults to `true`. ##### limit Controls the maximum request body size. If this is a number, then the value 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'`. ##### reviver The `reviver` option is passed directly to `JSON.parse` as the second 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`. ##### type The `type` option is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `json`), a mime type (like `application/json`), or a mime type with a wildcard (like `*/*` or `*/json`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. Defaults to `application/json`. ##### verify The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. ### bodyParser.raw([options]) Returns middleware that parses all bodies as a `Buffer` and only looks at requests where the `Content-Type` header matches the `type` option. This parser supports automatic inflation of `gzip` and `deflate` encodings. A new `body` object containing the parsed data is populated on the `request` object after the middleware (i.e. `req.body`). This will be a `Buffer` object of the body. #### Options The `raw` function takes an optional `options` object that may contain any of the following keys: ##### inflate When set to `true`, then deflated (compressed) bodies will be inflated; when `false`, deflated bodies are rejected. Defaults to `true`. ##### limit Controls the maximum request body size. If this is a number, then the value 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'`. ##### type The `type` option is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `bin`), a mime type (like `application/octet-stream`), or a mime type with a wildcard (like `*/*` or `application/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. Defaults to `application/octet-stream`. ##### verify The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. ### bodyParser.text([options]) Returns middleware that parses all bodies as a string and only looks at requests where the `Content-Type` header matches the `type` option. This parser supports automatic inflation of `gzip` and `deflate` encodings. A new `body` string containing the parsed data is populated on the `request` object after the middleware (i.e. `req.body`). This will be a string of the body. #### Options The `text` function takes an optional `options` object that may contain any of the following keys: ##### defaultCharset Specify the default character set for the text content if the charset is not specified in the `Content-Type` header of the request. Defaults to `utf-8`. ##### inflate When set to `true`, then deflated (compressed) bodies will be inflated; when `false`, deflated bodies are rejected. Defaults to `true`. ##### limit Controls the maximum request body size. If this is a number, then the value 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'`. ##### type The `type` option is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `txt`), a mime type (like `text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. Defaults to `text/plain`. ##### verify The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. ### bodyParser.urlencoded([options]) Returns middleware that only parses `urlencoded` bodies and only looks at requests where the `Content-Type` header matches the `type` option. This parser accepts only UTF-8 encoding of the body and supports automatic inflation of `gzip` and `deflate` encodings. A new `body` object containing the parsed data is populated on the `request` object after the middleware (i.e. `req.body`). This object will contain key-value pairs, where the value can be a string or array (when `extended` is `false`), or any type (when `extended` is `true`). #### Options The `urlencoded` function takes an optional `options` object that may contain any of the following keys: ##### extended The `extended` option allows to choose between parsing the URL-encoded data with the `querystring` library (when `false`) or the `qs` library (when `true`). The "extended" syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded. For more information, please [see the qs library](https://www.npmjs.org/package/qs#readme). Defaults to `true`, but using the default has been deprecated. Please research into the difference between `qs` and `querystring` and choose the appropriate setting. ##### inflate When set to `true`, then deflated (compressed) bodies will be inflated; when `false`, deflated bodies are rejected. Defaults to `true`. ##### limit Controls the maximum request body size. If this is a number, then the value 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'`. ##### parameterLimit The `parameterLimit` option controls the maximum number of parameters that are allowed in the URL-encoded data. If a request contains more parameters than this value, a 413 will be returned to the client. Defaults to `1000`. ##### type The `type` option is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `urlencoded`), a mime type (like `application/x-www-form-urlencoded`), or a mime type with a wildcard (like `*/x-www-form-urlencoded`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. Defaults to `application/x-www-form-urlencoded`. ##### verify The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. ## Errors The middlewares provided by this module create errors depending on the error condition during parsing. The errors will typically have a `status`/`statusCode` property that contains the suggested HTTP response code, an `expose` property to determine if the `message` property should be displayed to the client, a `type` property to determine the type of error without matching against the `message`, and a `body` property containing the read body, if available. The following are the common errors emitted, though any error can come through for various reasons. ### content encoding unsupported This error will occur when the request had a `Content-Encoding` header that contained an encoding but the "inflation" option was set to `false`. The `status` property is set to `415`, the `type` property is set to `'encoding.unsupported'`, and the `charset` property will be set to the encoding that is unsupported. ### request aborted This error will occur when the request is aborted by the client before reading the body has finished. The `received` property will be set to the number of bytes received before the request was aborted and the `expected` property is set to the number of expected bytes. The `status` property is set to `400` and `type` property is set to `'request.aborted'`. ### request entity too large This error will occur when the request body's size is larger than the "limit" option. The `limit` property will be set to the byte limit and the `length` property will be set to the request body's length. The `status` property is set to `413` and the `type` property is set to `'entity.too.large'`. ### request size did not match content length This error will occur when the request's length did not match the length from the `Content-Length` header. This typically occurs when the request is malformed, typically when the `Content-Length` header was calculated based on characters instead of bytes. The `status` property is set to `400` and the `type` property is set to `'request.size.invalid'`. ### stream encoding should not be set This error will occur when something called the `req.setEncoding` method prior to this middleware. This module operates directly on bytes only and you cannot call `req.setEncoding` when using this module. The `status` property is set to `500` and the `type` property is set to `'stream.encoding.set'`. ### too many parameters This error will occur when the content of the request exceeds the configured `parameterLimit` for the `urlencoded` parser. The `status` property is set to `413` and the `type` property is set to `'parameters.too.many'`. ### unsupported charset "BOGUS" This error will occur when the request had a charset parameter in the `Content-Type` header, but the `iconv-lite` module does not support it OR the parser does not support it. The charset is contained in the message as well as in the `charset` property. The `status` property is set to `415`, the `type` property is set to `'charset.unsupported'`, and the `charset` property is set to the charset that is unsupported. ### unsupported content encoding "bogus" This error will occur when the request had a `Content-Encoding` header that contained an unsupported encoding. The encoding is contained in the message as well as in the `encoding` property. The `status` property is set to `415`, the `type` property is set to `'encoding.unsupported'`, and the `encoding` property is set to the encoding that is unsupported. ## Examples ### Express/Connect top-level generic This example demonstrates adding a generic JSON and URL-encoded parser as a top-level middleware, which will parse the bodies of all incoming requests. This is the simplest setup. ```js var express = require('express') var bodyParser = require('body-parser') var app = express() // parse application/x-www-form-urlencoded app.use(bodyParser.urlencoded({ extended: false })) // parse application/json app.use(bodyParser.json()) app.use(function (req, res) { res.setHeader('Content-Type', 'text/plain') res.write('you posted:\n') res.end(JSON.stringify(req.body, null, 2)) }) ``` ### Express route-specific This example demonstrates adding body parsers specifically to the routes that need them. In general, this is the most recommended way to use body-parser with Express. ```js var express = require('express') var bodyParser = require('body-parser') var app = express() // create application/json parser var jsonParser = bodyParser.json() // create application/x-www-form-urlencoded parser var urlencodedParser = bodyParser.urlencoded({ extended: false }) // POST /login gets urlencoded bodies app.post('/login', urlencodedParser, function (req, res) { res.send('welcome, ' + req.body.username) }) // POST /api/users gets JSON bodies app.post('/api/users', jsonParser, function (req, res) { // create user in req.body }) ``` ### Change accepted type for parsers All the parsers accept a `type` option which allows you to change the `Content-Type` that the middleware will parse. ```js var express = require('express') var bodyParser = require('body-parser') var app = express() // parse various different custom JSON types as JSON app.use(bodyParser.json({ type: 'application/*+json' })) // parse some custom thing into a Buffer app.use(bodyParser.raw({ type: 'application/vnd.custom-type' })) // parse an HTML body into a string app.use(bodyParser.text({ type: 'text/html' })) ``` ## License [MIT](LICENSE) [npm-image]: https://img.shields.io/npm/v/body-parser.svg [npm-url]: https://npmjs.org/package/body-parser [travis-image]: https://img.shields.io/travis/expressjs/body-parser/master.svg [travis-url]: https://travis-ci.org/expressjs/body-parser [coveralls-image]: https://img.shields.io/coveralls/expressjs/body-parser/master.svg [coveralls-url]: https://coveralls.io/r/expressjs/body-parser?branch=master [downloads-image]: https://img.shields.io/npm/dm/body-parser.svg [downloads-url]: https://npmjs.org/package/body-parser body-parser-1.19.0/index.js000066400000000000000000000051401346047437500155130ustar00rootroot00000000000000/*! * body-parser * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict' /** * Module dependencies. * @private */ var deprecate = require('depd')('body-parser') /** * Cache of loaded parsers. * @private */ var parsers = Object.create(null) /** * @typedef Parsers * @type {function} * @property {function} json * @property {function} raw * @property {function} text * @property {function} urlencoded */ /** * Module exports. * @type {Parsers} */ exports = module.exports = deprecate.function(bodyParser, 'bodyParser: use individual json/urlencoded middlewares') /** * JSON parser. * @public */ Object.defineProperty(exports, 'json', { configurable: true, enumerable: true, get: createParserGetter('json') }) /** * Raw parser. * @public */ Object.defineProperty(exports, 'raw', { configurable: true, enumerable: true, get: createParserGetter('raw') }) /** * Text parser. * @public */ Object.defineProperty(exports, 'text', { configurable: true, enumerable: true, get: createParserGetter('text') }) /** * URL-encoded parser. * @public */ Object.defineProperty(exports, 'urlencoded', { configurable: true, enumerable: true, get: createParserGetter('urlencoded') }) /** * Create a middleware to parse json and urlencoded bodies. * * @param {object} [options] * @return {function} * @deprecated * @public */ function bodyParser (options) { var opts = {} // exclude type option if (options) { for (var prop in options) { if (prop !== 'type') { opts[prop] = options[prop] } } } var _urlencoded = exports.urlencoded(opts) var _json = exports.json(opts) return function bodyParser (req, res, next) { _json(req, res, function (err) { if (err) return next(err) _urlencoded(req, res, next) }) } } /** * Create a getter for loading a parser. * @private */ function createParserGetter (name) { return function get () { return loadParser(name) } } /** * Load a parser module. * @private */ function loadParser (parserName) { var parser = parsers[parserName] if (parser !== undefined) { return parser } // this uses a switch for static require analysis switch (parserName) { case 'json': parser = require('./lib/types/json') break case 'raw': parser = require('./lib/types/raw') break case 'text': parser = require('./lib/types/text') break case 'urlencoded': parser = require('./lib/types/urlencoded') break } // store to prevent invoking require() return (parsers[parserName] = parser) } body-parser-1.19.0/lib/000077500000000000000000000000001346047437500146145ustar00rootroot00000000000000body-parser-1.19.0/lib/read.js000066400000000000000000000074661346047437500161020ustar00rootroot00000000000000/*! * body-parser * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict' /** * Module dependencies. * @private */ var createError = require('http-errors') var getBody = require('raw-body') var iconv = require('iconv-lite') var onFinished = require('on-finished') var zlib = require('zlib') /** * Module exports. */ 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 * @private */ function read (req, res, next, parse, debug, options) { var length var opts = options var stream // flag as parsed req._body = true // read options var encoding = opts.encoding !== null ? opts.encoding : null var verify = opts.verify try { // get the content stream stream = contentstream(req, debug, opts.inflate) length = stream.length stream.length = undefined } catch (err) { return next(err) } // set raw-body options opts.length = length opts.encoding = verify ? null : encoding // assert charset is supported if (opts.encoding === null && encoding !== null && !iconv.encodingExists(encoding)) { return next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', { charset: encoding.toLowerCase(), type: 'charset.unsupported' })) } // read body debug('read body') getBody(stream, opts, function (error, body) { if (error) { var _error if (error.type === 'encoding.unsupported') { // echo back charset _error = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', { charset: encoding.toLowerCase(), type: 'charset.unsupported' }) } else { // set status code on error _error = createError(400, error) } // read off entire request stream.resume() onFinished(req, function onfinished () { next(createError(400, _error)) }) return } // verify if (verify) { try { debug('verify body') verify(req, res, body, encoding) } catch (err) { next(createError(403, err, { body: body, type: err.type || 'entity.verify.failed' })) return } } // parse var str = body try { debug('parse body') str = typeof body !== 'string' && encoding !== null ? iconv.decode(body, encoding) : body req.body = parse(str) } catch (err) { next(createError(400, err, { body: str, type: err.type || 'entity.parse.failed' })) return } next() }) } /** * Get the content stream of the request. * * @param {object} req * @param {function} debug * @param {boolean} [inflate=true] * @return {object} * @api private */ function contentstream (req, debug, inflate) { var encoding = (req.headers['content-encoding'] || 'identity').toLowerCase() var length = req.headers['content-length'] var stream debug('content-encoding "%s"', encoding) if (inflate === false && encoding !== 'identity') { throw createError(415, 'content encoding unsupported', { encoding: encoding, type: 'encoding.unsupported' }) } switch (encoding) { case 'deflate': stream = zlib.createInflate() debug('inflate body') req.pipe(stream) break case 'gzip': stream = zlib.createGunzip() debug('gunzip body') req.pipe(stream) break case 'identity': stream = req stream.length = length break default: throw createError(415, 'unsupported content encoding "' + encoding + '"', { encoding: encoding, type: 'encoding.unsupported' }) } return stream } body-parser-1.19.0/lib/types/000077500000000000000000000000001346047437500157605ustar00rootroot00000000000000body-parser-1.19.0/lib/types/json.js000066400000000000000000000114661346047437500172770ustar00rootroot00000000000000/*! * 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:json') var read = require('../read') var typeis = require('type-is') /** * Module exports. */ module.exports = json /** * RegExp to match the first non-space in a string. * * Allowed whitespace is defined in RFC 7159: * * ws = *( * %x20 / ; Space * %x09 / ; Horizontal tab * %x0A / ; Line feed or New line * %x0D ) ; Carriage return */ var FIRST_CHAR_REGEXP = /^[\x20\x09\x0a\x0d]*(.)/ // eslint-disable-line no-control-regex /** * Create a middleware to parse JSON bodies. * * @param {object} [options] * @return {function} * @public */ function json (options) { var opts = options || {} var limit = typeof opts.limit !== 'number' ? bytes.parse(opts.limit || '100kb') : opts.limit var inflate = opts.inflate !== false var reviver = opts.reviver var strict = opts.strict !== false var type = opts.type || 'application/json' var verify = opts.verify || false 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 function parse (body) { if (body.length === 0) { // special-case empty json body, as it's a common client-side mistake // TODO: maybe make this configurable or part of "strict" option return {} } if (strict) { var first = firstchar(body) if (first !== '{' && first !== '[') { debug('strict violation') throw createStrictSyntaxError(body, first) } } try { debug('parse json') return JSON.parse(body, reviver) } catch (e) { throw normalizeJsonSyntaxError(e, { message: e.message, stack: e.stack }) } } return function jsonParser (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 per RFC 7159 sec 8.1 var charset = getCharset(req) || 'utf-8' if (charset.substr(0, 4) !== 'utf-') { debug('invalid charset') next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', { charset: charset, type: 'charset.unsupported' })) return } // read read(req, res, next, parse, debug, { encoding: charset, inflate: inflate, limit: limit, verify: verify }) } } /** * Create strict violation syntax error matching native error. * * @param {string} str * @param {string} char * @return {Error} * @private */ function createStrictSyntaxError (str, char) { var index = str.indexOf(char) var partial = str.substring(0, index) + '#' try { JSON.parse(partial); /* istanbul ignore next */ throw new SyntaxError('strict violation') } catch (e) { return normalizeJsonSyntaxError(e, { message: e.message.replace('#', char), stack: e.stack }) } } /** * Get the first non-whitespace character in a string. * * @param {string} str * @return {function} * @private */ function firstchar (str) { return FIRST_CHAR_REGEXP.exec(str)[1] } /** * 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 } } /** * Normalize a SyntaxError for JSON.parse. * * @param {SyntaxError} error * @param {object} obj * @return {SyntaxError} */ function normalizeJsonSyntaxError (error, obj) { var keys = Object.getOwnPropertyNames(error) for (var i = 0; i < keys.length; i++) { var key = keys[i] if (key !== 'stack' && key !== 'message') { delete error[key] } } // replace stack before message for Node.js 0.10 and below error.stack = obj.stack.replace(error.message, obj.message) error.message = obj.message return error } /** * Get the simple type checker. * * @param {string} type * @return {function} */ function typeChecker (type) { return function checkType (req) { return Boolean(typeis(req, type)) } } body-parser-1.19.0/lib/types/raw.js000066400000000000000000000035341346047437500171140ustar00rootroot00000000000000/*! * body-parser * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict' /** * Module dependencies. */ var bytes = require('bytes') var debug = require('debug')('body-parser:raw') var read = require('../read') var typeis = require('type-is') /** * Module exports. */ module.exports = raw /** * Create a middleware to parse raw bodies. * * @param {object} [options] * @return {function} * @api public */ function raw (options) { var opts = options || {} var inflate = opts.inflate !== false var limit = typeof opts.limit !== 'number' ? bytes.parse(opts.limit || '100kb') : opts.limit var type = opts.type || 'application/octet-stream' var verify = opts.verify || false 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 function parse (buf) { return buf } return function rawParser (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 } // read read(req, res, next, parse, debug, { encoding: null, inflate: inflate, limit: limit, verify: verify }) } } /** * Get the simple type checker. * * @param {string} type * @return {function} */ function typeChecker (type) { return function checkType (req) { return Boolean(typeis(req, type)) } } body-parser-1.19.0/lib/types/text.js000066400000000000000000000043551346047437500173110ustar00rootroot00000000000000/*! * body-parser * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict' /** * Module dependencies. */ var bytes = require('bytes') var contentType = require('content-type') var debug = require('debug')('body-parser:text') var read = require('../read') var typeis = require('type-is') /** * Module exports. */ module.exports = text /** * Create a middleware to parse text bodies. * * @param {object} [options] * @return {function} * @api public */ function text (options) { var opts = options || {} var defaultCharset = opts.defaultCharset || 'utf-8' var inflate = opts.inflate !== false var limit = typeof opts.limit !== 'number' ? bytes.parse(opts.limit || '100kb') : opts.limit var type = opts.type || 'text/plain' var verify = opts.verify || false 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 function parse (buf) { return buf } return function textParser (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 } // get charset var charset = getCharset(req) || defaultCharset // read read(req, res, next, parse, debug, { encoding: charset, 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)) } } body-parser-1.19.0/lib/types/urlencoded.js000066400000000000000000000132451346047437500204470ustar00rootroot00000000000000/*! * 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)) } } body-parser-1.19.0/package.json000066400000000000000000000030241346047437500163330ustar00rootroot00000000000000{ "name": "body-parser", "description": "Node.js body parsing middleware", "version": "1.19.0", "contributors": [ "Douglas Christopher Wilson ", "Jonathan Ong (http://jongleberry.com)" ], "license": "MIT", "repository": "expressjs/body-parser", "dependencies": { "bytes": "3.1.0", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", "http-errors": "1.7.2", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", "qs": "6.7.0", "raw-body": "2.4.0", "type-is": "~1.6.17" }, "devDependencies": { "eslint": "5.16.0", "eslint-config-standard": "12.0.0", "eslint-plugin-import": "2.17.2", "eslint-plugin-markdown": "1.0.0", "eslint-plugin-node": "8.0.1", "eslint-plugin-promise": "4.1.1", "eslint-plugin-standard": "4.0.0", "istanbul": "0.4.5", "methods": "1.1.2", "mocha": "6.1.4", "safe-buffer": "5.1.2", "supertest": "4.0.2" }, "files": [ "lib/", "LICENSE", "HISTORY.md", "index.js" ], "engines": { "node": ">= 0.8" }, "scripts": { "lint": "eslint --plugin markdown --ext js,md .", "test": "mocha --require test/support/env --reporter spec --check-leaks --bail test/", "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/", "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/" } } body-parser-1.19.0/test/000077500000000000000000000000001346047437500150255ustar00rootroot00000000000000body-parser-1.19.0/test/.eslintrc.yml000066400000000000000000000000231346047437500174440ustar00rootroot00000000000000env: mocha: true body-parser-1.19.0/test/body-parser.js000066400000000000000000000101671346047437500176170ustar00rootroot00000000000000 var http = require('http') var methods = require('methods') var request = require('supertest') var bodyParser = require('..') describe('bodyParser()', function () { before(function () { this.server = createServer() }) it('should default to {}', function (done) { request(this.server) .post('/') .expect(200, '{}', done) }) it('should parse JSON', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) it('should parse x-www-form-urlencoded', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) it('should handle duplicated middleware', function (done) { var _bodyParser = bodyParser() var server = http.createServer(function (req, res) { _bodyParser(req, res, function (err0) { _bodyParser(req, res, function (err1) { var err = err0 || err1 res.statusCode = err ? (err.status || 500) : 200 res.end(err ? err.message : JSON.stringify(req.body)) }) }) }) request(server) .post('/') .set('Content-Type', 'application/json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) describe('http methods', function () { before(function () { var _bodyParser = bodyParser() this.server = http.createServer(function (req, res) { _bodyParser(req, res, function (err) { if (err) { res.statusCode = 500 res.end(err.message) return } res.statusCode = req.headers['x-expect-method'] === req.method ? req.body.user === 'tobi' ? 201 : 400 : 405 res.end() }) }) }) methods.slice().sort().forEach(function (method) { if (method === 'connect') { // except CONNECT return } it('should support ' + method.toUpperCase() + ' requests', function (done) { request(this.server)[method]('/') .set('Content-Type', 'application/json') .set('Content-Length', '15') .set('X-Expect-Method', method.toUpperCase()) .send('{"user":"tobi"}') .expect(201, done) }) }) }) describe('with type option', function () { before(function () { this.server = createServer({ limit: '1mb', type: 'application/octet-stream' }) }) it('should parse JSON', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) it('should parse x-www-form-urlencoded', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) }) describe('with verify option', function () { it('should apply to json', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x20) throw new Error('no leading space') } }) request(server) .post('/') .set('Content-Type', 'application/json') .send(' {"user":"tobi"}') .expect(403, 'no leading space', done) }) it('should apply to urlencoded', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x20) throw new Error('no leading space') } }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(' user=tobi') .expect(403, 'no leading space', done) }) }) }) function createServer (opts) { var _bodyParser = bodyParser(opts) return http.createServer(function (req, res) { _bodyParser(req, res, function (err) { res.statusCode = err ? (err.status || 500) : 200 res.end(err ? err.message : JSON.stringify(req.body)) }) }) } body-parser-1.19.0/test/json.js000066400000000000000000000522001346047437500163330ustar00rootroot00000000000000 var assert = require('assert') var Buffer = require('safe-buffer').Buffer var http = require('http') var request = require('supertest') var bodyParser = require('..') describe('bodyParser.json()', function () { it('should parse JSON', function (done) { request(createServer()) .post('/') .set('Content-Type', 'application/json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) it('should handle Content-Length: 0', function (done) { request(createServer()) .get('/') .set('Content-Type', 'application/json') .set('Content-Length', '0') .expect(200, '{}', done) }) it('should handle empty message-body', function (done) { request(createServer()) .get('/') .set('Content-Type', 'application/json') .set('Transfer-Encoding', 'chunked') .expect(200, '{}', done) }) it('should handle no message-body', function (done) { request(createServer()) .get('/') .set('Content-Type', 'application/json') .unset('Transfer-Encoding') .expect(200, '{}', done) }) it('should 400 when invalid content-length', function (done) { var jsonParser = bodyParser.json() var server = createServer(function (req, res, next) { req.headers['content-length'] = '20' // bad length jsonParser(req, res, next) }) request(server) .post('/') .set('Content-Type', 'application/json') .send('{"str":') .expect(400, /content length/, done) }) it('should handle duplicated middleware', function (done) { var jsonParser = bodyParser.json() var server = createServer(function (req, res, next) { jsonParser(req, res, function (err) { if (err) return next(err) jsonParser(req, res, next) }) }) request(server) .post('/') .set('Content-Type', 'application/json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) describe('when JSON is invalid', function () { before(function () { this.server = createServer() }) it('should 400 for bad token', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('{:') .expect(400, parseError('{:'), done) }) it('should 400 for incomplete', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('{"user"') .expect(400, parseError('{"user"'), done) }) it('should error with type = "entity.parse.failed"', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .set('X-Error-Property', 'type') .send(' {"user"') .expect(400, 'entity.parse.failed', done) }) it('should include original body on error object', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .set('X-Error-Property', 'body') .send(' {"user"') .expect(400, ' {"user"', done) }) }) describe('with limit option', function () { it('should 413 when over limit with Content-Length', function (done) { var buf = Buffer.alloc(1024, '.') request(createServer({ limit: '1kb' })) .post('/') .set('Content-Type', 'application/json') .set('Content-Length', '1034') .send(JSON.stringify({ str: buf.toString() })) .expect(413, done) }) it('should error with type = "entity.too.large"', function (done) { var buf = Buffer.alloc(1024, '.') request(createServer({ limit: '1kb' })) .post('/') .set('Content-Type', 'application/json') .set('Content-Length', '1034') .set('X-Error-Property', 'type') .send(JSON.stringify({ str: buf.toString() })) .expect(413, 'entity.too.large', done) }) it('should 413 when over limit with chunked encoding', function (done) { var buf = Buffer.alloc(1024, '.') var server = createServer({ limit: '1kb' }) var test = request(server).post('/') test.set('Content-Type', 'application/json') test.set('Transfer-Encoding', 'chunked') test.write('{"str":') test.write('"' + buf.toString() + '"}') test.expect(413, done) }) it('should accept number of bytes', function (done) { var buf = Buffer.alloc(1024, '.') request(createServer({ limit: 1024 })) .post('/') .set('Content-Type', 'application/json') .send(JSON.stringify({ str: buf.toString() })) .expect(413, done) }) it('should not change when options altered', function (done) { var buf = Buffer.alloc(1024, '.') var options = { limit: '1kb' } var server = createServer(options) options.limit = '100kb' request(server) .post('/') .set('Content-Type', 'application/json') .send(JSON.stringify({ str: buf.toString() })) .expect(413, done) }) it('should not hang response', function (done) { var buf = Buffer.alloc(10240, '.') var server = createServer({ limit: '8kb' }) var test = request(server).post('/') test.set('Content-Type', 'application/json') test.write(buf) test.write(buf) test.write(buf) test.expect(413, done) }) }) describe('with inflate option', function () { describe('when false', function () { before(function () { this.server = createServer({ inflate: false }) }) it('should not accept content-encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/json') test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) test.expect(415, 'content encoding unsupported', done) }) }) describe('when true', function () { before(function () { this.server = createServer({ inflate: true }) }) it('should accept content-encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/json') test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) test.expect(200, '{"name":"论"}', done) }) }) }) describe('with strict option', function () { describe('when undefined', function () { before(function () { this.server = createServer() }) it('should 400 on primitives', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('true') .expect(400, parseError('#rue').replace('#', 't'), done) }) }) describe('when false', function () { before(function () { this.server = createServer({ strict: false }) }) it('should parse primitives', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('true') .expect(200, 'true', done) }) }) describe('when true', function () { before(function () { this.server = createServer({ strict: true }) }) it('should not parse primitives', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('true') .expect(400, parseError('#rue').replace('#', 't'), done) }) it('should not parse primitives with leading whitespaces', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send(' true') .expect(400, parseError(' #rue').replace('#', 't'), done) }) it('should allow leading whitespaces in JSON', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send(' { "user": "tobi" }') .expect(200, '{"user":"tobi"}', done) }) it('should error with type = "entity.parse.failed"', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .set('X-Error-Property', 'type') .send('true') .expect(400, 'entity.parse.failed', done) }) it('should include correct message in stack trace', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .set('X-Error-Property', 'stack') .send('true') .expect(400) .expect(shouldContainInBody(parseError('#rue').replace('#', 't'))) .end(done) }) }) }) describe('with type option', function () { describe('when "application/vnd.api+json"', function () { before(function () { this.server = createServer({ type: 'application/vnd.api+json' }) }) it('should parse JSON for custom type', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/vnd.api+json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) it('should ignore standard type', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('{"user":"tobi"}') .expect(200, '{}', done) }) }) describe('when ["application/json", "application/vnd.api+json"]', function () { before(function () { this.server = createServer({ type: ['application/json', 'application/vnd.api+json'] }) }) it('should parse JSON for "application/json"', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) it('should parse JSON for "application/vnd.api+json"', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/vnd.api+json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) it('should ignore "application/x-json"', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-json') .send('{"user":"tobi"}') .expect(200, '{}', done) }) }) describe('when a function', function () { it('should parse when truthy value returned', function (done) { var server = createServer({ type: accept }) function accept (req) { return req.headers['content-type'] === 'application/vnd.api+json' } request(server) .post('/') .set('Content-Type', 'application/vnd.api+json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) it('should work without content-type', function (done) { var server = createServer({ type: accept }) function accept (req) { return true } var test = request(server).post('/') test.write('{"user":"tobi"}') test.expect(200, '{"user":"tobi"}', done) }) it('should not invoke without a body', function (done) { var server = createServer({ type: accept }) function accept (req) { throw new Error('oops!') } request(server) .get('/') .expect(200, done) }) }) }) describe('with verify option', function () { it('should assert value if function', function () { assert.throws(createServer.bind(null, { verify: 'lol' }), /TypeError: option verify must be function/) }) it('should error from verify', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x5b) throw new Error('no arrays') } }) request(server) .post('/') .set('Content-Type', 'application/json') .send('["tobi"]') .expect(403, 'no arrays', done) }) it('should error with type = "entity.verify.failed"', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x5b) throw new Error('no arrays') } }) request(server) .post('/') .set('Content-Type', 'application/json') .set('X-Error-Property', 'type') .send('["tobi"]') .expect(403, 'entity.verify.failed', done) }) it('should allow custom codes', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] !== 0x5b) return var err = new Error('no arrays') err.status = 400 throw err } }) request(server) .post('/') .set('Content-Type', 'application/json') .send('["tobi"]') .expect(400, 'no arrays', done) }) it('should allow custom type', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] !== 0x5b) return var err = new Error('no arrays') err.type = 'foo.bar' throw err } }) request(server) .post('/') .set('Content-Type', 'application/json') .set('X-Error-Property', 'type') .send('["tobi"]') .expect(403, 'foo.bar', done) }) it('should include original body on error object', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x5b) throw new Error('no arrays') } }) request(server) .post('/') .set('Content-Type', 'application/json') .set('X-Error-Property', 'body') .send('["tobi"]') .expect(403, '["tobi"]', done) }) it('should allow pass-through', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x5b) throw new Error('no arrays') } }) request(server) .post('/') .set('Content-Type', 'application/json') .send('{"user":"tobi"}') .expect(200, '{"user":"tobi"}', done) }) it('should work with different charsets', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x5b) throw new Error('no arrays') } }) var test = request(server).post('/') test.set('Content-Type', 'application/json; charset=utf-16') test.write(Buffer.from('feff007b0022006e0061006d00650022003a00228bba0022007d', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should 415 on unknown charset prior to verify', function (done) { var server = createServer({ verify: function (req, res, buf) { throw new Error('unexpected verify call') } }) var test = request(server).post('/') test.set('Content-Type', 'application/json; charset=x-bogus') test.write(Buffer.from('00000000', 'hex')) test.expect(415, 'unsupported charset "X-BOGUS"', done) }) }) describe('charset', function () { before(function () { this.server = createServer() }) it('should parse utf-8', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/json; charset=utf-8') test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should parse utf-16', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/json; charset=utf-16') test.write(Buffer.from('feff007b0022006e0061006d00650022003a00228bba0022007d', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should parse when content-length != char length', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/json; charset=utf-8') test.set('Content-Length', '13') test.write(Buffer.from('7b2274657374223a22c3a5227d', 'hex')) test.expect(200, '{"test":"å"}', done) }) it('should default to utf-8', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/json') test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should fail on unknown charset', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/json; charset=koi8-r') test.write(Buffer.from('7b226e616d65223a22cec5d4227d', 'hex')) test.expect(415, 'unsupported charset "KOI8-R"', done) }) it('should error with type = "charset.unsupported"', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/json; charset=koi8-r') test.set('X-Error-Property', 'type') test.write(Buffer.from('7b226e616d65223a22cec5d4227d', 'hex')) test.expect(415, 'charset.unsupported', done) }) }) describe('encoding', function () { before(function () { this.server = createServer({ limit: '1kb' }) }) it('should parse without encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/json') test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should support identity encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'identity') test.set('Content-Type', 'application/json') test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should support gzip encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/json') test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should support deflate encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'deflate') test.set('Content-Type', 'application/json') test.write(Buffer.from('789cab56ca4bcc4d55b2527ab16e97522d00274505ac', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should be case-insensitive', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'GZIP') test.set('Content-Type', 'application/json') test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should 415 on unknown encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'nulls') test.set('Content-Type', 'application/json') test.write(Buffer.from('000000000000', 'hex')) test.expect(415, 'unsupported content encoding "nulls"', done) }) it('should error with type = "encoding.unsupported"', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'nulls') test.set('Content-Type', 'application/json') test.set('X-Error-Property', 'type') test.write(Buffer.from('000000000000', 'hex')) test.expect(415, 'encoding.unsupported', done) }) it('should 400 on malformed encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/json') test.write(Buffer.from('1f8b080000000000000bab56cc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) test.expect(400, done) }) it('should 413 when inflated value exceeds limit', function (done) { // gzip'd data exceeds 1kb, but deflated below 1kb var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/json') test.write(Buffer.from('1f8b080000000000000bedc1010d000000c2a0f74f6d0f071400000000000000', 'hex')) test.write(Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex')) test.write(Buffer.from('0000000000000000004f0625b3b71650c30000', 'hex')) test.expect(413, done) }) }) }) function createServer (opts) { var _bodyParser = typeof opts !== 'function' ? bodyParser.json(opts) : opts return http.createServer(function (req, res) { _bodyParser(req, res, function (err) { if (err) { res.statusCode = err.status || 500 res.end(err[req.headers['x-error-property'] || 'message']) } else { res.statusCode = 200 res.end(JSON.stringify(req.body)) } }) }) } function parseError (str) { try { JSON.parse(str); throw new SyntaxError('strict violation') } catch (e) { return e.message } } function shouldContainInBody (str) { return function (res) { assert.ok(res.text.indexOf(str) !== -1, 'expected \'' + res.text + '\' to contain \'' + str + '\'') } } body-parser-1.19.0/test/raw.js000066400000000000000000000301141346047437500161530ustar00rootroot00000000000000 var assert = require('assert') var Buffer = require('safe-buffer').Buffer var http = require('http') var request = require('supertest') var bodyParser = require('..') describe('bodyParser.raw()', function () { before(function () { this.server = createServer() }) it('should parse application/octet-stream', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/octet-stream') .send('the user is tobi') .expect(200, 'buf:746865207573657220697320746f6269', done) }) it('should 400 when invalid content-length', function (done) { var rawParser = bodyParser.raw() var server = createServer(function (req, res, next) { req.headers['content-length'] = '20' // bad length rawParser(req, res, next) }) request(server) .post('/') .set('Content-Type', 'application/octet-stream') .send('stuff') .expect(400, /content length/, done) }) it('should handle Content-Length: 0', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/octet-stream') .set('Content-Length', '0') .expect(200, 'buf:', done) }) it('should handle empty message-body', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/octet-stream') .set('Transfer-Encoding', 'chunked') .send('') .expect(200, 'buf:', done) }) it('should handle duplicated middleware', function (done) { var rawParser = bodyParser.raw() var server = createServer(function (req, res, next) { rawParser(req, res, function (err) { if (err) return next(err) rawParser(req, res, next) }) }) request(server) .post('/') .set('Content-Type', 'application/octet-stream') .send('the user is tobi') .expect(200, 'buf:746865207573657220697320746f6269', done) }) describe('with limit option', function () { it('should 413 when over limit with Content-Length', function (done) { var buf = Buffer.alloc(1028, '.') var server = createServer({ limit: '1kb' }) var test = request(server).post('/') test.set('Content-Type', 'application/octet-stream') test.set('Content-Length', '1028') test.write(buf) test.expect(413, done) }) it('should 413 when over limit with chunked encoding', function (done) { var buf = Buffer.alloc(1028, '.') var server = createServer({ limit: '1kb' }) var test = request(server).post('/') test.set('Content-Type', 'application/octet-stream') test.set('Transfer-Encoding', 'chunked') test.write(buf) test.expect(413, done) }) it('should accept number of bytes', function (done) { var buf = Buffer.alloc(1028, '.') var server = createServer({ limit: 1024 }) var test = request(server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(buf) test.expect(413, done) }) it('should not change when options altered', function (done) { var buf = Buffer.alloc(1028, '.') var options = { limit: '1kb' } var server = createServer(options) options.limit = '100kb' var test = request(server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(buf) test.expect(413, done) }) it('should not hang response', function (done) { var buf = Buffer.alloc(10240, '.') var server = createServer({ limit: '8kb' }) var test = request(server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(buf) test.write(buf) test.write(buf) test.expect(413, done) }) }) describe('with inflate option', function () { describe('when false', function () { before(function () { this.server = createServer({ inflate: false }) }) it('should not accept content-encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) test.expect(415, 'content encoding unsupported', done) }) }) describe('when true', function () { before(function () { this.server = createServer({ inflate: true }) }) it('should accept content-encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) test.expect(200, 'buf:6e616d653de8aeba', done) }) }) }) describe('with type option', function () { describe('when "application/vnd+octets"', function () { before(function () { this.server = createServer({ type: 'application/vnd+octets' }) }) it('should parse for custom type', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/vnd+octets') test.write(Buffer.from('000102', 'hex')) test.expect(200, 'buf:000102', done) }) it('should ignore standard type', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('000102', 'hex')) test.expect(200, '{}', done) }) }) describe('when ["application/octet-stream", "application/vnd+octets"]', function () { before(function () { this.server = createServer({ type: ['application/octet-stream', 'application/vnd+octets'] }) }) it('should parse "application/octet-stream"', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('000102', 'hex')) test.expect(200, 'buf:000102', done) }) it('should parse "application/vnd+octets"', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/vnd+octets') test.write(Buffer.from('000102', 'hex')) test.expect(200, 'buf:000102', done) }) it('should ignore "application/x-foo"', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/x-foo') test.write(Buffer.from('000102', 'hex')) test.expect(200, '{}', done) }) }) describe('when a function', function () { it('should parse when truthy value returned', function (done) { var server = createServer({ type: accept }) function accept (req) { return req.headers['content-type'] === 'application/vnd.octet' } var test = request(server).post('/') test.set('Content-Type', 'application/vnd.octet') test.write(Buffer.from('000102', 'hex')) test.expect(200, 'buf:000102', done) }) it('should work without content-type', function (done) { var server = createServer({ type: accept }) function accept (req) { return true } var test = request(server).post('/') test.write(Buffer.from('000102', 'hex')) test.expect(200, 'buf:000102', done) }) it('should not invoke without a body', function (done) { var server = createServer({ type: accept }) function accept (req) { throw new Error('oops!') } request(server) .get('/') .expect(200, done) }) }) }) describe('with verify option', function () { it('should assert value is function', function () { assert.throws(createServer.bind(null, { verify: 'lol' }), /TypeError: option verify must be function/) }) it('should error from verify', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x00) throw new Error('no leading null') } }) var test = request(server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('000102', 'hex')) test.expect(403, 'no leading null', done) }) it('should allow custom codes', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] !== 0x00) return var err = new Error('no leading null') err.status = 400 throw err } }) var test = request(server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('000102', 'hex')) test.expect(400, 'no leading null', done) }) it('should allow pass-through', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x00) throw new Error('no leading null') } }) var test = request(server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('0102', 'hex')) test.expect(200, 'buf:0102', done) }) }) describe('charset', function () { before(function () { this.server = createServer() }) it('should ignore charset', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/octet-stream; charset=utf-8') test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) test.expect(200, 'buf:6e616d6520697320e8aeba', done) }) }) describe('encoding', function () { before(function () { this.server = createServer({ limit: '10kb' }) }) it('should parse without encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('6e616d653de8aeba', 'hex')) test.expect(200, 'buf:6e616d653de8aeba', done) }) it('should support identity encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'identity') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('6e616d653de8aeba', 'hex')) test.expect(200, 'buf:6e616d653de8aeba', done) }) it('should support gzip encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) test.expect(200, 'buf:6e616d653de8aeba', done) }) it('should support deflate encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'deflate') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('789ccb4bcc4db57db16e17001068042f', 'hex')) test.expect(200, 'buf:6e616d653de8aeba', done) }) it('should be case-insensitive', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'GZIP') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) test.expect(200, 'buf:6e616d653de8aeba', done) }) it('should fail on unknown encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'nulls') test.set('Content-Type', 'application/octet-stream') test.write(Buffer.from('000000000000', 'hex')) test.expect(415, 'unsupported content encoding "nulls"', done) }) }) }) function createServer (opts) { var _bodyParser = typeof opts !== 'function' ? bodyParser.raw(opts) : opts return http.createServer(function (req, res) { _bodyParser(req, res, function (err) { if (err) { res.statusCode = err.status || 500 res.end(err.message) return } if (Buffer.isBuffer(req.body)) { res.end('buf:' + req.body.toString('hex')) return } res.end(JSON.stringify(req.body)) }) }) } body-parser-1.19.0/test/support/000077500000000000000000000000001346047437500165415ustar00rootroot00000000000000body-parser-1.19.0/test/support/env.js000066400000000000000000000000541346047437500176660ustar00rootroot00000000000000 process.env.NO_DEPRECATION = 'body-parser' body-parser-1.19.0/test/text.js000066400000000000000000000327151346047437500163570ustar00rootroot00000000000000 var assert = require('assert') var Buffer = require('safe-buffer').Buffer var http = require('http') var request = require('supertest') var bodyParser = require('..') describe('bodyParser.text()', function () { before(function () { this.server = createServer() }) it('should parse text/plain', function (done) { request(this.server) .post('/') .set('Content-Type', 'text/plain') .send('user is tobi') .expect(200, '"user is tobi"', done) }) it('should 400 when invalid content-length', function (done) { var textParser = bodyParser.text() var server = createServer(function (req, res, next) { req.headers['content-length'] = '20' // bad length textParser(req, res, next) }) request(server) .post('/') .set('Content-Type', 'text/plain') .send('user') .expect(400, /content length/, done) }) it('should handle Content-Length: 0', function (done) { request(createServer({ limit: '1kb' })) .post('/') .set('Content-Type', 'text/plain') .set('Content-Length', '0') .expect(200, '""', done) }) it('should handle empty message-body', function (done) { request(createServer({ limit: '1kb' })) .post('/') .set('Content-Type', 'text/plain') .set('Transfer-Encoding', 'chunked') .send('') .expect(200, '""', done) }) it('should handle duplicated middleware', function (done) { var textParser = bodyParser.text() var server = createServer(function (req, res, next) { textParser(req, res, function (err) { if (err) return next(err) textParser(req, res, next) }) }) request(server) .post('/') .set('Content-Type', 'text/plain') .send('user is tobi') .expect(200, '"user is tobi"', done) }) describe('with defaultCharset option', function () { it('should change default charset', function (done) { var server = createServer({ defaultCharset: 'koi8-r' }) var test = request(server).post('/') test.set('Content-Type', 'text/plain') test.write(Buffer.from('6e616d6520697320cec5d4', 'hex')) test.expect(200, '"name is нет"', done) }) it('should honor content-type charset', function (done) { var server = createServer({ defaultCharset: 'koi8-r' }) var test = request(server).post('/') test.set('Content-Type', 'text/plain; charset=utf-8') test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) test.expect(200, '"name is 论"', done) }) }) describe('with limit option', function () { it('should 413 when over limit with Content-Length', function (done) { var buf = Buffer.alloc(1028, '.') request(createServer({ limit: '1kb' })) .post('/') .set('Content-Type', 'text/plain') .set('Content-Length', '1028') .send(buf.toString()) .expect(413, done) }) it('should 413 when over limit with chunked encoding', function (done) { var buf = Buffer.alloc(1028, '.') var server = createServer({ limit: '1kb' }) var test = request(server).post('/') test.set('Content-Type', 'text/plain') test.set('Transfer-Encoding', 'chunked') test.write(buf.toString()) test.expect(413, done) }) it('should accept number of bytes', function (done) { var buf = Buffer.alloc(1028, '.') request(createServer({ limit: 1024 })) .post('/') .set('Content-Type', 'text/plain') .send(buf.toString()) .expect(413, done) }) it('should not change when options altered', function (done) { var buf = Buffer.alloc(1028, '.') var options = { limit: '1kb' } var server = createServer(options) options.limit = '100kb' request(server) .post('/') .set('Content-Type', 'text/plain') .send(buf.toString()) .expect(413, done) }) it('should not hang response', function (done) { var buf = Buffer.alloc(10240, '.') var server = createServer({ limit: '8kb' }) var test = request(server).post('/') test.set('Content-Type', 'text/plain') test.write(buf) test.write(buf) test.write(buf) test.expect(413, done) }) }) describe('with inflate option', function () { describe('when false', function () { before(function () { this.server = createServer({ inflate: false }) }) it('should not accept content-encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'text/plain') test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex')) test.expect(415, 'content encoding unsupported', done) }) }) describe('when true', function () { before(function () { this.server = createServer({ inflate: true }) }) it('should accept content-encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'text/plain') test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex')) test.expect(200, '"name is 论"', done) }) }) }) describe('with type option', function () { describe('when "text/html"', function () { before(function () { this.server = createServer({ type: 'text/html' }) }) it('should parse for custom type', function (done) { request(this.server) .post('/') .set('Content-Type', 'text/html') .send('tobi') .expect(200, '"tobi"', done) }) it('should ignore standard type', function (done) { request(this.server) .post('/') .set('Content-Type', 'text/plain') .send('user is tobi') .expect(200, '{}', done) }) }) describe('when ["text/html", "text/plain"]', function () { before(function () { this.server = createServer({ type: ['text/html', 'text/plain'] }) }) it('should parse "text/html"', function (done) { request(this.server) .post('/') .set('Content-Type', 'text/html') .send('tobi') .expect(200, '"tobi"', done) }) it('should parse "text/plain"', function (done) { request(this.server) .post('/') .set('Content-Type', 'text/plain') .send('tobi') .expect(200, '"tobi"', done) }) it('should ignore "text/xml"', function (done) { request(this.server) .post('/') .set('Content-Type', 'text/xml') .send('tobi') .expect(200, '{}', done) }) }) describe('when a function', function () { it('should parse when truthy value returned', function (done) { var server = createServer({ type: accept }) function accept (req) { return req.headers['content-type'] === 'text/vnd.something' } request(server) .post('/') .set('Content-Type', 'text/vnd.something') .send('user is tobi') .expect(200, '"user is tobi"', done) }) it('should work without content-type', function (done) { var server = createServer({ type: accept }) function accept (req) { return true } var test = request(server).post('/') test.write('user is tobi') test.expect(200, '"user is tobi"', done) }) it('should not invoke without a body', function (done) { var server = createServer({ type: accept }) function accept (req) { throw new Error('oops!') } request(server) .get('/') .expect(200, done) }) }) }) describe('with verify option', function () { it('should assert value is function', function () { assert.throws(createServer.bind(null, { verify: 'lol' }), /TypeError: option verify must be function/) }) it('should error from verify', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x20) throw new Error('no leading space') } }) request(server) .post('/') .set('Content-Type', 'text/plain') .send(' user is tobi') .expect(403, 'no leading space', done) }) it('should allow custom codes', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] !== 0x20) return var err = new Error('no leading space') err.status = 400 throw err } }) request(server) .post('/') .set('Content-Type', 'text/plain') .send(' user is tobi') .expect(400, 'no leading space', done) }) it('should allow pass-through', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x20) throw new Error('no leading space') } }) request(server) .post('/') .set('Content-Type', 'text/plain') .send('user is tobi') .expect(200, '"user is tobi"', done) }) it('should 415 on unknown charset prior to verify', function (done) { var server = createServer({ verify: function (req, res, buf) { throw new Error('unexpected verify call') } }) var test = request(server).post('/') test.set('Content-Type', 'text/plain; charset=x-bogus') test.write(Buffer.from('00000000', 'hex')) test.expect(415, 'unsupported charset "X-BOGUS"', done) }) }) describe('charset', function () { before(function () { this.server = createServer() }) it('should parse utf-8', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'text/plain; charset=utf-8') test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) test.expect(200, '"name is 论"', done) }) it('should parse codepage charsets', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'text/plain; charset=koi8-r') test.write(Buffer.from('6e616d6520697320cec5d4', 'hex')) test.expect(200, '"name is нет"', done) }) it('should parse when content-length != char length', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'text/plain; charset=utf-8') test.set('Content-Length', '11') test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) test.expect(200, '"name is 论"', done) }) it('should default to utf-8', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'text/plain') test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) test.expect(200, '"name is 论"', done) }) it('should 415 on unknown charset', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'text/plain; charset=x-bogus') test.write(Buffer.from('00000000', 'hex')) test.expect(415, 'unsupported charset "X-BOGUS"', done) }) }) describe('encoding', function () { before(function () { this.server = createServer({ limit: '10kb' }) }) it('should parse without encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'text/plain') test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) test.expect(200, '"name is 论"', done) }) it('should support identity encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'identity') test.set('Content-Type', 'text/plain') test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) test.expect(200, '"name is 论"', done) }) it('should support gzip encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'text/plain') test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex')) test.expect(200, '"name is 论"', done) }) it('should support deflate encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'deflate') test.set('Content-Type', 'text/plain') test.write(Buffer.from('789ccb4bcc4d55c82c5678b16e17001a6f050e', 'hex')) test.expect(200, '"name is 论"', done) }) it('should be case-insensitive', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'GZIP') test.set('Content-Type', 'text/plain') test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex')) test.expect(200, '"name is 论"', done) }) it('should fail on unknown encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'nulls') test.set('Content-Type', 'text/plain') test.write(Buffer.from('000000000000', 'hex')) test.expect(415, 'unsupported content encoding "nulls"', done) }) }) }) function createServer (opts) { var _bodyParser = typeof opts !== 'function' ? bodyParser.text(opts) : opts return http.createServer(function (req, res) { _bodyParser(req, res, function (err) { res.statusCode = err ? (err.status || 500) : 200 res.end(err ? err.message : JSON.stringify(req.body)) }) }) } body-parser-1.19.0/test/urlencoded.js000066400000000000000000000577241346047437500175260ustar00rootroot00000000000000 var assert = require('assert') var Buffer = require('safe-buffer').Buffer var http = require('http') var request = require('supertest') var bodyParser = require('..') describe('bodyParser.urlencoded()', function () { before(function () { this.server = createServer() }) it('should parse x-www-form-urlencoded', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) it('should 400 when invalid content-length', function (done) { var urlencodedParser = bodyParser.urlencoded() var server = createServer(function (req, res, next) { req.headers['content-length'] = '20' // bad length urlencodedParser(req, res, next) }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('str=') .expect(400, /content length/, done) }) it('should handle Content-Length: 0', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .set('Content-Length', '0') .send('') .expect(200, '{}', done) }) it('should handle empty message-body', function (done) { request(createServer({ limit: '1kb' })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .set('Transfer-Encoding', 'chunked') .send('') .expect(200, '{}', done) }) it('should handle duplicated middleware', function (done) { var urlencodedParser = bodyParser.urlencoded() var server = createServer(function (req, res, next) { urlencodedParser(req, res, function (err) { if (err) return next(err) urlencodedParser(req, res, next) }) }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) it('should parse extended syntax', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user[name][first]=Tobi') .expect(200, '{"user":{"name":{"first":"Tobi"}}}', done) }) describe('with extended option', function () { describe('when false', function () { before(function () { this.server = createServer({ extended: false }) }) it('should not parse extended syntax', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user[name][first]=Tobi') .expect(200, '{"user[name][first]":"Tobi"}', done) }) it('should parse multiple key instances', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=Tobi&user=Loki') .expect(200, '{"user":["Tobi","Loki"]}', done) }) }) describe('when true', function () { before(function () { this.server = createServer({ extended: true }) }) it('should parse multiple key instances', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=Tobi&user=Loki') .expect(200, '{"user":["Tobi","Loki"]}', done) }) it('should parse extended syntax', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user[name][first]=Tobi') .expect(200, '{"user":{"name":{"first":"Tobi"}}}', done) }) it('should parse parameters with dots', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user.name=Tobi') .expect(200, '{"user.name":"Tobi"}', done) }) it('should parse fully-encoded extended syntax', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user%5Bname%5D%5Bfirst%5D=Tobi') .expect(200, '{"user":{"name":{"first":"Tobi"}}}', done) }) it('should parse array index notation', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('foo[0]=bar&foo[1]=baz') .expect(200, '{"foo":["bar","baz"]}', done) }) it('should parse array index notation with large array', function (done) { var str = 'f[0]=0' for (var i = 1; i < 500; i++) { str += '&f[' + i + ']=' + i.toString(16) } request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(str) .expect(function (res) { var obj = JSON.parse(res.text) assert.strictEqual(Object.keys(obj).length, 1) assert.strictEqual(Array.isArray(obj.f), true) assert.strictEqual(obj.f.length, 500) }) .expect(200, done) }) it('should parse array of objects syntax', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('foo[0][bar]=baz&foo[0][fizz]=buzz&foo[]=done!') .expect(200, '{"foo":[{"bar":"baz","fizz":"buzz"},"done!"]}', done) }) it('should parse deep object', function (done) { var str = 'foo' for (var i = 0; i < 500; i++) { str += '[p]' } str += '=bar' request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(str) .expect(function (res) { var obj = JSON.parse(res.text) assert.strictEqual(Object.keys(obj).length, 1) assert.strictEqual(typeof obj.foo, 'object') var depth = 0 var ref = obj.foo while ((ref = ref.p)) { depth++ } assert.strictEqual(depth, 500) }) .expect(200, done) }) }) }) describe('with inflate option', function () { describe('when false', function () { before(function () { this.server = createServer({ inflate: false }) }) it('should not accept content-encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) test.expect(415, 'content encoding unsupported', done) }) }) describe('when true', function () { before(function () { this.server = createServer({ inflate: true }) }) it('should accept content-encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) test.expect(200, '{"name":"论"}', done) }) }) }) describe('with limit option', function () { it('should 413 when over limit with Content-Length', function (done) { var buf = Buffer.alloc(1024, '.') request(createServer({ limit: '1kb' })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .set('Content-Length', '1028') .send('str=' + buf.toString()) .expect(413, done) }) it('should 413 when over limit with chunked encoding', function (done) { var buf = Buffer.alloc(1024, '.') var server = createServer({ limit: '1kb' }) var test = request(server).post('/') test.set('Content-Type', 'application/x-www-form-urlencoded') test.set('Transfer-Encoding', 'chunked') test.write('str=') test.write(buf.toString()) test.expect(413, done) }) it('should accept number of bytes', function (done) { var buf = Buffer.alloc(1024, '.') request(createServer({ limit: 1024 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('str=' + buf.toString()) .expect(413, done) }) it('should not change when options altered', function (done) { var buf = Buffer.alloc(1024, '.') var options = { limit: '1kb' } var server = createServer(options) options.limit = '100kb' request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('str=' + buf.toString()) .expect(413, done) }) it('should not hang response', function (done) { var buf = Buffer.alloc(10240, '.') var server = createServer({ limit: '8kb' }) var test = request(server).post('/') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(buf) test.write(buf) test.write(buf) test.expect(413, done) }) }) describe('with parameterLimit option', function () { describe('with extended: false', function () { it('should reject 0', function () { assert.throws(createServer.bind(null, { extended: false, parameterLimit: 0 }), /TypeError: option parameterLimit must be a positive number/) }) it('should reject string', function () { assert.throws(createServer.bind(null, { extended: false, parameterLimit: 'beep' }), /TypeError: option parameterLimit must be a positive number/) }) it('should 413 if over limit', function (done) { request(createServer({ extended: false, parameterLimit: 10 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(11)) .expect(413, /too many parameters/, done) }) it('should error with type = "parameters.too.many"', function (done) { request(createServer({ extended: false, parameterLimit: 10 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .set('X-Error-Property', 'type') .send(createManyParams(11)) .expect(413, 'parameters.too.many', done) }) it('should work when at the limit', function (done) { request(createServer({ extended: false, parameterLimit: 10 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(10)) .expect(expectKeyCount(10)) .expect(200, done) }) it('should work if number is floating point', function (done) { request(createServer({ extended: false, parameterLimit: 10.1 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(11)) .expect(413, /too many parameters/, done) }) it('should work with large limit', function (done) { request(createServer({ extended: false, parameterLimit: 5000 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(5000)) .expect(expectKeyCount(5000)) .expect(200, done) }) it('should work with Infinity limit', function (done) { request(createServer({ extended: false, parameterLimit: Infinity })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(10000)) .expect(expectKeyCount(10000)) .expect(200, done) }) }) describe('with extended: true', function () { it('should reject 0', function () { assert.throws(createServer.bind(null, { extended: true, parameterLimit: 0 }), /TypeError: option parameterLimit must be a positive number/) }) it('should reject string', function () { assert.throws(createServer.bind(null, { extended: true, parameterLimit: 'beep' }), /TypeError: option parameterLimit must be a positive number/) }) it('should 413 if over limit', function (done) { request(createServer({ extended: true, parameterLimit: 10 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(11)) .expect(413, /too many parameters/, done) }) it('should error with type = "parameters.too.many"', function (done) { request(createServer({ extended: true, parameterLimit: 10 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .set('X-Error-Property', 'type') .send(createManyParams(11)) .expect(413, 'parameters.too.many', done) }) it('should work when at the limit', function (done) { request(createServer({ extended: true, parameterLimit: 10 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(10)) .expect(expectKeyCount(10)) .expect(200, done) }) it('should work if number is floating point', function (done) { request(createServer({ extended: true, parameterLimit: 10.1 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(11)) .expect(413, /too many parameters/, done) }) it('should work with large limit', function (done) { request(createServer({ extended: true, parameterLimit: 5000 })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(5000)) .expect(expectKeyCount(5000)) .expect(200, done) }) it('should work with Infinity limit', function (done) { request(createServer({ extended: true, parameterLimit: Infinity })) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(createManyParams(10000)) .expect(expectKeyCount(10000)) .expect(200, done) }) }) }) describe('with type option', function () { describe('when "application/vnd.x-www-form-urlencoded"', function () { before(function () { this.server = createServer({ type: 'application/vnd.x-www-form-urlencoded' }) }) it('should parse for custom type', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/vnd.x-www-form-urlencoded') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) it('should ignore standard type', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=tobi') .expect(200, '{}', done) }) }) describe('when ["urlencoded", "application/x-pairs"]', function () { before(function () { this.server = createServer({ type: ['urlencoded', 'application/x-pairs'] }) }) it('should parse "application/x-www-form-urlencoded"', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) it('should parse "application/x-pairs"', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-pairs') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) it('should ignore application/x-foo', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-foo') .send('user=tobi') .expect(200, '{}', done) }) }) describe('when a function', function () { it('should parse when truthy value returned', function (done) { var server = createServer({ type: accept }) function accept (req) { return req.headers['content-type'] === 'application/vnd.something' } request(server) .post('/') .set('Content-Type', 'application/vnd.something') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) it('should work without content-type', function (done) { var server = createServer({ type: accept }) function accept (req) { return true } var test = request(server).post('/') test.write('user=tobi') test.expect(200, '{"user":"tobi"}', done) }) it('should not invoke without a body', function (done) { var server = createServer({ type: accept }) function accept (req) { throw new Error('oops!') } request(server) .get('/') .expect(200, done) }) }) }) describe('with verify option', function () { it('should assert value if function', function () { assert.throws(createServer.bind(null, { verify: 'lol' }), /TypeError: option verify must be function/) }) it('should error from verify', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x20) throw new Error('no leading space') } }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(' user=tobi') .expect(403, 'no leading space', done) }) it('should error with type = "entity.verify.failed"', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x20) throw new Error('no leading space') } }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .set('X-Error-Property', 'type') .send(' user=tobi') .expect(403, 'entity.verify.failed', done) }) it('should allow custom codes', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] !== 0x20) return var err = new Error('no leading space') err.status = 400 throw err } }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send(' user=tobi') .expect(400, 'no leading space', done) }) it('should allow custom type', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] !== 0x20) return var err = new Error('no leading space') err.type = 'foo.bar' throw err } }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .set('X-Error-Property', 'type') .send(' user=tobi') .expect(403, 'foo.bar', done) }) it('should allow pass-through', function (done) { var server = createServer({ verify: function (req, res, buf) { if (buf[0] === 0x5b) throw new Error('no arrays') } }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') .send('user=tobi') .expect(200, '{"user":"tobi"}', done) }) it('should 415 on unknown charset prior to verify', function (done) { var server = createServer({ verify: function (req, res, buf) { throw new Error('unexpected verify call') } }) var test = request(server).post('/') test.set('Content-Type', 'application/x-www-form-urlencoded; charset=x-bogus') test.write(Buffer.from('00000000', 'hex')) test.expect(415, 'unsupported charset "X-BOGUS"', done) }) }) describe('charset', function () { before(function () { this.server = createServer() }) it('should parse utf-8', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8') test.write(Buffer.from('6e616d653de8aeba', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should parse when content-length != char length', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8') test.set('Content-Length', '7') test.write(Buffer.from('746573743dc3a5', 'hex')) test.expect(200, '{"test":"å"}', done) }) it('should default to utf-8', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('6e616d653de8aeba', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should fail on unknown charset', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/x-www-form-urlencoded; charset=koi8-r') test.write(Buffer.from('6e616d653dcec5d4', 'hex')) test.expect(415, 'unsupported charset "KOI8-R"', done) }) }) describe('encoding', function () { before(function () { this.server = createServer({ limit: '10kb' }) }) it('should parse without encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('6e616d653de8aeba', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should support identity encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'identity') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('6e616d653de8aeba', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should support gzip encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'gzip') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should support deflate encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'deflate') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('789ccb4bcc4db57db16e17001068042f', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should be case-insensitive', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'GZIP') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) test.expect(200, '{"name":"论"}', done) }) it('should fail on unknown encoding', function (done) { var test = request(this.server).post('/') test.set('Content-Encoding', 'nulls') test.set('Content-Type', 'application/x-www-form-urlencoded') test.write(Buffer.from('000000000000', 'hex')) test.expect(415, 'unsupported content encoding "nulls"', done) }) }) }) function createManyParams (count) { var str = '' if (count === 0) { return str } str += '0=0' for (var i = 1; i < count; i++) { var n = i.toString(36) str += '&' + n + '=' + n } return str } function createServer (opts) { var _bodyParser = typeof opts !== 'function' ? bodyParser.urlencoded(opts) : opts return http.createServer(function (req, res) { _bodyParser(req, res, function (err) { if (err) { res.statusCode = err.status || 500 res.end(err[req.headers['x-error-property'] || 'message']) } else { res.statusCode = 200 res.end(JSON.stringify(req.body)) } }) }) } function expectKeyCount (count) { return function (res) { assert.strictEqual(Object.keys(JSON.parse(res.text)).length, count) } }