| /*! | 
|  * 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() | 
|   } | 
| } |