Skip to content

Commit bebd4e6

Browse files
climba03003jsumners
authored andcommitted
Merge commit from fork
* fix: schema validation bypass * chore: update comments Co-authored-by: James Sumners <321201+jsumners@users.noreply.github.com> Signed-off-by: KaKa <23028015+climba03003@users.noreply.github.com> --------- Signed-off-by: KaKa <23028015+climba03003@users.noreply.github.com> Co-authored-by: James Sumners <321201+jsumners@users.noreply.github.com>
1 parent 3a6d4ae commit bebd4e6

2 files changed

Lines changed: 131 additions & 1 deletion

File tree

lib/validation.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ function validate (context, request, execution) {
155155
validatorFunction = context[bodySchema]
156156
} else if (context[bodySchema]) {
157157
// TODO: add request.contentType and reuse it here
158-
const contentType = request.headers['content-type']?.split(';', 1)[0]
158+
const contentType = getEssenceMediaType(request.headers['content-type'])
159159
const contentSchema = context[bodySchema][contentType]
160160
if (contentSchema) {
161161
validatorFunction = contentSchema
@@ -254,6 +254,16 @@ function wrapValidationError (result, dataVar, schemaErrorFormatter) {
254254
return error
255255
}
256256

257+
/**
258+
* simple function to retrieve the essence media type
259+
* @param {string} header
260+
* @returns {string} Mimetype string.
261+
*/
262+
function getEssenceMediaType (header) {
263+
if (!header) return ''
264+
return header.split(';', 1)[0].trim().toLowerCase()
265+
}
266+
257267
module.exports = {
258268
symbols: { bodySchema, querystringSchema, responseSchema, paramsSchema, headersSchema },
259269
compileSchemasForValidation,

test/schema-validation.test.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,3 +1285,123 @@ test('Custom validator builder override by custom validator compiler in child in
12851285
})
12861286
t.equal(two.statusCode, 200)
12871287
})
1288+
1289+
test('Schema validation when no content type is provided', async t => {
1290+
// this case should not be happened in normal use-case,
1291+
// it is added for the completeness of code branch
1292+
const fastify = Fastify()
1293+
1294+
fastify.post('/', {
1295+
schema: {
1296+
body: {
1297+
content: {
1298+
'application/json': {
1299+
schema: {
1300+
type: 'object',
1301+
properties: {
1302+
foo: { type: 'string' }
1303+
},
1304+
required: ['foo'],
1305+
additionalProperties: false
1306+
}
1307+
}
1308+
}
1309+
}
1310+
},
1311+
preValidation: async (request) => {
1312+
request.headers['content-type'] = undefined
1313+
}
1314+
}, async () => 'ok')
1315+
1316+
await fastify.ready()
1317+
1318+
const invalid = await fastify.inject({
1319+
method: 'POST',
1320+
url: '/',
1321+
headers: {
1322+
'content-type': 'application/json'
1323+
},
1324+
body: { invalid: 'string' }
1325+
})
1326+
t.equal(invalid.statusCode, 200)
1327+
})
1328+
1329+
test('Schema validation will not be bypass by different content type', async t => {
1330+
t.plan(8)
1331+
1332+
const fastify = Fastify()
1333+
1334+
fastify.post('/', {
1335+
schema: {
1336+
body: {
1337+
content: {
1338+
'application/json': {
1339+
schema: {
1340+
type: 'object',
1341+
properties: {
1342+
foo: { type: 'string' }
1343+
},
1344+
required: ['foo'],
1345+
additionalProperties: false
1346+
}
1347+
}
1348+
}
1349+
}
1350+
}
1351+
}, async () => 'ok')
1352+
1353+
await fastify.ready()
1354+
1355+
const correct1 = await fastify.inject({
1356+
method: 'POST',
1357+
url: '/',
1358+
headers: {
1359+
'content-type': 'application/json'
1360+
},
1361+
body: { foo: 'string' }
1362+
})
1363+
t.equal(correct1.statusCode, 200)
1364+
1365+
const correct2 = await fastify.inject({
1366+
method: 'POST',
1367+
url: '/',
1368+
headers: {
1369+
'content-type': 'application/json; charset=utf-8'
1370+
},
1371+
body: { foo: 'string' }
1372+
})
1373+
t.equal(correct2.statusCode, 200)
1374+
1375+
const invalid1 = await fastify.inject({
1376+
method: 'POST',
1377+
url: '/',
1378+
headers: {
1379+
'content-type': 'application/json ;'
1380+
},
1381+
body: { invalid: 'string' }
1382+
})
1383+
t.equal(invalid1.statusCode, 400)
1384+
t.equal(invalid1.json().code, 'FST_ERR_VALIDATION')
1385+
1386+
const invalid2 = await fastify.inject({
1387+
method: 'POST',
1388+
url: '/',
1389+
headers: {
1390+
'content-type': 'ApPlIcAtIoN/JsOn;'
1391+
},
1392+
body: { invalid: 'string' }
1393+
})
1394+
t.equal(invalid2.statusCode, 400)
1395+
t.equal(invalid2.json().code, 'FST_ERR_VALIDATION')
1396+
1397+
const invalid3 = await fastify.inject({
1398+
method: 'POST',
1399+
url: '/',
1400+
headers: {
1401+
'content-type': 'ApPlIcAtIoN/JsOn ;'
1402+
},
1403+
body: { invalid: 'string' }
1404+
})
1405+
t.equal(invalid3.statusCode, 400)
1406+
t.equal(invalid3.json().code, 'FST_ERR_VALIDATION')
1407+
})

0 commit comments

Comments
 (0)