From 93b19420fc6546732993ace36fbde947962710ee Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Fri, 28 Jul 2023 11:18:21 +0000 Subject: [PATCH 01/12] fix(tracing-internal): Fix express middleware path param parsing --- .../src/node/integrations/express.ts | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index 165494563eb7..9386f4d2eb88 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -64,6 +64,8 @@ type Layer = { handle_request: (req: PatchedRequest, res: ExpressResponse, next: () => void) => void; route?: { path: RouteType | RouteType[] }; path?: string; + regexp?: RegExp; + keys?: [{ name: string, offset: number, optional: boolean }]; }; type RouteType = string | RegExp; @@ -366,6 +368,74 @@ type LayerRoutePathInfo = { numExtraSegments: number; }; + +/** + * Recreate layer.route.path from layer.regexp and layer.keys. + * Works until express.js used package path-to-regexp@0.1.7 + * Or until layer.keys contain offset attribute + * + * @param layer the layer to extract the stringified route from + * + * @returns string in layer.route.path structure 'router/:pathParam' or undefined + */ +const extractOriginalRoute = ({ path, regexp, keys }: Layer): (string | undefined) => { + if(!path || !regexp || !keys || Object.keys(keys).length === 0) { + return undefined; + } + /** + * add d flag for getting indices from regexp result + */ + const pathRegex = new RegExp(regexp, `${regexp.flags}d`); + + const orderedKeys = keys.sort((a, b) => a.offset - b.offset); + + const execResult: any = pathRegex.exec(path); + if(!execResult || !execResult.indices) { + return undefined; + } + /** + * remove first match from regex cause contain whole layer.path + */ + const [, ...paramIndices] = execResult.indices; + + if (paramIndices.length !== orderedKeys.length) { + return undefined; + } + let resultPath = path; + let indexShift = 0; + + /** + * iterate param matches from regexp.exec + */ + paramIndices.forEach(([startOffset, endOffset]: [number, number], index: number) => { + /** + * isolate part before param + */ + const substr1 = resultPath.substring(0, startOffset - indexShift); + /** + * define paramName as replacement in format :pathParam + */ + const replacement = `:${orderedKeys[index].name}`; + + /** + * isolate part after param + */ + const substr2 = resultPath.substring(endOffset - indexShift); + + /** + * recreate original path but with param replacement + */ + resultPath = substr1 + replacement + substr2; + + /** + * calculate new index shift after resultPath was modified + */ + indexShift = indexShift + (endOffset - startOffset - replacement.length); + }) + + return resultPath; +} + /** * Extracts and stringifies the layer's route which can either be a string with parameters (`users/:id`), * a RegEx (`/test/`) or an array of strings and regexes (`['/path1', /\/path[2-5]/, /path/:id]`). Additionally @@ -378,11 +448,18 @@ type LayerRoutePathInfo = { * if the route was an array (defaults to 0). */ function getLayerRoutePathInfo(layer: Layer): LayerRoutePathInfo { - const lrp = layer.route?.path; + let lrp = layer.route?.path; const isRegex = isRegExp(lrp); const isArray = Array.isArray(lrp); + if(!lrp && !isRegex && !isArray) { + /** + * If lrp does not exist try to recreate original layer path from route regexp + */ + lrp = extractOriginalRoute(layer); + } + if (!lrp) { return { isRegex, isArray, numExtraSegments: 0 }; } From 2ee216733f79fe86d760579eb3119ee01baedefc Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Fri, 28 Jul 2023 14:09:50 +0000 Subject: [PATCH 02/12] fix(tracing-internal): Fix lint errors --- .../src/node/integrations/express.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index 9386f4d2eb88..2cd9ecfc7dff 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -65,7 +65,7 @@ type Layer = { route?: { path: RouteType | RouteType[] }; path?: string; regexp?: RegExp; - keys?: [{ name: string, offset: number, optional: boolean }]; + keys?: [{ name: string; offset: number; optional: boolean }]; }; type RouteType = string | RegExp; @@ -368,7 +368,6 @@ type LayerRoutePathInfo = { numExtraSegments: number; }; - /** * Recreate layer.route.path from layer.regexp and layer.keys. * Works until express.js used package path-to-regexp@0.1.7 @@ -378,8 +377,8 @@ type LayerRoutePathInfo = { * * @returns string in layer.route.path structure 'router/:pathParam' or undefined */ -const extractOriginalRoute = ({ path, regexp, keys }: Layer): (string | undefined) => { - if(!path || !regexp || !keys || Object.keys(keys).length === 0) { +const extractOriginalRoute = ({ path, regexp, keys }: Layer): string | undefined => { + if (!path || !regexp || !keys || Object.keys(keys).length === 0) { return undefined; } /** @@ -389,8 +388,11 @@ const extractOriginalRoute = ({ path, regexp, keys }: Layer): (string | undefine const orderedKeys = keys.sort((a, b) => a.offset - b.offset); - const execResult: any = pathRegex.exec(path); - if(!execResult || !execResult.indices) { + /** + * use custom type cause of TS error with missing indices in RegExpExecArray + */ + const execResult = pathRegex.exec(path) as (RegExpExecArray & { indices: [number, number][] }) | null; + if (!execResult || !execResult.indices) { return undefined; } /** @@ -407,7 +409,7 @@ const extractOriginalRoute = ({ path, regexp, keys }: Layer): (string | undefine /** * iterate param matches from regexp.exec */ - paramIndices.forEach(([startOffset, endOffset]: [number, number], index: number) => { + paramIndices.forEach(([startOffset, endOffset], index: number) => { /** * isolate part before param */ @@ -431,10 +433,10 @@ const extractOriginalRoute = ({ path, regexp, keys }: Layer): (string | undefine * calculate new index shift after resultPath was modified */ indexShift = indexShift + (endOffset - startOffset - replacement.length); - }) + }); return resultPath; -} +}; /** * Extracts and stringifies the layer's route which can either be a string with parameters (`users/:id`), @@ -453,7 +455,7 @@ function getLayerRoutePathInfo(layer: Layer): LayerRoutePathInfo { const isRegex = isRegExp(lrp); const isArray = Array.isArray(lrp); - if(!lrp && !isRegex && !isArray) { + if (!lrp && !isRegex && !isArray) { /** * If lrp does not exist try to recreate original layer path from route regexp */ From ac325e93fbaee29dc8f77377da3d1b21dc428fa5 Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Sat, 29 Jul 2023 17:53:05 +0000 Subject: [PATCH 03/12] fix(tracing-internal): Add test for middlelayer path param --- .../middle-layer-parameterized/server.ts | 38 +++++++++++++++++++ .../middle-layer-parameterized/test.ts | 10 +++++ packages/node/src/requestdata.ts | 6 ++- packages/types/src/polymorphics.ts | 1 + 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts create mode 100644 packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts diff --git a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts new file mode 100644 index 000000000000..427825cf85cb --- /dev/null +++ b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts @@ -0,0 +1,38 @@ +import * as Sentry from '@sentry/node'; +import * as Tracing from '@sentry/tracing'; +import cors from 'cors'; +import express from 'express'; + +const app = express(); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + // eslint-disable-next-line deprecation/deprecation + integrations: [new Sentry.Integrations.Http({ tracing: true }), new Tracing.Integrations.Express({ app })], + tracesSampleRate: 1.0, +}); + +app.use(Sentry.Handlers.requestHandler()); +app.use(Sentry.Handlers.tracingHandler()); + +app.use(cors()); + +const APIv1 = express.Router(); + +APIv1.use( + '/users/:userId', + APIv1.get('/posts/:postId', (_req, res) => { + Sentry.captureMessage('Custom Message'); + return res.send('Success'); + }), +); + +const root = express.Router(); + +app.use('/api/v1', APIv1); +app.use('/api', root); + +app.use(Sentry.Handlers.errorHandler()); + +export default app; diff --git a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts new file mode 100644 index 000000000000..d6f1a86552b7 --- /dev/null +++ b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts @@ -0,0 +1,10 @@ +import { assertSentryEvent, TestEnv } from '../../../../utils/index'; + +test('should construct correct url with multiple parameterized routers, when param is also contain in middle layer route', async () => { + const env = await TestEnv.init(__dirname, `${__dirname}/server.ts`); + const event = await env.getEnvelopeRequest({ url: env.url.replace('test', 'api/v1/users/123/posts/456') }); + assertSentryEvent(event[2] as any, { + message: 'Custom Message', + transaction: 'GET /api/v1/users/:userId/posts/:postId', + }); +}); diff --git a/packages/node/src/requestdata.ts b/packages/node/src/requestdata.ts index a0d5aed926a9..d7669a72a046 100644 --- a/packages/node/src/requestdata.ts +++ b/packages/node/src/requestdata.ts @@ -109,7 +109,11 @@ function extractTransaction(req: PolymorphicRequest, type: boolean | Transaction } case 'methodPath': default: { - return extractPathForTransaction(req, { path: true, method: true })[0]; + /** + * if exist _reconstructedRoute return that path instead of route.path + */ + const customRoute = req._reconstructedRoute ? req._reconstructedRoute : undefined; + return extractPathForTransaction(req, { path: true, method: true, customRoute })[0]; } } } diff --git a/packages/types/src/polymorphics.ts b/packages/types/src/polymorphics.ts index e6fcac8a682f..88abf7770b2c 100644 --- a/packages/types/src/polymorphics.ts +++ b/packages/types/src/polymorphics.ts @@ -75,4 +75,5 @@ type ExpressRequest = NodeRequest & { user?: { [key: string]: any; }; + _reconstructedRoute?: string; }; From 731cec44ef26da1600ee5e8237c4dead60e29f95 Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Mon, 21 Aug 2023 06:47:36 +0000 Subject: [PATCH 04/12] fix(tracing-internal): remove useless cors from test --- .../multiple-routers/middle-layer-parameterized/server.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts index 427825cf85cb..5c1f1113ed8f 100644 --- a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts +++ b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts @@ -16,8 +16,6 @@ Sentry.init({ app.use(Sentry.Handlers.requestHandler()); app.use(Sentry.Handlers.tracingHandler()); -app.use(cors()); - const APIv1 = express.Router(); APIv1.use( From c456133bfc5ae02ba4546140d2cda8ccf7cbca51 Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Mon, 21 Aug 2023 13:24:57 +0000 Subject: [PATCH 05/12] fix(tracing-internal): fix req._reconstructedRoute param if express used multiple middlewares that match request url --- .../multiple-routers/complex-router/server.ts | 37 +++++++++++++++++++ .../multiple-routers/complex-router/test.ts | 10 +++++ 2 files changed, 47 insertions(+) create mode 100644 packages/node-integration-tests/suites/express/multiple-routers/complex-router/server.ts create mode 100644 packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts diff --git a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/server.ts b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/server.ts new file mode 100644 index 000000000000..f54ceff7ce8d --- /dev/null +++ b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/server.ts @@ -0,0 +1,37 @@ +import * as Sentry from '@sentry/node'; +import * as Tracing from '@sentry/tracing'; +import cors from 'cors'; +import express from 'express'; + +const app = express(); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + // eslint-disable-next-line deprecation/deprecation + integrations: [new Sentry.Integrations.Http({ tracing: true }), new Tracing.Integrations.Express({ app })], + tracesSampleRate: 1.0, +}); + +app.use(Sentry.Handlers.requestHandler()); +app.use(Sentry.Handlers.tracingHandler()); + +const APIv1 = express.Router(); + +APIv1.use( + '/users/:userId', + APIv1.get('/posts/:postId', (_req, res) => { + Sentry.captureMessage('Custom Message'); + return res.send('Success'); + }), +); + +const router = express.Router(); + +app.use('/api', router); +app.use('/api/api/v1', APIv1.use('/sub-router', APIv1)); + + +app.use(Sentry.Handlers.errorHandler()); + +export default app; diff --git a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts new file mode 100644 index 000000000000..bbca8cdd1d6f --- /dev/null +++ b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts @@ -0,0 +1,10 @@ +import { assertSentryEvent, TestEnv } from '../../../../utils/index'; + +test('test', async () => { + const env = await TestEnv.init(__dirname, `${__dirname}/server.ts`); + const event = await env.getEnvelopeRequest({ url: env.url.replace('test', 'api/api/v1/sub-router/users/123/posts/456') }); + assertSentryEvent(event[2] as any, { + message: 'Custom Message', + transaction: 'GET /api/api/v1/sub-router/users/:userId/posts/:postId', + }); +}); From a242cc7bbcf8d6348bf3b7a80b0fa244773b13fe Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Mon, 21 Aug 2023 13:41:09 +0000 Subject: [PATCH 06/12] fix(tracing-internal): fix eslint errors --- .../express/multiple-routers/complex-router/server.ts | 2 -- .../suites/express/multiple-routers/complex-router/test.ts | 6 ++++-- .../multiple-routers/middle-layer-parameterized/server.ts | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/server.ts b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/server.ts index f54ceff7ce8d..6083d1a85f91 100644 --- a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/server.ts +++ b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/server.ts @@ -1,6 +1,5 @@ import * as Sentry from '@sentry/node'; import * as Tracing from '@sentry/tracing'; -import cors from 'cors'; import express from 'express'; const app = express(); @@ -31,7 +30,6 @@ const router = express.Router(); app.use('/api', router); app.use('/api/api/v1', APIv1.use('/sub-router', APIv1)); - app.use(Sentry.Handlers.errorHandler()); export default app; diff --git a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts index bbca8cdd1d6f..78ae5de846b0 100644 --- a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts +++ b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts @@ -1,8 +1,10 @@ import { assertSentryEvent, TestEnv } from '../../../../utils/index'; -test('test', async () => { +test('should construct correct url with multiple parameterized routers, when param is also contain in middle layer route and express used multiple middlewares with route', async () => { const env = await TestEnv.init(__dirname, `${__dirname}/server.ts`); - const event = await env.getEnvelopeRequest({ url: env.url.replace('test', 'api/api/v1/sub-router/users/123/posts/456') }); + const event = await env.getEnvelopeRequest({ + url: env.url.replace('test', 'api/api/v1/sub-router/users/123/posts/456'), + }); assertSentryEvent(event[2] as any, { message: 'Custom Message', transaction: 'GET /api/api/v1/sub-router/users/:userId/posts/:postId', diff --git a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts index 5c1f1113ed8f..19cb3c544bde 100644 --- a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts +++ b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/server.ts @@ -1,6 +1,5 @@ import * as Sentry from '@sentry/node'; import * as Tracing from '@sentry/tracing'; -import cors from 'cors'; import express from 'express'; const app = express(); From 5736c28dfa120d8adc06c6e1ab026666b98fc203 Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Tue, 5 Sep 2023 18:30:10 +0000 Subject: [PATCH 07/12] fix(tracing-internal) fix duplicating route segment in _reconstructRoute param --- packages/node/src/requestdata.ts | 4 +-- .../src/node/integrations/express.ts | 36 +++++++++++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/node/src/requestdata.ts b/packages/node/src/requestdata.ts index d7669a72a046..ff095c827658 100644 --- a/packages/node/src/requestdata.ts +++ b/packages/node/src/requestdata.ts @@ -109,9 +109,7 @@ function extractTransaction(req: PolymorphicRequest, type: boolean | Transaction } case 'methodPath': default: { - /** - * if exist _reconstructedRoute return that path instead of route.path - */ + // if exist _reconstructedRoute return that path instead of route.path const customRoute = req._reconstructedRoute ? req._reconstructedRoute : undefined; return extractPathForTransaction(req, { path: true, method: true, customRoute })[0]; } diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index b51aa605d04d..cbe3dfffe4e9 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -319,8 +319,33 @@ function instrumentRouter(appOrRouter: ExpressRouter): void { req._hasParameters = true; } + /** + * prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path + * example: + * original url: /api/v1/1234 + * prevent: /api/api/v1/:userId + * router structure + * /api -> middleware + * /api/v1 -> middleware + * /1234 -> endpoint with param :userId + * final _reconstructedRoute is /api/v1/:userId + */ + const originalUrlSplit = req.originalUrl?.split('/').filter(v => !!v); + let tempCounter = 0; + const currentOffset = req._reconstructedRoute.split('/').filter(v => !!v).length || 0; + const layerPath = layer.path + ?.split('/') + .filter(segment => { + if (originalUrlSplit?.[currentOffset + tempCounter] === segment) { + tempCounter += 1; + return true; + } + return false; + }) + .join('/'); + // Otherwise, the hardcoded path (i.e. a partial route without params) is stored in layer.path - const partialRoute = layerRoutePath || layer.path || ''; + const partialRoute = layerRoutePath || layerPath || ''; // Normalize the partial route so that it doesn't contain leading or trailing slashes // and exclude empty or '*' wildcard routes. @@ -375,19 +400,18 @@ type LayerRoutePathInfo = { /** * Recreate layer.route.path from layer.regexp and layer.keys. * Works until express.js used package path-to-regexp@0.1.7 - * Or until layer.keys contain offset attribute + * or until layer.keys contain offset attribute * * @param layer the layer to extract the stringified route from * * @returns string in layer.route.path structure 'router/:pathParam' or undefined */ const extractOriginalRoute = ({ path, regexp, keys }: Layer): string | undefined => { - if (!path || !regexp || !keys || Object.keys(keys).length === 0) { + if (!path || !regexp || !keys || Object.keys(keys).length === 0 || !keys[0]?.offset) { return undefined; } - /** - * add d flag for getting indices from regexp result - */ + + // add d flag for getting indices from regexp result const pathRegex = new RegExp(regexp, `${regexp.flags}d`); const orderedKeys = keys.sort((a, b) => a.offset - b.offset); From 81ef719637140584301eb118b51e5ac81239388a Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Fri, 15 Sep 2023 21:39:00 +0200 Subject: [PATCH 08/12] fix(tracing-internal): add unit test for preventDuplicateSegments fn --- .../src/node/integrations/express.ts | 43 ++++++++---- .../test/node/express.test.ts | 68 +++++++++++++++++++ 2 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 packages/tracing-internal/test/node/express.test.ts diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index cbe3dfffe4e9..71b95fce1325 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -330,20 +330,7 @@ function instrumentRouter(appOrRouter: ExpressRouter): void { * /1234 -> endpoint with param :userId * final _reconstructedRoute is /api/v1/:userId */ - const originalUrlSplit = req.originalUrl?.split('/').filter(v => !!v); - let tempCounter = 0; - const currentOffset = req._reconstructedRoute.split('/').filter(v => !!v).length || 0; - const layerPath = layer.path - ?.split('/') - .filter(segment => { - if (originalUrlSplit?.[currentOffset + tempCounter] === segment) { - tempCounter += 1; - return true; - } - return false; - }) - .join('/'); - + const layerPath = preventDuplicateSegments(req.originalUrl, req._reconstructedRoute, layer.path) // Otherwise, the hardcoded path (i.e. a partial route without params) is stored in layer.path const partialRoute = layerRoutePath || layerPath || ''; @@ -483,7 +470,7 @@ function getLayerRoutePathInfo(layer: Layer): LayerRoutePathInfo { const isRegex = isRegExp(lrp); const isArray = Array.isArray(lrp); - if (!lrp && !isRegex && !isArray) { + if (!lrp) { /** * If lrp does not exist try to recreate original layer path from route regexp */ @@ -527,3 +514,29 @@ function getLayerRoutePathString(isArray: boolean, lrp?: RouteType | RouteType[] } return lrp && lrp.toString(); } + + + +/** + * remove duplicate segment contain in layerPath against _reconstructedRoute, + * and return only unique segment that can be added into _reconstructedRoute + */ +export function preventDuplicateSegments (originalUrl?: string, _reconstructedRoute?: string, layerPath?: string) { + const originalUrlSplit = originalUrl?.split('/').filter(v => !!v); + let tempCounter = 0; + const currentOffset = _reconstructedRoute?.split('/').filter(v => !!v).length || 0; + const result = layerPath + ?.split('/') + .filter(segment => { + console.log(segment, originalUrlSplit?.[currentOffset + tempCounter]) + + if (originalUrlSplit?.[currentOffset + tempCounter] === segment) { + tempCounter += 1; + return true; + } + return false; + }) + .join('/'); + console.log(result) + return result +} diff --git a/packages/tracing-internal/test/node/express.test.ts b/packages/tracing-internal/test/node/express.test.ts new file mode 100644 index 000000000000..4600c5b29bb9 --- /dev/null +++ b/packages/tracing-internal/test/node/express.test.ts @@ -0,0 +1,68 @@ +import { extractLayerPath } from '../../src/node/integrations/express'; + +/** + * prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path + * example: + * original url: /api/v1/1234 + * prevent: /api/api/v1/:userId + * router structure + * /api -> middleware + * /api/v1 -> middleware + * /1234 -> endpoint with param :userId + * final _reconstructedRoute is /api/v1/:userId + */ +describe('unit Test for extractLayerPath', () => { + + it('should return api segment', () => { + const originalUrl = '/api/v1/1234'; + const reconstructedRoute = ''; + const layerPath = '/api'; + const result = extractLayerPath(originalUrl, reconstructedRoute, layerPath); + expect(result).toBe('api'); + + }); + + it('should prevent duplicate segment api', () => { + const originalUrl = '/api/v1/1234'; + const reconstructedRoute = '/api'; + const layerPath = '/api/v1'; + const result = extractLayerPath(originalUrl, reconstructedRoute, layerPath); + expect(result).toBe('v1'); + + }); + + it('should prevent duplicate segment v1', () => { + const originalUrl = '/api/v1/1234'; + const reconstructedRoute = '/api/v1'; + const layerPath = '/v1/1234'; + const result1 = extractLayerPath(originalUrl, reconstructedRoute, layerPath); + expect(result1).toBe('1234'); + + }); + +}) +describe('extractLayerPath should handle empty input gracefully', () => { + it('Empty input values', () => { + + expect(extractLayerPath()).toBeUndefined(); + + }); + + it('Empty originalUrl', () => { + + expect(extractLayerPath('', '/api/v1/1234', '/api/api/v1/1234')).toBe(''); + + }); + + it('Empty reconstructedRoute', () => { + + expect(extractLayerPath('/api/v1/1234', '', '/api/api/v1/1234')).toBe('api/v1/1234'); + }); + + it('Empty layerPath', () => { + + expect(extractLayerPath('/api/v1/1234', '/api/v1/1234', '')).toBe(''); + }); + +}) + From aa23c412f5fb5dd681928ed0b03d1900011c5d44 Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Fri, 15 Sep 2023 21:47:14 +0200 Subject: [PATCH 09/12] fix(tracing-internal): call preventDuplicateSegments only when it is necessary --- .../src/node/integrations/express.ts | 44 ++++++++++--------- .../test/node/express.test.ts | 37 +++++----------- 2 files changed, 36 insertions(+), 45 deletions(-) diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index 71b95fce1325..f9349d22071c 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -319,20 +319,25 @@ function instrumentRouter(appOrRouter: ExpressRouter): void { req._hasParameters = true; } - /** - * prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path - * example: - * original url: /api/v1/1234 - * prevent: /api/api/v1/:userId - * router structure - * /api -> middleware - * /api/v1 -> middleware - * /1234 -> endpoint with param :userId - * final _reconstructedRoute is /api/v1/:userId - */ - const layerPath = preventDuplicateSegments(req.originalUrl, req._reconstructedRoute, layer.path) // Otherwise, the hardcoded path (i.e. a partial route without params) is stored in layer.path - const partialRoute = layerRoutePath || layerPath || ''; + let partialRoute; + + if (layerRoutePath) { + partialRoute = layerRoutePath; + } else { + /** + * prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path + * example: + * original url: /api/v1/1234 + * prevent: /api/api/v1/:userId + * router structure + * /api -> middleware + * /api/v1 -> middleware + * /1234 -> endpoint with param :userId + * final _reconstructedRoute is /api/v1/:userId + */ + partialRoute = preventDuplicateSegments(req.originalUrl, req._reconstructedRoute, layer.path) || ''; + } // Normalize the partial route so that it doesn't contain leading or trailing slashes // and exclude empty or '*' wildcard routes. @@ -515,21 +520,21 @@ function getLayerRoutePathString(isArray: boolean, lrp?: RouteType | RouteType[] return lrp && lrp.toString(); } - - /** * remove duplicate segment contain in layerPath against _reconstructedRoute, * and return only unique segment that can be added into _reconstructedRoute */ -export function preventDuplicateSegments (originalUrl?: string, _reconstructedRoute?: string, layerPath?: string) { +export function preventDuplicateSegments( + originalUrl?: string, + _reconstructedRoute?: string, + layerPath?: string, +): string | undefined { const originalUrlSplit = originalUrl?.split('/').filter(v => !!v); let tempCounter = 0; const currentOffset = _reconstructedRoute?.split('/').filter(v => !!v).length || 0; const result = layerPath ?.split('/') .filter(segment => { - console.log(segment, originalUrlSplit?.[currentOffset + tempCounter]) - if (originalUrlSplit?.[currentOffset + tempCounter] === segment) { tempCounter += 1; return true; @@ -537,6 +542,5 @@ export function preventDuplicateSegments (originalUrl?: string, _reconstructedRo return false; }) .join('/'); - console.log(result) - return result + return result; } diff --git a/packages/tracing-internal/test/node/express.test.ts b/packages/tracing-internal/test/node/express.test.ts index 4600c5b29bb9..ba99e4a10928 100644 --- a/packages/tracing-internal/test/node/express.test.ts +++ b/packages/tracing-internal/test/node/express.test.ts @@ -1,25 +1,23 @@ import { extractLayerPath } from '../../src/node/integrations/express'; /** - * prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path - * example: - * original url: /api/v1/1234 - * prevent: /api/api/v1/:userId - * router structure - * /api -> middleware - * /api/v1 -> middleware - * /1234 -> endpoint with param :userId - * final _reconstructedRoute is /api/v1/:userId - */ + * prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path + * example: + * original url: /api/v1/1234 + * prevent: /api/api/v1/:userId + * router structure + * /api -> middleware + * /api/v1 -> middleware + * /1234 -> endpoint with param :userId + * final _reconstructedRoute is /api/v1/:userId + */ describe('unit Test for extractLayerPath', () => { - it('should return api segment', () => { const originalUrl = '/api/v1/1234'; const reconstructedRoute = ''; const layerPath = '/api'; const result = extractLayerPath(originalUrl, reconstructedRoute, layerPath); expect(result).toBe('api'); - }); it('should prevent duplicate segment api', () => { @@ -28,7 +26,6 @@ describe('unit Test for extractLayerPath', () => { const layerPath = '/api/v1'; const result = extractLayerPath(originalUrl, reconstructedRoute, layerPath); expect(result).toBe('v1'); - }); it('should prevent duplicate segment v1', () => { @@ -37,32 +34,22 @@ describe('unit Test for extractLayerPath', () => { const layerPath = '/v1/1234'; const result1 = extractLayerPath(originalUrl, reconstructedRoute, layerPath); expect(result1).toBe('1234'); - }); - -}) +}); describe('extractLayerPath should handle empty input gracefully', () => { it('Empty input values', () => { - expect(extractLayerPath()).toBeUndefined(); - }); it('Empty originalUrl', () => { - expect(extractLayerPath('', '/api/v1/1234', '/api/api/v1/1234')).toBe(''); - }); it('Empty reconstructedRoute', () => { - expect(extractLayerPath('/api/v1/1234', '', '/api/api/v1/1234')).toBe('api/v1/1234'); }); it('Empty layerPath', () => { - expect(extractLayerPath('/api/v1/1234', '/api/v1/1234', '')).toBe(''); }); - -}) - +}); From 16ff8fa55e5b4f00e3f19fad3f1a0755ccc5e6a2 Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Thu, 5 Oct 2023 14:46:59 +0000 Subject: [PATCH 10/12] fix(tracing-internal): add regex indices polyfill to make nodejs compatibility from 8+ --- packages/tracing-internal/package.json | 1 + .../src/node/integrations/express.ts | 9 ++++----- yarn.lock | 12 ++++++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/tracing-internal/package.json b/packages/tracing-internal/package.json index 4818702c81bb..6942c4fc67a0 100644 --- a/packages/tracing-internal/package.json +++ b/packages/tracing-internal/package.json @@ -26,6 +26,7 @@ "@sentry/core": "7.73.0", "@sentry/types": "7.73.0", "@sentry/utils": "7.73.0", + "regexp-match-indices": "1.0.2", "tslib": "^2.4.1 || ^1.9.3" }, "devDependencies": { diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index f9349d22071c..5a7d5a6dcbd8 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -7,7 +7,7 @@ import { logger, stripUrlQueryAndFragment, } from '@sentry/utils'; - +import * as execWithIndices from 'regexp-match-indices'; import { shouldDisableAutoInstrumentation } from './utils/node-utils'; type Method = @@ -403,15 +403,14 @@ const extractOriginalRoute = ({ path, regexp, keys }: Layer): string | undefined return undefined; } - // add d flag for getting indices from regexp result - const pathRegex = new RegExp(regexp, `${regexp.flags}d`); const orderedKeys = keys.sort((a, b) => a.offset - b.offset); /** - * use custom type cause of TS error with missing indices in RegExpExecArray + * use execWithIndices polyfill instead of native RegExp d flag because it has to be compatible with node 8+ */ - const execResult = pathRegex.exec(path) as (RegExpExecArray & { indices: [number, number][] }) | null; + const execResult = execWithIndices(regexp, path); + if (!execResult || !execResult.indices) { return undefined; } diff --git a/yarn.lock b/yarn.lock index 694880f6b6df..8f9a6a756f4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24058,6 +24058,18 @@ regex-parser@^2.2.11: resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== +regexp-match-indices@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz#cf20054a6f7d5b3e116a701a7b00f82889d10da6" + integrity sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ== + dependencies: + regexp-tree "^0.1.11" + +regexp-tree@^0.1.11: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" From df3faf604efcff7243fdce9228c2f05e6150d3bc Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Fri, 13 Oct 2023 18:46:00 +0000 Subject: [PATCH 11/12] remove regex d flag polyfill and aply fix only if node is 16+add new unit test for extractOriginalRoute fn --- .../multiple-routers/complex-router/test.ts | 23 ++++++-- .../middle-layer-parameterized/test.ts | 26 +++++++-- .../src/node/integrations/express.ts | 39 ++++++++----- .../test/node/express.test.ts | 56 +++++++++++++++---- yarn.lock | 12 ---- 5 files changed, 112 insertions(+), 44 deletions(-) diff --git a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts index 78ae5de846b0..1425bb282a98 100644 --- a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts +++ b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts @@ -4,9 +4,24 @@ test('should construct correct url with multiple parameterized routers, when par const env = await TestEnv.init(__dirname, `${__dirname}/server.ts`); const event = await env.getEnvelopeRequest({ url: env.url.replace('test', 'api/api/v1/sub-router/users/123/posts/456'), + envelopeType: 'transaction', }); - assertSentryEvent(event[2] as any, { - message: 'Custom Message', - transaction: 'GET /api/api/v1/sub-router/users/:userId/posts/:postId', - }); + // parse node.js major version + const [major] = process.versions.node.split('.').map(Number); + // Split test result base on major node version because regex d flag is support from node 16+ + if (major >= 16) { + assertSentryEvent(event[2] as any, { + transaction: 'GET /api/api/v1/sub-router/users/:userId/posts/:postId', + transaction_info: { + source: 'route', + }, + }); + } else { + assertSentryEvent(event[2] as any, { + transaction: 'GET /api/api/v1/sub-router/users/:userId/posts/456', + transaction_info: { + source: 'route', + }, + }); + } }); diff --git a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts index d6f1a86552b7..4dafbc381367 100644 --- a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts +++ b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts @@ -2,9 +2,27 @@ import { assertSentryEvent, TestEnv } from '../../../../utils/index'; test('should construct correct url with multiple parameterized routers, when param is also contain in middle layer route', async () => { const env = await TestEnv.init(__dirname, `${__dirname}/server.ts`); - const event = await env.getEnvelopeRequest({ url: env.url.replace('test', 'api/v1/users/123/posts/456') }); - assertSentryEvent(event[2] as any, { - message: 'Custom Message', - transaction: 'GET /api/v1/users/:userId/posts/:postId', + const event = await env.getEnvelopeRequest({ + url: env.url.replace('test', 'api/v1/users/123/posts/456'), + envelopeType: 'transaction', }); + + // parse node.js major version + const [major] = process.versions.node.split('.').map(Number); + // Split test result base on major node version because regex d flag is support from node 16+ + if (major >= 16) { + assertSentryEvent(event[2] as any, { + transaction: 'GET /api/v1/users/:userId/posts/:postId', + transaction_info: { + source: 'route', + }, + }); + } else { + assertSentryEvent(event[2] as any, { + transaction: 'GET /api/v1/users/:userId/posts/456', + transaction_info: { + source: 'route', + }, + }); + } }); diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index 5a7d5a6dcbd8..4327f11c5ea7 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -7,7 +7,7 @@ import { logger, stripUrlQueryAndFragment, } from '@sentry/utils'; -import * as execWithIndices from 'regexp-match-indices'; + import { shouldDisableAutoInstrumentation } from './utils/node-utils'; type Method = @@ -65,7 +65,7 @@ type Layer = { route?: { path: RouteType | RouteType[] }; path?: string; regexp?: RegExp; - keys?: [{ name: string; offset: number; optional: boolean }]; + keys?: { name: string; offset: number; optional: boolean }[]; }; type RouteType = string | RegExp; @@ -398,18 +398,23 @@ type LayerRoutePathInfo = { * * @returns string in layer.route.path structure 'router/:pathParam' or undefined */ -const extractOriginalRoute = ({ path, regexp, keys }: Layer): string | undefined => { +export const extractOriginalRoute = ( + path?: Layer['path'], + regexp?: Layer['regexp'], + keys?: Layer['keys'], +): string | undefined => { if (!path || !regexp || !keys || Object.keys(keys).length === 0 || !keys[0]?.offset) { return undefined; } - const orderedKeys = keys.sort((a, b) => a.offset - b.offset); + // add d flag for getting indices from regexp result + const pathRegex = new RegExp(regexp, `${regexp.flags}d`); /** - * use execWithIndices polyfill instead of native RegExp d flag because it has to be compatible with node 8+ + * use custom type cause of TS error with missing indices in RegExpExecArray */ - const execResult = execWithIndices(regexp, path); + const execResult = pathRegex.exec(path) as (RegExpExecArray & { indices: [number, number][] }) | null; if (!execResult || !execResult.indices) { return undefined; @@ -475,10 +480,16 @@ function getLayerRoutePathInfo(layer: Layer): LayerRoutePathInfo { const isArray = Array.isArray(lrp); if (!lrp) { - /** - * If lrp does not exist try to recreate original layer path from route regexp - */ - lrp = extractOriginalRoute(layer); + // parse node.js major version + const [major] = process.versions.node.split('.').map(Number); + + // allow call extractOriginalRoute only if node version support Regex d flag, node 16+ + if (major >= 16) { + /** + * If lrp does not exist try to recreate original layer path from route regexp + */ + lrp = extractOriginalRoute(layer.path, layer.regexp, layer.keys); + } } if (!lrp) { @@ -520,17 +531,17 @@ function getLayerRoutePathString(isArray: boolean, lrp?: RouteType | RouteType[] } /** - * remove duplicate segment contain in layerPath against _reconstructedRoute, - * and return only unique segment that can be added into _reconstructedRoute + * remove duplicate segment contain in layerPath against reconstructedRoute, + * and return only unique segment that can be added into reconstructedRoute */ export function preventDuplicateSegments( originalUrl?: string, - _reconstructedRoute?: string, + reconstructedRoute?: string, layerPath?: string, ): string | undefined { const originalUrlSplit = originalUrl?.split('/').filter(v => !!v); let tempCounter = 0; - const currentOffset = _reconstructedRoute?.split('/').filter(v => !!v).length || 0; + const currentOffset = reconstructedRoute?.split('/').filter(v => !!v).length || 0; const result = layerPath ?.split('/') .filter(segment => { diff --git a/packages/tracing-internal/test/node/express.test.ts b/packages/tracing-internal/test/node/express.test.ts index ba99e4a10928..e9f4df236b33 100644 --- a/packages/tracing-internal/test/node/express.test.ts +++ b/packages/tracing-internal/test/node/express.test.ts @@ -1,4 +1,4 @@ -import { extractLayerPath } from '../../src/node/integrations/express'; +import { extractOriginalRoute, preventDuplicateSegments } from '../../src/node/integrations/express'; /** * prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path @@ -11,12 +11,12 @@ import { extractLayerPath } from '../../src/node/integrations/express'; * /1234 -> endpoint with param :userId * final _reconstructedRoute is /api/v1/:userId */ -describe('unit Test for extractLayerPath', () => { +describe('unit Test for preventDuplicateSegments', () => { it('should return api segment', () => { const originalUrl = '/api/v1/1234'; const reconstructedRoute = ''; const layerPath = '/api'; - const result = extractLayerPath(originalUrl, reconstructedRoute, layerPath); + const result = preventDuplicateSegments(originalUrl, reconstructedRoute, layerPath); expect(result).toBe('api'); }); @@ -24,7 +24,7 @@ describe('unit Test for extractLayerPath', () => { const originalUrl = '/api/v1/1234'; const reconstructedRoute = '/api'; const layerPath = '/api/v1'; - const result = extractLayerPath(originalUrl, reconstructedRoute, layerPath); + const result = preventDuplicateSegments(originalUrl, reconstructedRoute, layerPath); expect(result).toBe('v1'); }); @@ -32,24 +32,60 @@ describe('unit Test for extractLayerPath', () => { const originalUrl = '/api/v1/1234'; const reconstructedRoute = '/api/v1'; const layerPath = '/v1/1234'; - const result1 = extractLayerPath(originalUrl, reconstructedRoute, layerPath); + const result1 = preventDuplicateSegments(originalUrl, reconstructedRoute, layerPath); expect(result1).toBe('1234'); }); }); -describe('extractLayerPath should handle empty input gracefully', () => { +describe('preventDuplicateSegments should handle empty input gracefully', () => { it('Empty input values', () => { - expect(extractLayerPath()).toBeUndefined(); + expect(preventDuplicateSegments()).toBeUndefined(); }); it('Empty originalUrl', () => { - expect(extractLayerPath('', '/api/v1/1234', '/api/api/v1/1234')).toBe(''); + expect(preventDuplicateSegments('', '/api/v1/1234', '/api/api/v1/1234')).toBe(''); }); it('Empty reconstructedRoute', () => { - expect(extractLayerPath('/api/v1/1234', '', '/api/api/v1/1234')).toBe('api/v1/1234'); + expect(preventDuplicateSegments('/api/v1/1234', '', '/api/api/v1/1234')).toBe('api/v1/1234'); }); it('Empty layerPath', () => { - expect(extractLayerPath('/api/v1/1234', '/api/v1/1234', '')).toBe(''); + expect(preventDuplicateSegments('/api/v1/1234', '/api/v1/1234', '')).toBe(''); }); }); + +// parse node.js major version +const [major] = process.versions.node.split('.').map(Number); +// Test this funciton only if node is 16+ because regex d flag is support from node 16+ +if (major >= 16) { + describe('extractOriginalRoute', () => { + it('should return undefined if path, regexp, or keys are missing', () => { + expect(extractOriginalRoute('/example')).toBeUndefined(); + expect(extractOriginalRoute('/example', /test/)).toBeUndefined(); + }); + + it('should return undefined if keys do not contain an offset property', () => { + const path = '/example'; + const regex = /example/; + const key = { name: 'param1', offset: 0, optional: false }; + expect(extractOriginalRoute(path, regex, [key])).toBeUndefined(); + }); + + it('should return the original route path when valid inputs are provided', () => { + const path = '/router/123'; + const regex = /^\/router\/(\d+)$/; + const keys = [{ name: 'pathParam', offset: 8, optional: false }]; + expect(extractOriginalRoute(path, regex, keys)).toBe('/router/:pathParam'); + }); + + it('should handle multiple parameters in the route', () => { + const path = '/user/42/profile/username'; + const regex = /^\/user\/(\d+)\/profile\/(\w+)$/; + const keys = [ + { name: 'userId', offset: 6, optional: false }, + { name: 'username', offset: 17, optional: false }, + ]; + expect(extractOriginalRoute(path, regex, keys)).toBe('/user/:userId/profile/:username'); + }); + }); +} diff --git a/yarn.lock b/yarn.lock index 90ca50570e6e..f64756e09026 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25891,18 +25891,6 @@ regex-parser@^2.2.11: resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== -regexp-match-indices@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz#cf20054a6f7d5b3e116a701a7b00f82889d10da6" - integrity sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ== - dependencies: - regexp-tree "^0.1.11" - -regexp-tree@^0.1.11: - version "0.1.27" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" - integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== - regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" From 740ef637f3fcca2ae9750b25c46ac9d1f6de85b1 Mon Sep 17 00:00:00 2001 From: Lubomir Igonda Date: Sat, 14 Oct 2023 05:37:22 +0000 Subject: [PATCH 12/12] fix(tracing-internal): Fix tests for node <=14 --- .../suites/express/multiple-routers/complex-router/test.ts | 2 +- .../express/multiple-routers/middle-layer-parameterized/test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts index 1425bb282a98..b8079bfdc0ac 100644 --- a/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts +++ b/packages/node-integration-tests/suites/express/multiple-routers/complex-router/test.ts @@ -18,7 +18,7 @@ test('should construct correct url with multiple parameterized routers, when par }); } else { assertSentryEvent(event[2] as any, { - transaction: 'GET /api/api/v1/sub-router/users/:userId/posts/456', + transaction: 'GET /api/api/v1/sub-router/users/123/posts/:postId', transaction_info: { source: 'route', }, diff --git a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts index 4dafbc381367..3527cce5c3a6 100644 --- a/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts +++ b/packages/node-integration-tests/suites/express/multiple-routers/middle-layer-parameterized/test.ts @@ -19,7 +19,7 @@ test('should construct correct url with multiple parameterized routers, when par }); } else { assertSentryEvent(event[2] as any, { - transaction: 'GET /api/v1/users/:userId/posts/456', + transaction: 'GET /api/v1/users/123/posts/:postId', transaction_info: { source: 'route', },