diff --git a/lib/bindings/HTTPBinding.js b/lib/bindings/HTTPBinding.js index 2a4412bd..90423dbf 100644 --- a/lib/bindings/HTTPBinding.js +++ b/lib/bindings/HTTPBinding.js @@ -50,14 +50,19 @@ const config = require('../configService'); let httpBindingServer; const transport = 'HTTP'; -const { promisify } = require('util'); -const json = promisify(bodyParser.json({ strict: false })); // accept anything JSON.parse accepts. -const text = promisify(bodyParser.text()); -const raw = promisify(bodyParser.raw()); const xml2js = require('xml2js'); const xmlStripPrefix = xml2js.processors.stripPrefix; -const xml = promisify( - bodyParser.xml({ +const typeis = require('type-is'); + +function parserBody() { + const json = bodyParser.json({ strict: false }); // accept anything JSON.parse accepts. + const text = bodyParser.text(); + const raw = bodyParser.raw(); + const xml = bodyParser.xml({ + // Tell bodyparser-xml to not check the Content-Type header, + // we will check it ourselves. This works around upstream bug + // https://github.com/jshttp/type-is/issues/52 + type: () => true, xmlParseOptions: { // XML namespaces might change from one request to the next. // It is useful to remove them from the document, @@ -67,24 +72,39 @@ const xml = promisify( attrNameProcessors: [xmlStripPrefix] } }) -); - -function parserBody() { // generic bodyParser return function (req, res, next) { - if (req.is('text/plain')) { - text(req, res).then(() => next(), next); - } else if (req.is('application/octet-stream')) { - raw(req, res).then(() => next(), next); - } else if (req.is('application/soap+xml')) { - xml(req, res).then(() => next(), next); + // use typeis.is on a trimmed header, instead of + // req.is on the request, to work around + // https://github.com/jshttp/type-is/issues/52 + const contentType = req.get('content-type').split(';').shift().trim(); + if (typeis.is(contentType, ['text/plain'])) { + text(req, res, next) + } else if (typeis.is(contentType, ['application/octet-stream'])) { + raw(req, res, next) + } else if (typeis.is(contentType, ['application/soap+xml'])) { + xml(req, res, next) } else { // req.is('json') - json(req, res).then(() => next(), next); + json(req, res, next) } }; } +function checkPostContentType(...mimeTypes) { + return function (req, res, next) { + let err + // use typeis.is on a trimmed header, instead of + // req.is on the request, to work around + // https://github.com/jshttp/type-is/issues/52 + const contentType = req.get('content-type').split(';').shift().trim(); + if (!typeis.hasBody(req) || !typeis.is(contentType, mimeTypes)) { + err = new errors.UnsupportedType(mimeTypes.join(', ')); + } + next(err); + }; +} + function checkMandatoryParams(queryPayload) { return function (req, res, next) { const notFoundParams = []; @@ -106,17 +126,6 @@ function checkMandatoryParams(queryPayload) { if (queryPayload && !req.query.d && req.query.getCmd !== '1') { notFoundParams.push('Payload'); } - if ( - req.method === 'POST' && - !req.is('json') && - !req.is('text/plain') && - !req.is('application/octet-stream') && - !req.is('application/soap+xml') - ) { - error = new errors.UnsupportedType( - 'application/json, text/plain, application/octet-stream, application/soap+xml' - ); - } if (notFoundParams.length !== 0) { next(new errors.MandatoryParamsNotFound(notFoundParams)); @@ -681,6 +690,8 @@ function start(callback) { httpBindingServer.router.post( config.getConfig().iota.defaultResource || constants.HTTP_MEASURE_PATH, + // text and octet-stream allowed for backward compatibility + checkPostContentType('application/json', 'text/plain', 'application/octet-stream'), bodyParser.json({ strict: false }), // accept anything JSON.parse accepts checkMandatoryParams(false), parseDataMultipleMeasure, @@ -694,6 +705,7 @@ function start(callback) { '/' + constants.MEASURES_SUFIX + '/:attrValue', + checkPostContentType('application/json', 'text/plain', 'application/octet-stream', 'application/soap+xml'), parserBody(), checkMandatoryParams(false), parseData, // non multiple measures are expected in this route @@ -704,6 +716,8 @@ function start(callback) { httpBindingServer.router.post( (config.getConfig().iota.defaultResource || constants.HTTP_MEASURE_PATH) + constants.HTTP_COMMANDS_PATH, + // text and octet-stream allowed for backward compatibility + checkPostContentType('application/json', 'text/plain', 'application/octet-stream'), bodyParser.json({ strict: false }), // accept anything JSON.parse accepts. checkMandatoryParams(false), parseData, @@ -715,6 +729,8 @@ function start(callback) { httpBindingServer.router.post( (config.getConfig().iota.defaultResource || constants.HTTP_MEASURE_PATH) + constants.HTTP_CONFIGURATION_PATH, + // text and octet-stream allowed for backward compatibility + checkPostContentType('application/json', 'text/plain', 'application/octet-stream'), bodyParser.json({ strict: false }), // accept anything JSON.parse accepts. checkMandatoryParams(false), parseData,