3 * Copyright(c) 2014 Jonathan Ong
4 * Copyright(c) 2014 Douglas Christopher Wilson
12 var bytes = require('bytes')
13 var read = require('../read')
14 var typer = require('media-typer')
15 var typeis = require('type-is')
24 * RegExp to match the first non-space in a string.
26 * Allowed whitespace is defined in RFC 7159:
30 * %x09 / ; Horizontal tab
31 * %x0A / ; Line feed or New line
32 * %x0D ) ; Carriage return
35 var firstcharRegExp = /^[\x20\x09\x0a\x0d]*(.)/
38 * Create a middleware to parse JSON bodies.
40 * @param {object} [options]
45 function json(options) {
46 options = options || {}
48 var limit = typeof options.limit !== 'number'
49 ? bytes(options.limit || '100kb')
51 var inflate = options.inflate !== false
52 var reviver = options.reviver
53 var strict = options.strict !== false
54 var type = options.type || 'json'
55 var verify = options.verify || false
57 if (verify !== false && typeof verify !== 'function') {
58 throw new TypeError('option verify must be function')
61 function parse(body) {
62 if (body.length === 0) {
63 // special-case empty json body, as it's a common client-side mistake
64 // TODO: maybe make this configurable or part of "strict" option
69 var first = firstchar(body)
71 if (first !== '{' && first !== '[') {
72 throw new Error('invalid json')
76 return JSON.parse(body, reviver)
79 return function jsonParser(req, res, next) {
80 if (req._body) return next()
81 req.body = req.body || {}
83 if (!typeis(req, type)) return next()
86 var charset = (typer.parse(req).parameters.charset || 'utf-8').toLowerCase()
87 if (charset.substr(0, 4) !== 'utf-') {
88 var err = new Error('unsupported charset "' + charset.toUpperCase() + '"')
96 read(req, res, next, parse, {
106 * Get the first non-whitespace character in a string.
108 * @param {string} str
114 function firstchar(str) {
115 var match = firstcharRegExp.exec(str)
116 return match ? match[1] : ''