From 18cc6805bf4af62d9ab050682ada4e97a189bfec Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Thu, 29 Sep 2022 13:04:54 +0200 Subject: [PATCH] fix(utils): Normalize when serializing envelope (#5851) --- packages/utils/src/envelope.ts | 20 ++++++++++++++++++-- packages/utils/test/envelope.test.ts | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/utils/src/envelope.ts b/packages/utils/src/envelope.ts index f203cef51284..a52ec8b4b52e 100644 --- a/packages/utils/src/envelope.ts +++ b/packages/utils/src/envelope.ts @@ -8,6 +8,7 @@ import { TextEncoderInternal, } from '@sentry/types'; +import { normalize } from './normalize'; import { dropUndefinedKeys } from './object'; /** @@ -67,9 +68,24 @@ export function serializeEnvelope(envelope: Envelope, textEncoder?: TextEncoderI } for (const item of items) { - const [itemHeaders, payload] = item as typeof items[number]; + const [itemHeaders, payload] = item; + append(`\n${JSON.stringify(itemHeaders)}\n`); - append(typeof payload === 'string' || payload instanceof Uint8Array ? payload : JSON.stringify(payload)); + + if (typeof payload === 'string' || payload instanceof Uint8Array) { + append(payload); + } else { + let stringifiedPayload: string; + try { + stringifiedPayload = JSON.stringify(payload); + } catch (e) { + // In case, despite all our efforts to keep `payload` circular-dependency-free, `JSON.strinify()` still + // fails, we try again after normalizing it again with infinite normalization depth. This of course has a + // performance impact but in this case a performance hit is better than throwing. + stringifiedPayload = JSON.stringify(normalize(payload)); + } + append(stringifiedPayload); + } } return typeof parts === 'string' ? parts : concatBuffers(parts); diff --git a/packages/utils/test/envelope.test.ts b/packages/utils/test/envelope.test.ts index af63b5bfb9bf..5fa7102281b3 100644 --- a/packages/utils/test/envelope.test.ts +++ b/packages/utils/test/envelope.test.ts @@ -58,6 +58,21 @@ describe('envelope', () => { Uint8Array.from([7, 8, 9, 10, 11, 12]), ]); }); + + it("doesn't throw when being passed a an envelope that contains a circular item payload", () => { + const chicken: { egg?: unknown } = {}; + const egg = { chicken }; + chicken.egg = chicken; + + const env = createEnvelope({ event_id: 'aa3ff046696b4bc6b609ce6d28fde9e2', sent_at: '123' }, [ + [{ type: 'event' }, egg], + ]); + + const serializedEnvelope = serializeEnvelope(env, new TextEncoder()); + const [, , serializedBody] = serializedEnvelope.toString().split('\n'); + + expect(serializedBody).toBe('{"chicken":{"egg":"[Circular ~]"}}'); + }); }); describe('addItemToEnvelope()', () => {