From 7a21af777abffed2437ad7009705948c4dbcc1c1 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Wed, 7 May 2025 19:07:39 +0200 Subject: [PATCH 1/4] feat(node): Add `maxRequestBodySize` --- .../with-http/{ => base}/instrument.mjs | 0 .../express/with-http/{ => base}/scenario.mjs | 0 .../express/with-http/{ => base}/test.ts | 0 .../maxRequestBodySize/generatePayload.ts | 35 +++ .../maxRequestBodySize/instrument-always.mjs | 10 + .../maxRequestBodySize/instrument-default.mjs | 9 + .../maxRequestBodySize/instrument-medium.mjs | 10 + .../maxRequestBodySize/instrument-none.mjs | 10 + .../maxRequestBodySize/instrument-small.mjs | 10 + .../with-http/maxRequestBodySize/scenario.mjs | 23 ++ .../with-http/maxRequestBodySize/test.ts | 278 ++++++++++++++++++ .../http/SentryHttpInstrumentation.ts | 55 +++- packages/node/src/integrations/http/index.ts | 16 + 13 files changed, 448 insertions(+), 8 deletions(-) rename dev-packages/node-integration-tests/suites/express/with-http/{ => base}/instrument.mjs (100%) rename dev-packages/node-integration-tests/suites/express/with-http/{ => base}/scenario.mjs (100%) rename dev-packages/node-integration-tests/suites/express/with-http/{ => base}/test.ts (100%) create mode 100644 dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/generatePayload.ts create mode 100644 dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-always.mjs create mode 100644 dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-default.mjs create mode 100644 dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-medium.mjs create mode 100644 dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs create mode 100644 dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-small.mjs create mode 100644 dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs create mode 100644 dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts diff --git a/dev-packages/node-integration-tests/suites/express/with-http/instrument.mjs b/dev-packages/node-integration-tests/suites/express/with-http/base/instrument.mjs similarity index 100% rename from dev-packages/node-integration-tests/suites/express/with-http/instrument.mjs rename to dev-packages/node-integration-tests/suites/express/with-http/base/instrument.mjs diff --git a/dev-packages/node-integration-tests/suites/express/with-http/scenario.mjs b/dev-packages/node-integration-tests/suites/express/with-http/base/scenario.mjs similarity index 100% rename from dev-packages/node-integration-tests/suites/express/with-http/scenario.mjs rename to dev-packages/node-integration-tests/suites/express/with-http/base/scenario.mjs diff --git a/dev-packages/node-integration-tests/suites/express/with-http/test.ts b/dev-packages/node-integration-tests/suites/express/with-http/base/test.ts similarity index 100% rename from dev-packages/node-integration-tests/suites/express/with-http/test.ts rename to dev-packages/node-integration-tests/suites/express/with-http/base/test.ts diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/generatePayload.ts b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/generatePayload.ts new file mode 100644 index 000000000000..7b85c82f9ab9 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/generatePayload.ts @@ -0,0 +1,35 @@ +// Payload for requests +export function generatePayload(sizeInBytes: number): { data: string } { + const baseSize = JSON.stringify({ data: '' }).length; + const contentLength = sizeInBytes - baseSize; + + return { data: 'x'.repeat(contentLength) }; +} + +// Generate the "expected" body string +export function generatePayloadString(dataLength: number, truncate?: boolean): string { + const prefix = '{"data":"'; + const suffix = truncate ? '...' : '"}'; + + const baseStructuralLength = prefix.length + suffix.length; + const dataContent = 'x'.repeat(dataLength - baseStructuralLength); + + return `${prefix}${dataContent}${suffix}`; +} + +// Functions for non-ASCII payloads (e.g. emojis) +export function generateEmojiPayload(sizeInBytes: number): { data: string } { + const baseSize = JSON.stringify({ data: '' }).length; + const contentLength = sizeInBytes - baseSize; + + return { data: '👍'.repeat(contentLength) }; +} +export function generateEmojiPayloadString(dataLength: number, truncate?: boolean): string { + const prefix = '{"data":"'; + const suffix = truncate ? '...' : '"}'; + + const baseStructuralLength = suffix.length; + const dataContent = '👍'.repeat(dataLength - baseStructuralLength); + + return `${prefix}${dataContent}${suffix}`; +} diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-always.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-always.mjs new file mode 100644 index 000000000000..569fa14666b4 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-always.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, + integrations: [Sentry.httpIntegration({ maxRequestBodySize: 'always' })], +}); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-default.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-default.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-default.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-medium.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-medium.mjs new file mode 100644 index 000000000000..4fd83727c671 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-medium.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, + integrations: [Sentry.httpIntegration({ maxRequestBodySize: 'medium' })], +}); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs new file mode 100644 index 000000000000..f77102549ec3 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, + integrations: [Sentry.httpIntegration({ maxRequestBodySize: 'none' })], +}); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-small.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-small.mjs new file mode 100644 index 000000000000..4dfe2be19d0c --- /dev/null +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-small.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, + integrations: [Sentry.httpIntegration({ maxRequestBodySize: 'small' })], +}); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs new file mode 100644 index 000000000000..7ec41ed3ff8b --- /dev/null +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs @@ -0,0 +1,23 @@ +import * as Sentry from '@sentry/node'; +import { startExpressServerAndSendPortToRunner } from '@sentry-internal/node-integration-tests'; +import bodyParser from 'body-parser'; +import express from 'express'; + +const app = express(); + +// Increase limit for JSON parsing +app.use(bodyParser.json({ limit: '3mb' })); +app.use(express.json({ limit: '3mb' })); + +app.post('/test-body-size', (req, res) => { + const receivedSize = JSON.stringify(req.body).length; + res.json({ + success: true, + receivedSize, + message: 'Payload processed successfully', + }); +}); + +Sentry.setupExpressErrorHandler(app); + +startExpressServerAndSendPortToRunner(app); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts new file mode 100644 index 000000000000..3d8c0f4d2cfc --- /dev/null +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts @@ -0,0 +1,278 @@ +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../../utils/runner'; +import { + generateEmojiPayload, + generateEmojiPayloadString, + generatePayload, + generatePayloadString, +} from './generatePayload'; + +// Value of MAX_BODY_BYTE_LENGTH in SentryHttpIntegration +const MAX_GENERAL = 1024 * 1024; // 1MB +const MAX_MEDIUM = 10_000; +const MAX_SMALL = 1000; + +describe('express with httpIntegration and not defined maxRequestBodySize', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument-default.mjs', (createRunner, test) => { + test('captures medium request bodies with default setting (medium)', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + data: JSON.stringify(generatePayload(MAX_MEDIUM)), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(MAX_MEDIUM)), + }); + + await runner.completed(); + }); + + test('truncates large request bodies with default setting (medium)', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + data: generatePayloadString(MAX_MEDIUM, true), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(MAX_MEDIUM + 1)), + }); + + await runner.completed(); + }); + }); +}); + +describe('express with httpIntegration and maxRequestBodySize: "none"', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument-none.mjs', + (createRunner, test) => { + test('does not capture any request bodies with none setting', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: expect.not.objectContaining({ + data: expect.any(String), + }), + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(500)), + }); + + await runner.completed(); + }); + }, + { failsOnEsm: false }, + ); +}); + +describe('express with httpIntegration and maxRequestBodySize: "always"', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument-always.mjs', + (createRunner, test) => { + test('captures maximum allowed request body length with "always" setting', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + data: JSON.stringify(generatePayload(MAX_GENERAL)), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(MAX_GENERAL)), + }); + + await runner.completed(); + }); + + test('captures large request bodies with "always" setting but respects maximum size limit', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + data: generatePayloadString(MAX_GENERAL, true), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(MAX_GENERAL + 1)), + }); + + await runner.completed(); + }); + }, + { failsOnEsm: false }, + ); +}); + +describe('express with httpIntegration and maxRequestBodySize: "small"', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument-small.mjs', + (createRunner, test) => { + test('keeps small request bodies with "small" setting', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + data: JSON.stringify(generatePayload(MAX_SMALL)), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(MAX_SMALL)), + }); + + await runner.completed(); + }); + + test('truncates too large request bodies with "small" setting', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + data: generatePayloadString(MAX_SMALL, true), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(MAX_SMALL + 1)), + }); + + await runner.completed(); + }); + + test('truncates too large non-ASCII request bodies with "small" setting', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + // 250 emojis, each 4 bytes in UTF-8 (resulting in 1000 bytes --> MAX_SMALL) + data: generateEmojiPayloadString(250, true), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generateEmojiPayload(MAX_SMALL + 1)), + }); + + await runner.completed(); + }); + }, + { failsOnEsm: false }, + ); +}); + +describe('express with httpIntegration and maxRequestBodySize: "medium"', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument-medium.mjs', + (createRunner, test) => { + test('keeps medium request bodies with "medium" setting', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + data: JSON.stringify(generatePayload(MAX_MEDIUM)), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(MAX_MEDIUM)), + }); + + await runner.completed(); + }); + + test('truncates large request bodies with "medium" setting', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: { + data: generatePayloadString(MAX_MEDIUM, true), + }, + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(MAX_MEDIUM + 1)), + }); + + await runner.completed(); + }); + }, + { failsOnEsm: false }, + ); +}); diff --git a/packages/node/src/integrations/http/SentryHttpInstrumentation.ts b/packages/node/src/integrations/http/SentryHttpInstrumentation.ts index 4e044879d2aa..8447259f280c 100644 --- a/packages/node/src/integrations/http/SentryHttpInstrumentation.ts +++ b/packages/node/src/integrations/http/SentryHttpInstrumentation.ts @@ -69,6 +69,22 @@ export type SentryHttpInstrumentationOptions = InstrumentationConfig & { */ ignoreIncomingRequestBody?: (url: string, request: http.RequestOptions) => boolean; + /** + * Controls the maximum size of HTTP request bodies attached to events. + * + * Available options: + * - 'none': No request bodies will be attached + * - 'small': Request bodies up to 1,000 bytes will be attached + * - 'medium': Request bodies up to 10,000 bytes will be attached (default) + * - 'always': Request bodies will always be attached + * + * Note that even with 'always' setting, bodies exceeding 1MB will never be attached + * for performance and security reasons. + * + * @default 'medium' + */ + maxRequestBodySize?: 'none' | 'small' | 'medium' | 'always'; + /** * Whether the integration should create [Sessions](https://docs.sentry.io/product/releases/health/#sessions) for incoming requests to track the health and crash-free rate of your releases in Sentry. * Read more about Release Health: https://docs.sentry.io/product/releases/health/ @@ -226,7 +242,7 @@ export class SentryHttpInstrumentation extends InstrumentationBase) => { try { const chunk = args[0] as Buffer | string; const bufferifiedChunk = Buffer.from(chunk); - if (bodyByteLength < MAX_BODY_BYTE_LENGTH) { + if (bodyByteLength < maxBodySize) { chunks.push(bufferifiedChunk); bodyByteLength += bufferifiedChunk.byteLength; } else if (DEBUG_BUILD) { logger.log( INSTRUMENTATION_NAME, - `Dropping request body chunk because maximum body length of ${MAX_BODY_BYTE_LENGTH}b is exceeded.`, + `Dropping request body chunk because maximum body length of ${maxBodySize}b is exceeded.`, ); } } catch (err) { @@ -429,7 +459,16 @@ function patchRequestToCaptureBody(req: http.IncomingMessage, isolationScope: Sc try { const body = Buffer.concat(chunks).toString('utf-8'); if (body) { - isolationScope.setSDKProcessingMetadata({ normalizedRequest: { data: body } }); + // Using Buffer.byteLength here, because the body may contain characters that are not 1 byte long + const bodyByteLength = Buffer.byteLength(body, 'utf-8'); + const truncatedBody = + bodyByteLength > maxBodySize + ? `${Buffer.from(body) + .subarray(0, maxBodySize - 3) + .toString('utf-8')}...` + : body; + + isolationScope.setSDKProcessingMetadata({ normalizedRequest: { data: truncatedBody } }); } } catch (error) { if (DEBUG_BUILD) { diff --git a/packages/node/src/integrations/http/index.ts b/packages/node/src/integrations/http/index.ts index 9d1113702410..70cd8883425e 100644 --- a/packages/node/src/integrations/http/index.ts +++ b/packages/node/src/integrations/http/index.ts @@ -90,6 +90,22 @@ interface HttpOptions { */ ignoreIncomingRequestBody?: (url: string, request: RequestOptions) => boolean; + /** + * Controls the maximum size of HTTP request bodies attached to events. + * + * Available options: + * - 'none': No request bodies will be attached + * - 'small': Request bodies up to 1,000 bytes will be attached + * - 'medium': Request bodies up to 10,000 bytes will be attached (default) + * - 'always': Request bodies will always be attached + * + * Note that even with 'always' setting, bodies exceeding 1MB will never be attached + * for performance and security reasons. + * + * @default 'medium' + */ + maxRequestBodySize?: 'none' | 'small' | 'medium' | 'always'; + /** * If true, do not generate spans for incoming requests at all. * This is used by Remix to avoid generating spans for incoming requests, as it generates its own spans. From bafd05f8dfd526b669535e2922423c6a87de0ce8 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Thu, 8 May 2025 16:37:46 +0200 Subject: [PATCH 2/4] review suggestions --- .../maxRequestBodySize/instrument-none.mjs | 7 +++- .../with-http/maxRequestBodySize/scenario.mjs | 9 +++++ .../with-http/maxRequestBodySize/test.ts | 33 +++++++++++++++++++ .../http/SentryHttpInstrumentation.ts | 15 +++------ 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs index f77102549ec3..7eff6bec8a7d 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs @@ -6,5 +6,10 @@ Sentry.init({ release: '1.0', tracesSampleRate: 1.0, transport: loggingTransport, - integrations: [Sentry.httpIntegration({ maxRequestBodySize: 'none' })], + integrations: [ + Sentry.httpIntegration({ + maxRequestBodySize: 'none', + ignoreIncomingRequestBody: url => url.includes('/ignore-request-body'), + }), + ], }); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs index 7ec41ed3ff8b..c198c8056fea 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs @@ -18,6 +18,15 @@ app.post('/test-body-size', (req, res) => { }); }); +app.post('/ignore-request-body', (req, res) => { + const receivedSize = JSON.stringify(req.body).length; + res.json({ + success: true, + receivedSize, + message: 'Payload processed successfully', + }); +}); + Sentry.setupExpressErrorHandler(app); startExpressServerAndSendPortToRunner(app); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts index 3d8c0f4d2cfc..c3b5af077727 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts @@ -89,6 +89,39 @@ describe('express with httpIntegration and maxRequestBodySize: "none"', () => { await runner.completed(); }); + + test('does not capture any request bodies with none setting and "ignoreIncomingRequestBody"', async () => { + const runner = createRunner() + .expect({ + transaction: { + transaction: 'POST /test-body-size', + request: expect.not.objectContaining({ + data: expect.any(String), + }), + }, + }) + .expect({ + transaction: { + transaction: 'POST /ignore-request-body', + request: expect.not.objectContaining({ + data: expect.any(String), + }), + }, + }) + .start(); + + await runner.makeRequest('post', '/test-body-size', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(500)), + }); + + await runner.makeRequest('post', '/ignore-request-body', { + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify(generatePayload(500)), + }); + + await runner.completed(); + }); }, { failsOnEsm: false }, ); diff --git a/packages/node/src/integrations/http/SentryHttpInstrumentation.ts b/packages/node/src/integrations/http/SentryHttpInstrumentation.ts index 8447259f280c..d1541224da75 100644 --- a/packages/node/src/integrations/http/SentryHttpInstrumentation.ts +++ b/packages/node/src/integrations/http/SentryHttpInstrumentation.ts @@ -263,7 +263,7 @@ export class SentryHttpInstrumentation extends InstrumentationBase) => { try { From 190903ae382e37aa1912876f88ef0efef0b58af0 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Thu, 8 May 2025 17:44:40 +0200 Subject: [PATCH 3/4] fix import --- .../suites/express/with-http/base/test.ts | 2 +- .../suites/express/with-http/maxRequestBodySize/test.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/express/with-http/base/test.ts b/dev-packages/node-integration-tests/suites/express/with-http/base/test.ts index 10dbefa74a9a..40c74a3d8888 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/base/test.ts +++ b/dev-packages/node-integration-tests/suites/express/with-http/base/test.ts @@ -1,5 +1,5 @@ import { afterAll, describe } from 'vitest'; -import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../../utils/runner'; describe('express with http import', () => { afterAll(() => { diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts index c3b5af077727..60a821618b62 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts @@ -70,7 +70,7 @@ describe('express with httpIntegration and maxRequestBodySize: "none"', () => { 'scenario.mjs', 'instrument-none.mjs', (createRunner, test) => { - test('does not capture any request bodies with none setting', async () => { + test('does not capture any request bodies with "none" setting', async () => { const runner = createRunner() .expect({ transaction: { @@ -90,7 +90,7 @@ describe('express with httpIntegration and maxRequestBodySize: "none"', () => { await runner.completed(); }); - test('does not capture any request bodies with none setting and "ignoreIncomingRequestBody"', async () => { + test('does not capture any request bodies with "none" setting and "ignoreIncomingRequestBody"', async () => { const runner = createRunner() .expect({ transaction: { From 0be545ec5205bbee87c92873fc4d99223e597947 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Tue, 13 May 2025 10:31:46 +0200 Subject: [PATCH 4/4] rename to `maxIncomingRequestBodySize` --- .../generatePayload.ts | 0 .../instrument-always.mjs | 2 +- .../instrument-default.mjs | 0 .../instrument-medium.mjs | 2 +- .../instrument-none.mjs | 2 +- .../instrument-small.mjs | 2 +- .../scenario.mjs | 0 .../test.ts | 10 +++++----- .../http/SentryHttpInstrumentation.ts | 18 +++++++++++------- packages/node/src/integrations/http/index.ts | 4 ++-- 10 files changed, 22 insertions(+), 18 deletions(-) rename dev-packages/node-integration-tests/suites/express/with-http/{maxRequestBodySize => maxIncomingRequestBodySize}/generatePayload.ts (100%) rename dev-packages/node-integration-tests/suites/express/with-http/{maxRequestBodySize => maxIncomingRequestBodySize}/instrument-always.mjs (75%) rename dev-packages/node-integration-tests/suites/express/with-http/{maxRequestBodySize => maxIncomingRequestBodySize}/instrument-default.mjs (100%) rename dev-packages/node-integration-tests/suites/express/with-http/{maxRequestBodySize => maxIncomingRequestBodySize}/instrument-medium.mjs (75%) rename dev-packages/node-integration-tests/suites/express/with-http/{maxRequestBodySize => maxIncomingRequestBodySize}/instrument-none.mjs (90%) rename dev-packages/node-integration-tests/suites/express/with-http/{maxRequestBodySize => maxIncomingRequestBodySize}/instrument-small.mjs (75%) rename dev-packages/node-integration-tests/suites/express/with-http/{maxRequestBodySize => maxIncomingRequestBodySize}/scenario.mjs (100%) rename dev-packages/node-integration-tests/suites/express/with-http/{maxRequestBodySize => maxIncomingRequestBodySize}/test.ts (95%) diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/generatePayload.ts b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/generatePayload.ts similarity index 100% rename from dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/generatePayload.ts rename to dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/generatePayload.ts diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-always.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-always.mjs similarity index 75% rename from dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-always.mjs rename to dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-always.mjs index 569fa14666b4..9f26662334fb 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-always.mjs +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-always.mjs @@ -6,5 +6,5 @@ Sentry.init({ release: '1.0', tracesSampleRate: 1.0, transport: loggingTransport, - integrations: [Sentry.httpIntegration({ maxRequestBodySize: 'always' })], + integrations: [Sentry.httpIntegration({ maxIncomingRequestBodySize: 'always' })], }); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-default.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-default.mjs similarity index 100% rename from dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-default.mjs rename to dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-default.mjs diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-medium.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-medium.mjs similarity index 75% rename from dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-medium.mjs rename to dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-medium.mjs index 4fd83727c671..92ed3d0d5d35 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-medium.mjs +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-medium.mjs @@ -6,5 +6,5 @@ Sentry.init({ release: '1.0', tracesSampleRate: 1.0, transport: loggingTransport, - integrations: [Sentry.httpIntegration({ maxRequestBodySize: 'medium' })], + integrations: [Sentry.httpIntegration({ maxIncomingRequestBodySize: 'medium' })], }); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-none.mjs similarity index 90% rename from dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs rename to dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-none.mjs index 7eff6bec8a7d..609863666ee4 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-none.mjs +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-none.mjs @@ -8,7 +8,7 @@ Sentry.init({ transport: loggingTransport, integrations: [ Sentry.httpIntegration({ - maxRequestBodySize: 'none', + maxIncomingRequestBodySize: 'none', ignoreIncomingRequestBody: url => url.includes('/ignore-request-body'), }), ], diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-small.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-small.mjs similarity index 75% rename from dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-small.mjs rename to dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-small.mjs index 4dfe2be19d0c..fc13fbe20d31 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/instrument-small.mjs +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/instrument-small.mjs @@ -6,5 +6,5 @@ Sentry.init({ release: '1.0', tracesSampleRate: 1.0, transport: loggingTransport, - integrations: [Sentry.httpIntegration({ maxRequestBodySize: 'small' })], + integrations: [Sentry.httpIntegration({ maxIncomingRequestBodySize: 'small' })], }); diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/scenario.mjs similarity index 100% rename from dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/scenario.mjs rename to dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/scenario.mjs diff --git a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/test.ts similarity index 95% rename from dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts rename to dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/test.ts index 60a821618b62..5ae6b4e2bacc 100644 --- a/dev-packages/node-integration-tests/suites/express/with-http/maxRequestBodySize/test.ts +++ b/dev-packages/node-integration-tests/suites/express/with-http/maxIncomingRequestBodySize/test.ts @@ -12,7 +12,7 @@ const MAX_GENERAL = 1024 * 1024; // 1MB const MAX_MEDIUM = 10_000; const MAX_SMALL = 1000; -describe('express with httpIntegration and not defined maxRequestBodySize', () => { +describe('express with httpIntegration and not defined maxIncomingRequestBodySize', () => { afterAll(() => { cleanupChildProcesses(); }); @@ -60,7 +60,7 @@ describe('express with httpIntegration and not defined maxRequestBodySize', () = }); }); -describe('express with httpIntegration and maxRequestBodySize: "none"', () => { +describe('express with httpIntegration and maxIncomingRequestBodySize: "none"', () => { afterAll(() => { cleanupChildProcesses(); }); @@ -127,7 +127,7 @@ describe('express with httpIntegration and maxRequestBodySize: "none"', () => { ); }); -describe('express with httpIntegration and maxRequestBodySize: "always"', () => { +describe('express with httpIntegration and maxIncomingRequestBodySize: "always"', () => { afterAll(() => { cleanupChildProcesses(); }); @@ -181,7 +181,7 @@ describe('express with httpIntegration and maxRequestBodySize: "always"', () => ); }); -describe('express with httpIntegration and maxRequestBodySize: "small"', () => { +describe('express with httpIntegration and maxIncomingRequestBodySize: "small"', () => { afterAll(() => { cleanupChildProcesses(); }); @@ -256,7 +256,7 @@ describe('express with httpIntegration and maxRequestBodySize: "small"', () => { ); }); -describe('express with httpIntegration and maxRequestBodySize: "medium"', () => { +describe('express with httpIntegration and maxIncomingRequestBodySize: "medium"', () => { afterAll(() => { cleanupChildProcesses(); }); diff --git a/packages/node/src/integrations/http/SentryHttpInstrumentation.ts b/packages/node/src/integrations/http/SentryHttpInstrumentation.ts index d1541224da75..40d0d59e8a1d 100644 --- a/packages/node/src/integrations/http/SentryHttpInstrumentation.ts +++ b/packages/node/src/integrations/http/SentryHttpInstrumentation.ts @@ -70,7 +70,7 @@ export type SentryHttpInstrumentationOptions = InstrumentationConfig & { ignoreIncomingRequestBody?: (url: string, request: http.RequestOptions) => boolean; /** - * Controls the maximum size of HTTP request bodies attached to events. + * Controls the maximum size of incoming HTTP request bodies attached to events. * * Available options: * - 'none': No request bodies will be attached @@ -83,7 +83,7 @@ export type SentryHttpInstrumentationOptions = InstrumentationConfig & { * * @default 'medium' */ - maxRequestBodySize?: 'none' | 'small' | 'medium' | 'always'; + maxIncomingRequestBodySize?: 'none' | 'small' | 'medium' | 'always'; /** * Whether the integration should create [Sessions](https://docs.sentry.io/product/releases/health/#sessions) for incoming requests to track the health and crash-free rate of your releases in Sentry. @@ -242,7 +242,7 @@ export class SentryHttpInstrumentation extends InstrumentationBase boolean; /** - * Controls the maximum size of HTTP request bodies attached to events. + * Controls the maximum size of incoming HTTP request bodies attached to events. * * Available options: * - 'none': No request bodies will be attached @@ -104,7 +104,7 @@ interface HttpOptions { * * @default 'medium' */ - maxRequestBodySize?: 'none' | 'small' | 'medium' | 'always'; + maxIncomingRequestBodySize?: 'none' | 'small' | 'medium' | 'always'; /** * If true, do not generate spans for incoming requests at all.