Skip to content

Commit 315020a

Browse files
IlyasShabisimon-id
andauthored
fix(express): 2 crashes when router[method]() is used with no handler (#6908)
Co-authored-by: simon-id <simon.id@datadoghq.com>
1 parent e5e826e commit 315020a

File tree

3 files changed

+27
-15
lines changed

3 files changed

+27
-15
lines changed

packages/datadog-instrumentations/src/express.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,26 +76,28 @@ function wrapResponseRender (render) {
7676
}
7777

7878
function wrapAppAll (all) {
79-
return function wrappedAll (path, ...otherArgs) {
80-
if (!routeAddedChannel.hasSubscribers) return all.call(this, path, ...otherArgs)
79+
return function wrappedAll (...args) {
80+
if (!routeAddedChannel.hasSubscribers) return all.apply(this, args)
8181

82+
const path = args[0]
8283
const paths = normalizeRoutePaths(path)
8384

8485
for (const p of paths) {
8586
routeAddedChannel.publish({ method: '*', path: p })
8687
}
8788

88-
return all.call(this, path, ...otherArgs)
89+
return all.apply(this, args)
8990
}
9091
}
9192

9293
// Wrap app.route() to instrument Route object
9394
function wrapAppRoute (route) {
94-
return function wrappedRoute (path, ...otherArgs) {
95-
const routeObj = route.call(this, path, ...otherArgs)
95+
return function wrappedRoute (...args) {
96+
const routeObj = route.apply(this, args)
9697

9798
if (!routeAddedChannel.hasSubscribers) return routeObj
9899

100+
const path = args[0]
99101
const paths = normalizeRoutePaths(path)
100102

101103
if (!paths.length) return routeObj

packages/datadog-instrumentations/src/router.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,33 +146,34 @@ function createWrapRouterMethod (name) {
146146
}
147147

148148
function wrapMethod (original) {
149-
return shimmer.wrapFunction(original, original => function methodWithTrace (fn, ...otherArgs) {
149+
return shimmer.wrapFunction(original, original => function methodWithTrace (...args) {
150150
let offset = 0
151151
if (this.stack) {
152152
offset = Array.isArray(this.stack) ? this.stack.length : 1
153153
}
154-
const router = original.call(this, fn, ...otherArgs)
154+
const router = original.apply(this, args)
155155

156156
if (typeof this.stack === 'function') {
157157
this.stack = [{ handle: this.stack }]
158158
}
159159

160160
if (routeAddedChannel.hasSubscribers) {
161-
routeAddedChannel.publish({ topOfStackFunc: methodWithTrace, layer: this.stack.at(-1) })
161+
routeAddedChannel.publish({ topOfStackFunc: methodWithTrace, layer: this.stack?.at(-1) })
162162
}
163163

164+
const fn = args[0]
165+
164166
// Publish only if this router was mounted by app.use() (prevents early '/sub/...')
165167
if (routeAddedChannel.hasSubscribers && isAppMounted(this) && this.stack?.length > offset) {
166168
// Handle nested router mounting for 'use' method
167-
if (original.name === 'use' && otherArgs.length >= 1) {
169+
if (original.name === 'use' && args.length >= 2) {
168170
const { mountPaths, startIdx } = extractMountPaths(fn)
169171

170172
if (mountPaths.length) {
171173
const parentPaths = getRouterMountPaths(this)
172-
const callArgs = [fn, ...otherArgs]
173174

174-
for (let i = startIdx; i < callArgs.length; i++) {
175-
const nestedRouter = callArgs[i]
175+
for (let i = startIdx; i < args.length; i++) {
176+
const nestedRouter = args[i]
176177

177178
if (!nestedRouter || typeof nestedRouter !== 'function') continue
178179

@@ -206,7 +207,7 @@ function createWrapRouterMethod (name) {
206207
}
207208
}
208209

209-
if (this.stack.length > offset) {
210+
if (this.stack?.length > offset) {
210211
wrapStack(this.stack.slice(offset), extractMatchers(fn))
211212
}
212213

packages/datadog-instrumentations/test/express.spec.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,22 @@ const { expect } = require('chai')
55
const dc = require('dc-polyfill')
66
const { describe, it, beforeEach, before, after } = require('mocha')
77
const sinon = require('sinon')
8+
const semifies = require('semifies')
89

910
const agent = require('../../dd-trace/test/plugins/agent')
1011
const { withVersions } = require('../../dd-trace/test/setup/mocha')
1112

1213
withVersions('express', 'express', version => {
1314
describe('express query instrumentation', () => {
1415
const queryParserReadCh = dc.channel('datadog:query:read:finish')
15-
let port, server, requestBody
16+
let port, server, requestBody, express
1617

1718
before(() => {
1819
return agent.load(['express', 'body-parser'], { client: false })
1920
})
2021

2122
before((done) => {
22-
const express = require(`../../../versions/express@${version}`).get()
23+
express = require(`../../../versions/express@${version}`).get()
2324
const app = express()
2425
app.get('/', (req, res) => {
2526
requestBody()
@@ -73,5 +74,13 @@ withVersions('express', 'express', version => {
7374

7475
queryParserReadCh.unsubscribe(blockRequest)
7576
})
77+
78+
if (semifies(version, '4')) {
79+
// Router does not exist in Express 5
80+
it('should work correctly when router[method] is called without handler', () => {
81+
const router = express.Router()
82+
expect(() => { router.bind('/test') }).to.not.throw()
83+
})
84+
}
7685
})
7786
})

0 commit comments

Comments
 (0)