Skip to content

Commit 436da4c

Browse files
Merge commit from fork
* fix: schema validation bypass * chore: update comments Co-authored-by: James Sumners <[email protected]> Signed-off-by: KaKa <[email protected]> --------- Signed-off-by: KaKa <[email protected]> Co-authored-by: James Sumners <[email protected]>
1 parent ebbd4a6 commit 436da4c

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-1
lines changed

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
@@ -1300,3 +1300,123 @@ test('Custom validator builder override by custom validator compiler in child in
13001300
})
13011301
t.equal(two.statusCode, 200)
13021302
})
1303+
1304+
test('Schema validation when no content type is provided', async t => {
1305+
// this case should not be happened in normal use-case,
1306+
// it is added for the completeness of code branch
1307+
const fastify = Fastify()
1308+
1309+
fastify.post('/', {
1310+
schema: {
1311+
body: {
1312+
content: {
1313+
'application/json': {
1314+
schema: {
1315+
type: 'object',
1316+
properties: {
1317+
foo: { type: 'string' }
1318+
},
1319+
required: ['foo'],
1320+
additionalProperties: false
1321+
}
1322+
}
1323+
}
1324+
}
1325+
},
1326+
preValidation: async (request) => {
1327+
request.headers['content-type'] = undefined
1328+
}
1329+
}, async () => 'ok')
1330+
1331+
await fastify.ready()
1332+
1333+
const invalid = await fastify.inject({
1334+
method: 'POST',
1335+
url: '/',
1336+
headers: {
1337+
'content-type': 'application/json'
1338+
},
1339+
body: { invalid: 'string' }
1340+
})
1341+
t.equal(invalid.statusCode, 200)
1342+
})
1343+
1344+
test('Schema validation will not be bypass by different content type', async t => {
1345+
t.plan(8)
1346+
1347+
const fastify = Fastify()
1348+
1349+
fastify.post('/', {
1350+
schema: {
1351+
body: {
1352+
content: {
1353+
'application/json': {
1354+
schema: {
1355+
type: 'object',
1356+
properties: {
1357+
foo: { type: 'string' }
1358+
},
1359+
required: ['foo'],
1360+
additionalProperties: false
1361+
}
1362+
}
1363+
}
1364+
}
1365+
}
1366+
}, async () => 'ok')
1367+
1368+
await fastify.ready()
1369+
1370+
const correct1 = await fastify.inject({
1371+
method: 'POST',
1372+
url: '/',
1373+
headers: {
1374+
'content-type': 'application/json'
1375+
},
1376+
body: { foo: 'string' }
1377+
})
1378+
t.equal(correct1.statusCode, 200)
1379+
1380+
const correct2 = await fastify.inject({
1381+
method: 'POST',
1382+
url: '/',
1383+
headers: {
1384+
'content-type': 'application/json; charset=utf-8'
1385+
},
1386+
body: { foo: 'string' }
1387+
})
1388+
t.equal(correct2.statusCode, 200)
1389+
1390+
const invalid1 = await fastify.inject({
1391+
method: 'POST',
1392+
url: '/',
1393+
headers: {
1394+
'content-type': 'application/json ;'
1395+
},
1396+
body: { invalid: 'string' }
1397+
})
1398+
t.equal(invalid1.statusCode, 400)
1399+
t.equal(invalid1.json().code, 'FST_ERR_VALIDATION')
1400+
1401+
const invalid2 = await fastify.inject({
1402+
method: 'POST',
1403+
url: '/',
1404+
headers: {
1405+
'content-type': 'ApPlIcAtIoN/JsOn;'
1406+
},
1407+
body: { invalid: 'string' }
1408+
})
1409+
t.equal(invalid2.statusCode, 400)
1410+
t.equal(invalid2.json().code, 'FST_ERR_VALIDATION')
1411+
1412+
const invalid3 = await fastify.inject({
1413+
method: 'POST',
1414+
url: '/',
1415+
headers: {
1416+
'content-type': 'ApPlIcAtIoN/JsOn ;'
1417+
},
1418+
body: { invalid: 'string' }
1419+
})
1420+
t.equal(invalid3.statusCode, 400)
1421+
t.equal(invalid3.json().code, 'FST_ERR_VALIDATION')
1422+
})

0 commit comments

Comments
 (0)