-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
plugin.js
113 lines (97 loc) · 3.13 KB
/
plugin.js
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
'use strict'
const fp = require('fastify-plugin')
const getRawBody = require('raw-body')
const secureJson = require('secure-json-parse')
const kRawBodyHook = Symbol('fastify-raw-body:rawBodyHook')
function rawBody (fastify, opts, next) {
if (fastify[kRawBodyHook] === true) {
next(new Error('Cannot register fastify-raw-body twice'))
return
}
const { field, encoding, global, runFirst, routes, jsonContentTypes } = Object.assign({
field: 'rawBody',
encoding: 'utf8',
global: true,
runFirst: false,
routes: [],
jsonContentTypes: ['application/json']
}, opts)
if (encoding === false) {
fastify.addContentTypeParser(jsonContentTypes,
{ parseAs: 'buffer' },
almostDefaultJsonParser)
}
fastify.addHook('onRoute', (routeOptions) => {
const wantSkip = routeOptions.method === 'GET' || (routeOptions.config && routeOptions.config.rawBody === false)
if (
(global && !wantSkip && !routes.length) ||
(routeOptions.config && routeOptions.config.rawBody === true) ||
routes.includes(routeOptions.path)
) {
if (!routeOptions.preParsing) {
routeOptions.preParsing = [preparsingRawBody]
} else if (Array.isArray(routeOptions.preParsing)) {
if (runFirst) {
routeOptions.preParsing.unshift(preparsingRawBody)
} else {
routeOptions.preParsing.push(preparsingRawBody)
}
} else {
if (runFirst) {
routeOptions.preParsing = [preparsingRawBody, routeOptions.preParsing]
} else {
routeOptions.preParsing = [routeOptions.preParsing, preparsingRawBody]
}
}
}
})
fastify[kRawBodyHook] = true
next()
function preparsingRawBody (request, reply, payload, done) {
const applyLimit = request.routeOptions.bodyLimit
getRawBody(runFirst ? request.raw : payload, {
length: null, // avoid content lenght check: fastify will do it
limit: applyLimit, // limit to avoid memory leak or DoS
encoding
}, function (err, string) {
if (err) {
/**
* the error is managed by fastify server
* so the request object will not have any
* `body` parsed.
*
* The preparsingRawBody decorates the request
* meanwhile the `payload` is processed by
* the fastify server.
*/
return
}
request[field] = string
})
done(null, payload)
}
function almostDefaultJsonParser (req, body, done) {
if (body.length === 0 || body == null) {
const err = new Error("Body cannot be empty when content-type is set to 'application/json'")
err.statusCode = 400
return done(err)
}
try {
const json = secureJson.parse(body.toString('utf8'), {
protoAction: fastify.initialConfig.onProtoPoisoning,
constructorAction: fastify.initialConfig.onConstructorPoisoning
})
done(null, json)
} catch (err) {
err.statusCode = 400
return done(err)
}
}
}
const plugin = fp(rawBody, {
fastify: '^4.19.x',
name: 'fastify-raw-body'
})
module.exports = plugin
module.exports.default = plugin
module.exports.fastifyRawBody = plugin