diff --git a/lib/contentTypeParser.js b/lib/contentTypeParser.js index 10f4bff5f8..958c16ef5e 100644 --- a/lib/contentTypeParser.js +++ b/lib/contentTypeParser.js @@ -364,7 +364,7 @@ function removeAllContentTypeParsers () { function compareContentType (contentType, parserListItem) { if (parserListItem.isEssence) { // we do essence check - return contentType.type.indexOf(parserListItem) !== -1 + return contentType.type.indexOf(parserListItem.type) !== -1 } else { // when the content-type includes parameters // we do a full-text search @@ -394,12 +394,21 @@ function compareRegExpContentType (contentType, essenceMIMEType, regexp) { function ParserListItem (contentType) { this.name = contentType // we pre-calculate all the needed information - // before content-type comparsion + // before content-type comparison const parsed = safeParseContentType(contentType) - this.type = parsed.type + this.isEssence = contentType.indexOf(';') === -1 + if (parsed.type === '') { + if (this.isEssence === true) { + this.type = contentType.trim() + } else { + this.type = contentType.split(';')[0].trim() + this.isEssence = true + } + } else { + this.type = parsed.type + } this.parameters = parsed.parameters this.parameterKeys = Object.keys(parsed.parameters) - this.isEssence = contentType.indexOf(';') === -1 } // used in ContentTypeParser.remove diff --git a/test/content-parser.test.js b/test/content-parser.test.js index d677ecfedb..62085fe6f7 100644 --- a/test/content-parser.test.js +++ b/test/content-parser.test.js @@ -649,3 +649,252 @@ test('content-type regexp list should be cloned when plugin override', async t = t.same(payload, 'png') } }) + +test('allow partial content-type /1', async t => { + t.plan(1) + + const fastify = Fastify() + fastify.removeAllContentTypeParsers() + fastify.addContentTypeParser('json', function (request, body, done) { + t.pass('should be called') + done(null, body) + }) + + fastify.post('/', async () => { + return 'ok' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'application/json; foo=bar; charset=utf8' + }, + body: '' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'image/jpeg' + }, + body: '' + }) +}) + +test('allow partial content-type /2', async t => { + t.plan(1) + + const fastify = Fastify() + fastify.removeAllContentTypeParsers() + fastify.addContentTypeParser(' json', function (request, body, done) { + t.pass('should be called') + done(null, body) + }) + + fastify.post('/', async () => { + return 'ok' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'application/json; foo=bar; charset=utf8' + }, + body: '' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'image/jpeg' + }, + body: '' + }) +}) + +test('allow partial content-type /3', async t => { + t.plan(1) + + const fastify = Fastify() + fastify.removeAllContentTypeParsers() + fastify.addContentTypeParser('json ', function (request, body, done) { + t.pass('should be called') + done(null, body) + }) + + fastify.post('/', async () => { + return 'ok' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'application/json; foo=bar; charset=utf8' + }, + body: '' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'image/jpeg' + }, + body: '' + }) +}) + +test('allow partial content-type /4', async t => { + t.plan(1) + + const fastify = Fastify() + fastify.removeAllContentTypeParsers() + fastify.addContentTypeParser(' json ', function (request, body, done) { + t.pass('should be called') + done(null, body) + }) + + fastify.post('/', async () => { + return 'ok' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'application/json; foo=bar; charset=utf8' + }, + body: '' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'image/jpeg' + }, + body: '' + }) +}) + +test('allow partial content-type /5', async t => { + t.plan(1) + + const fastify = Fastify() + fastify.removeAllContentTypeParsers() + fastify.addContentTypeParser('json;', function (request, body, done) { + t.pass('should be called') + done(null, body) + }) + + fastify.post('/', async () => { + return 'ok' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'application/json; foo=bar; charset=utf8' + }, + body: '' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'image/jpeg' + }, + body: '' + }) +}) + +test('content-type isEssence-check should use ParserListItem.type /1', async t => { + t.plan(1) + + const fastify = Fastify() + fastify.removeAllContentTypeParsers() + fastify.addContentTypeParser(' application/json', function (request, body, done) { + t.pass('should be called') + done(null, body) + }) + fastify.addContentTypeParser('text/plain', function (request, body, done) { + t.fail('shouldn\'t be called') + done(null, body) + }) + + fastify.post('/', async () => { + return 'ok' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'application/json; foo=bar; charset=utf8' + }, + body: '' + }) +}) + +test('content-type isEssence-check should use ParserListItem.type /2', async t => { + t.plan(1) + + const fastify = Fastify() + fastify.removeAllContentTypeParsers() + fastify.addContentTypeParser('application/json ', function (request, body, done) { + t.pass('should be called') + done(null, body) + }) + fastify.addContentTypeParser('text/plain', function (request, body, done) { + t.fail('shouldn\'t be called') + done(null, body) + }) + + fastify.post('/', async () => { + return 'ok' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'application/json; foo=bar; charset=utf8' + }, + body: '' + }) +}) + +test('content-type isEssence-check should use ParserListItem.type /3', async t => { + t.plan(1) + + const fastify = Fastify() + fastify.removeAllContentTypeParsers() + fastify.addContentTypeParser(' application/json ', function (request, body, done) { + t.pass('should be called') + done(null, body) + }) + fastify.addContentTypeParser('text/plain', function (request, body, done) { + t.fail('shouldn\'t be called') + done(null, body) + }) + + fastify.post('/', async () => { + return 'ok' + }) + + await fastify.inject({ + method: 'POST', + path: '/', + headers: { + 'content-type': 'application/json; foo=bar; charset=utf8' + }, + body: '' + }) +})