From 5f31c5b30ae6067e966a1e8d0766716d0f746055 Mon Sep 17 00:00:00 2001 From: Krystian Jarmicki Date: Thu, 1 Oct 2020 14:39:42 +0200 Subject: [PATCH 1/2] Make it work with Async Hooks --- HISTORY.md | 1 + lib/read.js | 25 +++++++++++++++---- test/body-parser.js | 58 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) 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..3e981fb1 100644 --- a/lib/read.js +++ b/lib/read.js @@ -17,6 +17,12 @@ var iconv = require('iconv-lite') var onFinished = require('on-finished') var zlib = require('zlib') +var asyncHooks +try { + asyncHooks = require('async_hooks') +} catch (ignored) { +} + /** * Module exports. */ @@ -74,7 +80,7 @@ function read (req, res, next, parse, debug, options) { // read body debug('read body') - getBody(stream, opts, function (error, body) { + getBody(stream, opts, preserveAsyncContext('GetBody', function (error, body) { if (error) { var _error @@ -91,9 +97,9 @@ function read (req, res, next, parse, debug, options) { // read off entire request stream.resume() - onFinished(req, function onfinished () { + onFinished(req, preserveAsyncContext('OnFinished', function onfinished () { next(createError(400, _error)) - }) + })) return } @@ -128,7 +134,7 @@ function read (req, res, next, parse, debug, options) { } next() - }) + })) } /** @@ -179,3 +185,14 @@ function contentstream (req, debug, inflate) { return stream } + +function preserveAsyncContext (asyncResourceType, fn) { + if (!asyncHooks) { + return fn + } + var asyncResource = new asyncHooks.AsyncResource(asyncResourceType) + return function () { + var args = [].slice.call(arguments) + asyncResource.runInAsyncScope.apply(asyncResource, [fn, null].concat(args)) + } +} 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() From 90434e34a8c5e3fe4bc9e85221e628c16a3678fa Mon Sep 17 00:00:00 2001 From: Krystian Jarmicki Date: Thu, 1 Oct 2020 22:47:53 +0200 Subject: [PATCH 2/2] replace function wrapper with bind --- lib/read.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/read.js b/lib/read.js index 3e981fb1..21349a17 100644 --- a/lib/read.js +++ b/lib/read.js @@ -191,8 +191,5 @@ function preserveAsyncContext (asyncResourceType, fn) { return fn } var asyncResource = new asyncHooks.AsyncResource(asyncResourceType) - return function () { - var args = [].slice.call(arguments) - asyncResource.runInAsyncScope.apply(asyncResource, [fn, null].concat(args)) - } + return asyncResource.runInAsyncScope.bind(asyncResource, fn, null) }