From 7eba938a22a1b2dc1b09e5a3b76a23bd0f66f7e1 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Thu, 17 Sep 2020 12:05:11 -0700 Subject: [PATCH] Use diagnostics_channel in layers --- lib/layer.js | 40 ++++++++++++++ test/diagnostics-channel.js | 104 ++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 test/diagnostics-channel.js diff --git a/lib/layer.js b/lib/layer.js index 60a737f..ca8abbb 100644 --- a/lib/layer.js +++ b/lib/layer.js @@ -15,6 +15,18 @@ var pathRegexp = require('path-to-regexp') var debug = require('debug')('router:layer') +/** + * Diagnostic channels + * @private + */ +var onHandleRequest +var onHandleError +try { + var dc = require('diagnostics_channel') + onHandleRequest = dc.channel('express.layer.handle_request') + onHandleError = dc.channel('express.layer.handle_error') +} catch (err) { } + /** * Module variables. * @private @@ -41,6 +53,7 @@ function Layer(path, options, fn) { this.params = undefined this.path = undefined this.regexp = pathRegexp(path, this.keys = [], opts) + this.routingPath = path // set fast path flags this.regexp.fast_star = path === '*' @@ -65,9 +78,23 @@ Layer.prototype.handle_error = function handle_error(error, req, res, next) { return next(error) } + req.layerStack = req.layerStack || [] + req.layerStack.push(this) + + if (onHandleError && onHandleError.shouldPublish()) { + onHandleError.publish({ + error: error, + request: req, + response: res, + layer: this + }) + } + try { fn(error, req, res, next) + req.layerStack.pop() } catch (err) { + req.layerStack.pop() next(err) } } @@ -89,9 +116,22 @@ Layer.prototype.handle_request = function handle(req, res, next) { return next() } + req.layerStack = req.layerStack || [] + req.layerStack.push(this) + + if (onHandleRequest && onHandleRequest.shouldPublish()) { + onHandleRequest.publish({ + request: req, + response: res, + layer: this + }) + } + try { fn(req, res, next) + req.layerStack.pop() } catch (err) { + req.layerStack.pop() next(err) } } diff --git a/test/diagnostics-channel.js b/test/diagnostics-channel.js new file mode 100644 index 0000000..b457d04 --- /dev/null +++ b/test/diagnostics-channel.js @@ -0,0 +1,104 @@ + +var Router = require('../') + , assert = require('assert'); + +var dc = require('diagnostics_channel'); +var onHandleRequest = dc.channel('express.layer.handle_request'); +var onHandleError = dc.channel('express.layer.handle_error'); + +function mapProp(prop) { + return function mapped(obj) { + return obj[prop]; + }; +} + +function mapAndJoin(prop) { + return function (list) { + return list.map(mapProp(prop)).join(''); + } +} + +function noop() { } + +describe('diagnostics_channel', function () { + var joinLayerStack = mapAndJoin('routingPath'); + var handleRequest; + var handleError; + + onHandleRequest.subscribe(function (message) { + handleRequest = message; + }); + + onHandleError.subscribe(function (message) { + handleError = message; + }); + + it('use has no layers with a path', function (done) { + var router = new Router(); + + router.use(function (req, res) { + res.end(); + }); + + function end() { + assert.strictEqual(joinLayerStack(handleRequest.request.layerStack), '/'); + done(); + } + + router.handle({ url: '/', method: 'GET' }, { end }, noop); + }); + + it('regular routes have a layer with a path', function (done) { + var router = new Router(); + + router.get('/hello/:name', function (req, res) { + res.end(); + }); + + function end() { + assert.strictEqual(joinLayerStack(handleRequest.request.layerStack), '/hello/:name/'); + done(); + } + + router.handle({ url: '/hello/world', method: 'GET' }, { end }, noop); + }); + + it('nested routes have multiple layers with paths', function (done) { + var outer = new Router(); + var inner = new Router(); + + inner.get('/:name', function (req, res) { + res.end(); + }); + + outer.use('/hello', inner); + + function end() { + assert.strictEqual(joinLayerStack(handleRequest.request.layerStack), '/hello/:name/'); + done(); + } + + outer.handle({ url: '/hello/world', method: 'GET' }, { end }, noop); + }); + + it('errors send through a different channel', function (done) { + var router = new Router(); + var error = new Error('fail'); + + router.get('/hello/:name', function (req, res) { + throw error; + }); + + router.use(function (err, req, res, next) { + res.end(); + }); + + function end() { + assert.strictEqual(joinLayerStack(handleRequest.request.layerStack), '/hello/:name/'); + assert.strictEqual(handleError.error, error); + done(); + } + + router.handle({ url: '/hello/world', method: 'GET' }, { end }, noop); + }); +});