fix: crash on viewing large responses (#5647)

* fix: crash on viewing large responses
This commit is contained in:
naman-bruno
2025-10-30 13:29:53 +05:30
committed by GitHub
parent e68b2ae3b7
commit 73caaef42b
2 changed files with 70 additions and 22 deletions

View File

@@ -13,40 +13,50 @@ import { useTheme } from 'providers/Theme/index';
import { getEncoding, uuid } from 'utils/common/index';
import LargeResponseWarning from '../LargeResponseWarning';
// Memory threshold to prevent crashes when decoding large buffers
const LARGE_BUFFER_THRESHOLD = 50 * 1024 * 1024; // 50 MB
const applyJSONPathFilter = (data, filter) => {
try {
return JSONPath({ path: filter, json: data });
} catch (e) {
console.warn('Could not apply JSONPath filter:', e.message);
return data;
}
};
const formatResponse = (data, dataBuffer, encoding, mode, filter) => {
if (data === undefined || !dataBuffer || !mode) {
return '';
}
// TODO: We need a better way to get the raw response-data here instead
// of using this dataBuffer param.
// Also, we only need the raw response-data and content-type to show the preview.
const rawData = iconv.decode(
Buffer.from(dataBuffer, "base64"),
iconv.encodingExists(encoding) ? encoding : "utf-8"
);
let bufferSize = 0;
try {
bufferSize = Buffer.from(dataBuffer, 'base64').length;
} catch (error) {
console.warn('Failed to calculate buffer size:', error);
}
const isVeryLargeResponse = bufferSize > LARGE_BUFFER_THRESHOLD;
if (mode.includes('json')) {
try {
JSON.parse(rawData);
const prettyPrint = !isVeryLargeResponse;
const processedData = filter ? applyJSONPathFilter(data, filter) : data;
return typeof processedData === 'string'
? processedData
: safeStringifyJSON(processedData, prettyPrint);
} catch (error) {
// If the response content-type is JSON and it fails parsing, its an invalid JSON.
// In that case, just show the response as it is in the preview.
return rawData;
return typeof data === 'string' ? data : String(data);
}
if (filter) {
try {
data = JSONPath({ path: filter, json: data });
} catch (e) {
console.warn('Could not apply JSONPath filter:', e.message);
}
}
return safeStringifyJSON(data, true);
}
if (mode.includes('xml')) {
if (isVeryLargeResponse) {
return typeof data === 'string' ? data : safeStringifyJSON(data, false);
}
let parsed = safeParseXML(data, { collapseContent: true });
if (typeof parsed === 'string') {
return parsed;
@@ -58,7 +68,7 @@ const formatResponse = (data, dataBuffer, encoding, mode, filter) => {
return data;
}
return safeStringifyJSON(data, true);
return safeStringifyJSON(data, !isVeryLargeResponse);
};
const formatErrorMessage = (error) => {

View File

@@ -0,0 +1,38 @@
import { test, expect } from '../../playwright';
test.describe('Large Response Crash Prevention', () => {
test('should show appropriate warning for responses over 10MB', async ({ page, createTmpDir }) => {
// Create collection
await page.getByLabel('Create Collection').click();
await page.getByLabel('Name').fill('size-warning-test');
await page.getByLabel('Name').press('Tab');
await page.getByLabel('Location').fill(await createTmpDir('size-warning-test'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.getByText('size-warning-test').click();
await page.getByLabel('Safe Mode').check();
await page.getByRole('button', { name: 'Save' }).click();
// Create request
await page.locator('#create-new-tab').getByRole('img').click();
await page.getByPlaceholder('Request Name').fill('size-check');
await page.locator('#new-request-url .CodeMirror').click();
await page.locator('textarea').fill('https://samples.json-format.com/employees/json/employees_50MB.json');
await page.getByRole('button', { name: 'Create' }).click();
// Send request
const sendButton = page.locator('#send-request').getByRole('img').nth(2);
await sendButton.click();
// Verify warning appears
await expect(page.getByText('Large Response Warning')).toBeVisible({ timeout: 60000 });
// Verify warning content
await expect(page.getByText('Handling responses over')).toBeVisible();
await expect(page.getByText('could degrade performance')).toBeVisible();
// Verify action button
await expect(page.getByRole('button', { name: 'View' })).toBeVisible();
console.log('Large response warning displayed correctly');
});
});