123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /*!
- * body-parser
- * Copyright(c) 2014-2015 Douglas Christopher Wilson
- * MIT Licensed
- */
-
- 'use strict'
-
- /**
- * Module dependencies.
- * @private
- */
-
- var createError = require('http-errors')
- var destroy = require('destroy')
- var getBody = require('raw-body')
- var iconv = require('iconv-lite')
- var onFinished = require('on-finished')
- var unpipe = require('unpipe')
- 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)
- }
-
- // unpipe from stream and destroy
- if (stream !== req) {
- unpipe(req)
- destroy(stream, true)
- }
-
- // read off entire request
- dump(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
- }
-
- /**
- * Dump the contents of a request.
- *
- * @param {object} req
- * @param {function} callback
- * @api private
- */
-
- function dump (req, callback) {
- if (onFinished.isFinished(req)) {
- callback(null)
- } else {
- onFinished(req, callback)
- req.resume()
- }
- }
|