diff --git a/lib/request.js b/lib/request.js index c1cd37e8..ec004ab1 100644 --- a/lib/request.js +++ b/lib/request.js @@ -75,7 +75,13 @@ class Request { * @return {boolean} */ is(...types) { - return typeis(this, types.flat()) || false; + try { + return typeis(this, types.flat()) || false; + } catch { + // type-is throws on some malformed content-types (e.g. `;charset=utf-8`), + // which can never match any of the given mime types. + return false; + } } } diff --git a/test/integration/handlers/authenticate-handler_test.js b/test/integration/handlers/authenticate-handler_test.js index f3e5e92d..a28a35da 100644 --- a/test/integration/handlers/authenticate-handler_test.js +++ b/test/integration/handlers/authenticate-handler_test.js @@ -525,6 +525,27 @@ describe('AuthenticateHandler integration', function () { } }); + it('should throw an error if the media type is malformed', async function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} }, + }); + const request = new Request({ + body: { access_token: 'foo' }, + headers: { 'content-type': ';charset=utf-8', 'transfer-encoding': 'chunked' }, + method: 'POST', + query: {}, + }); + + try { + await handler.getTokenFromRequestBody(request); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid request: content must be application/x-www-form-urlencoded'); + } + }); + it('should return the bearer token', function () { const handler = new AuthenticateHandler({ model: { getAccessToken: function () {} }, diff --git a/test/integration/handlers/token-handler_test.js b/test/integration/handlers/token-handler_test.js index 4fc52ca0..4df497c4 100644 --- a/test/integration/handlers/token-handler_test.js +++ b/test/integration/handlers/token-handler_test.js @@ -286,6 +286,33 @@ describe('TokenHandler integration', function () { }); }); + it('should throw an error if the media type is malformed', function () { + const model = Model.from({ + getClient: function () {}, + saveToken: function () {}, + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { grant_type: 'password' }, + headers: { 'content-type': ';charset=utf-8', 'transfer-encoding': 'chunked' }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(should.fail) + .catch(function (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid request: content must be application/x-www-form-urlencoded'); + }); + }); + it('should throw the error if an oauth error is thrown', function () { const model = Model.from({ getClient: function () {}, diff --git a/test/integration/request_test.js b/test/integration/request_test.js index 7766603f..83dae562 100644 --- a/test/integration/request_test.js +++ b/test/integration/request_test.js @@ -175,6 +175,20 @@ describe('Request integration', function () { request.is('json').should.be.false; }); + it('should return `false` if the content type is malformed', function () { + const request = new Request({ + body: {}, + headers: { + 'content-type': ';charset=utf-8', + 'transfer-encoding': 'chunked', + }, + method: {}, + query: {}, + }); + + request.is('application/x-www-form-urlencoded').should.be.false; + }); + it('should return `false` if the request has no body', function () { const request = new Request({ body: {},