Blame view

node_modules/body-parser/lib/read.js 3.68 KB
cf76164e6   Ting Chan   20190709
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  /*!
   * 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 (err, body) {
      if (err) {
        // echo back charset
        if (err.type === 'encoding.unsupported') {
          err = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
            charset: encoding.toLowerCase(),
            type: 'charset.unsupported'
          })
        }
  
        // read off entire request
        stream.resume()
        onFinished(req, function onfinished () {
          next(createError(400, err))
        })
        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
  }