arnaucube
arnaucube/thoughtsPublic Self-hosted repository
thoughts/node_modules/body-parser/lib/read.js
node_modules/body-parser/lib/read.jsRaw
  1/*!
  2 * body-parser
  3 * Copyright(c) 2014-2015 Douglas Christopher Wilson
  4 * MIT Licensed
  5 */
  6
  7'use strict'
  8
  9/**
 10 * Module dependencies.
 11 * @private
 12 */
 13
 14var createError = require('http-errors')
 15var getBody = require('raw-body')
 16var iconv = require('iconv-lite')
 17var onFinished = require('on-finished')
 18var zlib = require('zlib')
 19
 20/**
 21 * Module exports.
 22 */
 23
 24module.exports = read
 25
 26/**
 27 * Read a request into a buffer and parse.
 28 *
 29 * @param {object} req
 30 * @param {object} res
 31 * @param {function} next
 32 * @param {function} parse
 33 * @param {function} debug
 34 * @param {object} [options]
 35 * @api private
 36 */
 37
 38function read (req, res, next, parse, debug, options) {
 39  var length
 40  var opts = options || {}
 41  var stream
 42
 43  // flag as parsed
 44  req._body = true
 45
 46  // read options
 47  var encoding = opts.encoding !== null
 48    ? opts.encoding || 'utf-8'
 49    : null
 50  var verify = opts.verify
 51
 52  try {
 53    // get the content stream
 54    stream = contentstream(req, debug, opts.inflate)
 55    length = stream.length
 56    stream.length = undefined
 57  } catch (err) {
 58    return next(err)
 59  }
 60
 61  // set raw-body options
 62  opts.length = length
 63  opts.encoding = verify
 64    ? null
 65    : encoding
 66
 67  // assert charset is supported
 68  if (opts.encoding === null && encoding !== null && !iconv.encodingExists(encoding)) {
 69    return next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
 70      charset: encoding.toLowerCase()
 71    }))
 72  }
 73
 74  // read body
 75  debug('read body')
 76  getBody(stream, opts, function (err, body) {
 77    if (err) {
 78      // default to 400
 79      setErrorStatus(err, 400)
 80
 81      // echo back charset
 82      if (err.type === 'encoding.unsupported') {
 83        err = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
 84          charset: encoding.toLowerCase()
 85        })
 86      }
 87
 88      // read off entire request
 89      stream.resume()
 90      onFinished(req, function onfinished () {
 91        next(err)
 92      })
 93      return
 94    }
 95
 96    // verify
 97    if (verify) {
 98      try {
 99        debug('verify body')
100        verify(req, res, body, encoding)
101      } catch (err) {
102        // default to 403
103        setErrorStatus(err, 403)
104        next(err)
105        return
106      }
107    }
108
109    // parse
110    var str
111    try {
112      debug('parse body')
113      str = typeof body !== 'string' && encoding !== null
114        ? iconv.decode(body, encoding)
115        : body
116      req.body = parse(str)
117    } catch (err) {
118      err.body = str === undefined
119        ? body
120        : str
121
122      // default to 400
123      setErrorStatus(err, 400)
124
125      next(err)
126      return
127    }
128
129    next()
130  })
131}
132
133/**
134 * Get the content stream of the request.
135 *
136 * @param {object} req
137 * @param {function} debug
138 * @param {boolean} [inflate=true]
139 * @return {object}
140 * @api private
141 */
142
143function contentstream (req, debug, inflate) {
144  var encoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
145  var length = req.headers['content-length']
146  var stream
147
148  debug('content-encoding "%s"', encoding)
149
150  if (inflate === false && encoding !== 'identity') {
151    throw createError(415, 'content encoding unsupported')
152  }
153
154  switch (encoding) {
155    case 'deflate':
156      stream = zlib.createInflate()
157      debug('inflate body')
158      req.pipe(stream)
159      break
160    case 'gzip':
161      stream = zlib.createGunzip()
162      debug('gunzip body')
163      req.pipe(stream)
164      break
165    case 'identity':
166      stream = req
167      stream.length = length
168      break
169    default:
170      throw createError(415, 'unsupported content encoding "' + encoding + '"', {
171        encoding: encoding
172      })
173  }
174
175  return stream
176}
177
178/**
179 * Set a status on an error object, if ones does not exist
180 * @private
181 */
182
183function setErrorStatus (error, status) {
184  if (!error.status && !error.statusCode) {
185    error.status = status
186    error.statusCode = status
187  }
188}