From edb8dbc517818baf10fb8e41cd57b061775c0ff1 Mon Sep 17 00:00:00 2001 From: Mike Li Date: Mon, 12 Feb 2018 11:28:19 -0800 Subject: [PATCH] Support middleware injected by AppDynamics. AppDynamics injects a proxy object into the router stack, which it uses for its network analysis. This is similar to how NewRelic adds a sentinel handler to the router stack. This commit adds a similar workaround so that loopback can find the original layer. --- lib/server-app.js | 13 ++++++++----- test/app.test.js | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/server-app.js b/lib/server-app.js index 6bba947dd..98e46824d 100644 --- a/lib/server-app.js +++ b/lib/server-app.js @@ -221,12 +221,15 @@ proto.middleware = function(name, paths, handler) { */ proto._findLayerByHandler = function(handler) { // Other handlers can be added to the stack, for example, - // NewRelic adds sentinel handler. We need to search the stack + // NewRelic adds sentinel handler, and AppDynamics adds + // some additional proxy info. We need to search the stack for (var k = this._router.stack.length - 1; k >= 0; k--) { - if (this._router.stack[k].handle === handler || - // NewRelic replaces the handle and keeps it as __NR_original - this._router.stack[k].handle['__NR_original'] === handler - ) { + const isOriginal = this._router.stack[k].handle === handler; + const isNewRelic = this._router.stack[k].handle['__NR_original'] === handler; + const isAppDynamics = this._router.stack[k].handle['__appdynamicsProxyInfo__'] && + this._router.stack[k].handle['__appdynamicsProxyInfo__']['orig'] === handler; + + if (isOriginal || isNewRelic || isAppDynamics) { return this._router.stack[k]; } else { // Aggressively check if the original handler has been wrapped diff --git a/test/app.test.js b/test/app.test.js index f9e6843f7..93214bfe0 100644 --- a/test/app.test.js +++ b/test/app.test.js @@ -124,6 +124,28 @@ describe('app', function() { }); }); + it('allows handlers to be wrapped as __appdynamicsProxyInfo__ on express stack', + function(done) { + var myHandler = namedHandler('my-handler'); + var wrappedHandler = function(req, res, next) { + myHandler(req, res, next); + }; + wrappedHandler['__appdynamicsProxyInfo__'] = { + orig: myHandler, + }; + app.middleware('routes:before', wrappedHandler); + var found = app._findLayerByHandler(myHandler); + expect(found).to.be.an('object'); + expect(found).have.property('phase', 'routes:before'); + executeMiddlewareHandlers(app, function(err) { + if (err) return done(err); + + expect(steps).to.eql(['my-handler']); + + done(); + }); + }); + it('allows handlers to be wrapped as a property on express stack', function(done) { var myHandler = namedHandler('my-handler');