diff --git a/HISTORY.md b/HISTORY.md index 63288c30..e6f5348f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -8,6 +8,7 @@ unreleased - deps: http-errors@1.7.3 * deps: safe-buffer@5.2.0 * deps: type-is@~1.6.18 + * Make it work with Async Hooks 1.19.0 / 2019-04-25 =================== diff --git a/lib/read.js b/lib/read.js index c1026095..dbdb52aa 100644 --- a/lib/read.js +++ b/lib/read.js @@ -73,30 +73,35 @@ function read (req, res, next, parse, debug, options) { } // read body - debug('read body') - getBody(stream, opts, function (error, body) { - if (error) { - var _error - - if (error.type === 'encoding.unsupported') { - // echo back charset - _error = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', { - charset: encoding.toLowerCase(), - type: 'charset.unsupported' - }) - } else { - // set status code on error - _error = createError(400, error) - } + function readErrorHandler (error) { + var _error + if (error.type === 'encoding.unsupported') { + // echo back charset + _error = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', { + charset: encoding.toLowerCase(), + type: 'charset.unsupported' + }) + } else { + // set status code on error + _error = createError(400, error) + } - // read off entire request - stream.resume() - onFinished(req, function onfinished () { + // read off entire request + stream.resume() + if (isPromiseAvailable()) { + new Promise(function (resolve) { + onFinished(req, resolve) + }).then(function () { + next(createError(400, _error)) + }) + } else { + onFinished(req, function () { next(createError(400, _error)) }) - return } + } + function readSuccessHandler (body) { // verify if (verify) { try { @@ -128,7 +133,20 @@ function read (req, res, next, parse, debug, options) { } next() - }) + } + + debug('read body') + if (isPromiseAvailable()) { + getBody(stream, opts) + .then(readSuccessHandler, readErrorHandler) + } else { + getBody(stream, opts, function (error, body) { + if (error) { + return readErrorHandler(error) + } + readSuccessHandler(body) + }) + } } /** @@ -179,3 +197,14 @@ function contentstream (req, debug, inflate) { return stream } + +/** + * Check whether Promise is available. + * + * @return {boolean} + * @private + */ + +function isPromiseAvailable () { + return typeof global.Promise === 'function' +} diff --git a/test/body-parser.js b/test/body-parser.js index e32cf94d..38389eed 100644 --- a/test/body-parser.js +++ b/test/body-parser.js @@ -3,6 +3,13 @@ var http = require('http') var methods = require('methods') var request = require('supertest') +var describeWhenAsyncHooksAreSupported = describe.skip +try { + var asyncHooks = require('async_hooks') + describeWhenAsyncHooksAreSupported = typeof asyncHooks.AsyncLocalStorage === 'function' ? describe : describe.skip +} catch (ignored) { +} + var bodyParser = require('..') describe('bodyParser()', function () { @@ -51,6 +58,57 @@ describe('bodyParser()', function () { .expect(200, '{"user":"tobi"}', done) }) + describeWhenAsyncHooksAreSupported('used with async hooks', function () { + it('should maintain context when parsing was successful', function (done) { + var _bodyParser = bodyParser() + var asyncLocalStorage = new asyncHooks.AsyncLocalStorage() + + var server = http.createServer(function (req, res) { + const store = { + contextMaintained: true + } + asyncLocalStorage.run(store, function () { + _bodyParser(req, res, function (err) { + res.statusCode = err ? (err.status || 500) : 200 + res.end(err ? err.message : JSON.stringify(asyncLocalStorage.getStore())) + }) + }) + }) + + request(server) + .post('/') + .set('Content-Type', 'application/json') + .send('{"user":"tobi"}') + .expect(200, '{"contextMaintained":true}', done) + }) + + it('should maintain context when parsing has failed', function (done) { + var _bodyParser = bodyParser.text() + var asyncLocalStorage = new asyncHooks.AsyncLocalStorage() + + var server = http.createServer(function (req, res) { + const store = { + contextMaintained: true + } + asyncLocalStorage.run(store, function () { + _bodyParser(req, res, function (err) { + if (!err) { + res.statusCode = 500 + res.end('parsing was expeced to fail, but it succeeded') + } + res.end(JSON.stringify(asyncLocalStorage.getStore())) + }) + }) + }) + + request(server) + .post('/') + .set('Content-Type', 'text/plain; charset=x-fake') + .send('user is tobi') + .expect(200, '{"contextMaintained":true}', done) + }) + }) + describe('http methods', function () { before(function () { var _bodyParser = bodyParser()