From e5bbc6f17ad321b1c42d38b842bb541469fe4a76 Mon Sep 17 00:00:00 2001 From: kay delaney <45561153+kaydelaney@users.noreply.github.com> Date: Wed, 10 Jul 2024 10:42:33 +0100 Subject: [PATCH] [v11.1.x] Frontend: Use safe stringifier in parseBody (#90234) Frontend: Use safe stringifier in parseBody (#90047) * Frontend: Use safe stringifier in parseBody Closes #88064 (cherry picked from commit 434f3869820c7820b41dfd13351017a31409eff3) --- packages/grafana-data/src/utils/object.ts | 19 +++++++++++++++++++ public/app/core/utils/fetch.ts | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/grafana-data/src/utils/object.ts b/packages/grafana-data/src/utils/object.ts index 0f40f8e636a..50d3ff25507 100644 --- a/packages/grafana-data/src/utils/object.ts +++ b/packages/grafana-data/src/utils/object.ts @@ -10,3 +10,22 @@ export const isEmptyObject = (value: unknown): value is Record => { return typeof value === 'object' && value !== null && Object.keys(value).length === 0; }; + +/** Stringifies an object that may contain circular references */ +export function safeStringifyValue(value: unknown) { + const getCircularReplacer = () => { + const seen = new WeakSet(); + return (_: string, value: object | null) => { + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) { + return; + } + seen.add(value); + } + + return value; + }; + }; + + return JSON.stringify(value, getCircularReplacer()); +} diff --git a/public/app/core/utils/fetch.ts b/public/app/core/utils/fetch.ts index 49253f74a31..8b4031123b7 100644 --- a/public/app/core/utils/fetch.ts +++ b/public/app/core/utils/fetch.ts @@ -1,6 +1,6 @@ import { omitBy } from 'lodash'; -import { deprecationWarning } from '@grafana/data'; +import { deprecationWarning, safeStringifyValue } from '@grafana/data'; import { BackendSrvRequest } from '@grafana/runtime'; export const parseInitFromOptions = (options: BackendSrvRequest): RequestInit => { @@ -93,7 +93,7 @@ export const parseBody = (options: BackendSrvRequest, isAppJson: boolean) => { return options.data; } - return isAppJson ? JSON.stringify(options.data) : new URLSearchParams(options.data); + return isAppJson ? safeStringifyValue(options.data) : new URLSearchParams(options.data); }; export async function parseResponseBody(