twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

read.js (3894B)


      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 
     14 var createError = require('http-errors')
     15 var getBody = require('raw-body')
     16 var iconv = require('iconv-lite')
     17 var onFinished = require('on-finished')
     18 var zlib = require('zlib')
     19 
     20 /**
     21  * Module exports.
     22  */
     23 
     24 module.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  * @private
     36  */
     37 
     38 function 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
     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       type: 'charset.unsupported'
     72     }))
     73   }
     74 
     75   // read body
     76   debug('read body')
     77   getBody(stream, opts, function (error, body) {
     78     if (error) {
     79       var _error
     80 
     81       if (error.type === 'encoding.unsupported') {
     82         // echo back charset
     83         _error = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
     84           charset: encoding.toLowerCase(),
     85           type: 'charset.unsupported'
     86         })
     87       } else {
     88         // set status code on error
     89         _error = createError(400, error)
     90       }
     91 
     92       // read off entire request
     93       stream.resume()
     94       onFinished(req, function onfinished () {
     95         next(createError(400, _error))
     96       })
     97       return
     98     }
     99 
    100     // verify
    101     if (verify) {
    102       try {
    103         debug('verify body')
    104         verify(req, res, body, encoding)
    105       } catch (err) {
    106         next(createError(403, err, {
    107           body: body,
    108           type: err.type || 'entity.verify.failed'
    109         }))
    110         return
    111       }
    112     }
    113 
    114     // parse
    115     var str = body
    116     try {
    117       debug('parse body')
    118       str = typeof body !== 'string' && encoding !== null
    119         ? iconv.decode(body, encoding)
    120         : body
    121       req.body = parse(str)
    122     } catch (err) {
    123       next(createError(400, err, {
    124         body: str,
    125         type: err.type || 'entity.parse.failed'
    126       }))
    127       return
    128     }
    129 
    130     next()
    131   })
    132 }
    133 
    134 /**
    135  * Get the content stream of the request.
    136  *
    137  * @param {object} req
    138  * @param {function} debug
    139  * @param {boolean} [inflate=true]
    140  * @return {object}
    141  * @api private
    142  */
    143 
    144 function contentstream (req, debug, inflate) {
    145   var encoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
    146   var length = req.headers['content-length']
    147   var stream
    148 
    149   debug('content-encoding "%s"', encoding)
    150 
    151   if (inflate === false && encoding !== 'identity') {
    152     throw createError(415, 'content encoding unsupported', {
    153       encoding: encoding,
    154       type: 'encoding.unsupported'
    155     })
    156   }
    157 
    158   switch (encoding) {
    159     case 'deflate':
    160       stream = zlib.createInflate()
    161       debug('inflate body')
    162       req.pipe(stream)
    163       break
    164     case 'gzip':
    165       stream = zlib.createGunzip()
    166       debug('gunzip body')
    167       req.pipe(stream)
    168       break
    169     case 'identity':
    170       stream = req
    171       stream.length = length
    172       break
    173     default:
    174       throw createError(415, 'unsupported content encoding "' + encoding + '"', {
    175         encoding: encoding,
    176         type: 'encoding.unsupported'
    177       })
    178   }
    179 
    180   return stream
    181 }