Skip to content

Commit

Permalink
Add option to limit incoming form size
Browse files Browse the repository at this point in the history
  • Loading branch information
jsumners committed Jan 10, 2018
1 parent c708c2f commit c9c49ac
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 33 deletions.
8 changes: 8 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ The sent reply would be the object:
}
```

## Options

The plugin accepts an options object with the following properties:

+ `bodyLimit` (Default: `1048576`): the maximum amount of bytes to process
before returning an error. If the limit is exceeded, a `500` error will be
returned immediately.

## License

[MIT License](http://jsumners.mit-license.org/)
35 changes: 26 additions & 9 deletions formbody.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,37 @@
const fp = require('fastify-plugin')
const qs = require('qs')

const internals = {}
internals.contentParser = function (req, done) {
let body = ''
req.on('error', done)
req.on('data', (data) => { body = body + data })
req.on('end', () => { return done(null, qs.parse(body)) })
const DEFAULT_BODY_LIMIT = 1024 * 1024 // 1 MiB
const defaults = {
bodyLimit: DEFAULT_BODY_LIMIT
}

function formBodyPlugin (fastify, options, next) {
fastify.addContentTypeParser('application/x-www-form-urlencoded', internals.contentParser)
const opts = Object.assign({}, defaults, options || {})

function contentParser (req, done) {
const bodyLimit = opts.bodyLimit
const tooLargeError = Error('Form data exceeds allowed limit: ' + bodyLimit)
const contentLength = (req.headers['content-length'])
? Number.parseInt(req.headers['content-length'], 10)
: null
if (contentLength > bodyLimit) return done(tooLargeError)

let body = ''
req.on('error', done)
req.on('data', (data) => {
body = body + data
if (body.length > bodyLimit) {
return done(tooLargeError)
}
})
req.on('end', () => { return done(null, qs.parse(body)) })
}

fastify.addContentTypeParser('application/x-www-form-urlencoded', contentParser)
next()
}

module.exports = fp(formBodyPlugin, {
fastify: '>=0.37.0'
fastify: '>=0.38.0'
})
module.exports.internals = internals
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
},
"homepage": "https://github.com/fastify/fastify-formbody#readme",
"devDependencies": {
"fastify": "^0.37.0",
"fastify": "^0.38.0",
"request": "^2.81.0",
"snazzy": "^7.0.0",
"standard": "^10.0.3",
Expand Down
67 changes: 44 additions & 23 deletions test/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,61 @@

const tap = require('tap')
const test = tap.test
const fastify = require('fastify')()
const Fastify = require('fastify')
const request = require('request')
const plugin = require('../')

test('successful route', (t) => {
t.plan(1)
try {
fastify.post('/test1', (req, res) => {
test('succes route succeeds', (t) => {
t.plan(3)
const fastify = Fastify()

fastify
.register(plugin)
.post('/test1', (req, res) => {
res.send(Object.assign({}, req.body, {message: 'done'}))
})
t.pass()
} catch (e) {
t.fail(e.message)
}
})

fastify.register(plugin, (err) => { if (err) tap.error(err) })

fastify.listen(0, (err) => {
if (err) tap.error(err)
fastify.server.unref()

const reqOpts = {
method: 'POST',
baseUrl: 'http://localhost:' + fastify.server.address().port
}
const req = request.defaults(reqOpts)
fastify.listen(0, (err) => {
if (err) tap.error(err)
fastify.server.unref()

test('success route succeeds', (t) => {
t.plan(3)
const reqOpts = {
method: 'POST',
baseUrl: 'http://localhost:' + fastify.server.address().port
}
const req = request.defaults(reqOpts)
req({uri: '/test1', form: {foo: 'foo'}}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 200)
t.deepEqual(JSON.parse(body), {foo: 'foo', message: 'done'})
})
})
})

test('cannot exceed body limit', (t) => {
t.plan(3)
const fastify = Fastify()

fastify
.register(plugin, {bodyLimit: 10})
.post('/limited', (req, res) => {
res.send(Object.assign({}, req.body, {message: 'done'}))
})

fastify.listen(0, (err) => {
if (err) tap.error(err)
fastify.server.unref()

const reqOpts = {
method: 'POST',
baseUrl: 'http://localhost:' + fastify.server.address().port
}
const req = request.defaults(reqOpts)
const payload = require('crypto').randomBytes(128).toString('hex')
req({uri: '/limited', form: {foo: payload}}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 500)
t.is(JSON.parse(body).message, 'Form data exceeds allowed limit: 10')
})
})
})

0 comments on commit c9c49ac

Please sign in to comment.