Browse Source

Do not use it for `json()` either

master
Leo Lamprecht 8 years ago
parent
commit
34eb7cd0cd
No known key found for this signature in database GPG Key ID: B08517883D5E0E10
  1. 77
      lib/server.js
  2. 1
      package.json
  3. 56
      test/index.js

77
lib/server.js

@ -5,26 +5,25 @@ const server = require('http').Server
const getRawBody = require('raw-body')
const typer = require('media-typer')
const isStream = require('isstream')
const Q = require('q')
const DEV = process.env.NODE_ENV === 'development'
const TESTING = process.env.NODE_ENV === 'test'
const serve = fn => server((req, res) => {
run(req, res, fn)
})
const serve = fn => server(Q.async(function * (req, res) {
yield exports.run(req, res, fn)
}))
module.exports = exports = serve
exports.json = json
exports.send = send
exports.sendError = sendError
exports.createError = createError
async function run(req, res, fn) {
exports.run = Q.async(function * (req, res, fn) {
try {
const val = await fn(req, res)
const val = yield fn(req, res)
// Return 204 No Content if value is null
if (val === null) {
send(res, 204, null)
}
@ -34,55 +33,47 @@ async function run(req, res, fn) {
send(res, res.statusCode || 200, val)
}
} catch (err) {
await sendError(req, res, err)
}
}
exports.run = (req, res, fn) => {
fn(req, res).then(val => {
// Return 204 No Content if value is null
if (val === null) {
send(res, 204, null)
}
// Return a undefined-null value -> send
if (undefined !== val) {
send(res, res.statusCode || 200, val)
}
}).catch(err => {
sendError(req, res, err)
})
}
}
})
// maps requests to buffered raw bodies so that
// multiple calls to `json` work as expected
const rawBodyMap = new WeakMap()
async function json(req, {limit = '1mb'} = {}) {
const returnJSON = (resolve, reject, str) => {
try {
const type = req.headers['content-type']
const length = req.headers['content-length']
const encoding = typer.parse(type).parameters.charset
let str = rawBodyMap.get(req)
if (!str) {
str = await getRawBody(req, {limit, length, encoding})
rawBodyMap.set(req, str)
}
try {
return JSON.parse(str)
} catch (err) {
throw createError(400, 'Invalid JSON', err)
}
resolve(JSON.parse(str))
} catch (err) {
reject(createError(400, 'Invalid JSON', err))
}
}
exports.json = (req, {limit = '1mb'} = {}) => new Promise((resolve, reject) => {
const type = req.headers['content-type']
const length = req.headers['content-length']
const encoding = typer.parse(type).parameters.charset
let str = rawBodyMap.get(req)
if (str) {
returnJSON(resolve, reject, str)
return
}
getRawBody(req, {limit, length, encoding}).then(buf => {
str = buf
rawBodyMap.set(req, str)
returnJSON(resolve, reject, str)
}).catch(err => {
if (err.type === 'entity.too.large') {
throw createError(413, `Body exceeded ${limit} limit`, err)
} else {
throw createError(400, 'Invalid body', err)
}
}
}
})
})
function send(res, code, obj = null) {
res.statusCode = code

1
package.json

@ -70,6 +70,7 @@
"isstream": "0.1.2",
"media-typer": "0.3.0",
"node-version": "1.0.0",
"q": "1.4.1",
"raw-body": "2.2.0",
"update-notifier": "1.0.3"
}

56
test/index.js

@ -318,30 +318,22 @@ test('json limit (below)', async t => {
test('json limit (over)', async t => {
const fn = async (req, res) => {
const body = await json(req, {
limit: 3
})
let body
try {
body = await json(req, {
limit: 3
})
} catch (err) {
t.deepEqual(err.statusCode, 413)
}
send(res, 200, {
response: body.some.cool
})
}
const url = await getUrl(fn)
try {
await request(url, {
method: 'POST',
body: {
some: {
cool: 'json'
}
},
json: true
})
} catch (err) {
t.deepEqual(err.statusCode, 413)
}
await getUrl(fn)
})
test('json circular', async t => {
@ -382,28 +374,20 @@ test('no async', async t => {
test('limit included in error', async t => {
const fn = async (req, res) => {
const body = await json(req, {
limit: 3
})
let body
try {
body = await json(req, {
limit: 3
})
} catch (err) {
t.truthy(/exceeded 3 limit/.test(err.message))
}
send(res, 200, {
response: body.some.cool
})
}
const url = await getUrl(fn)
try {
await request(url, {
method: 'POST',
body: {
some: {
cool: 'json'
}
},
json: true
})
} catch (err) {
t.truthy(/exceeded 3 limit/.test(err.message))
}
await getUrl(fn)
})

Loading…
Cancel
Save