Merge pull request #1696 from Burlesque1/fix/large-json-body-and-extraheaders

fix(ui): truncate over-large JSON bodies in preview to avoid formatter worker crash
This commit is contained in:
musi
2026-08-19 17:58:27 +08:00
committed by GitHub
2 changed files with 39 additions and 1 deletions
@@ -114,7 +114,16 @@ export function formatLogBodyForWorker(
} {
const large = isLargeLogBody(body, largeTextThreshold);
const preview = large && mode !== "full";
const formattedBodyView = formatLogBodyView(body);
// Large-body preview: only skip the full JSON parse/pretty-print when the actual
// text is over-length. Otherwise the worker does JSON.parse on a huge object graph
// and pretty-prints + structured-clones it back, blowing up memory/CPU and surfacing
// "Body formatter worker failed." (issue #1694).
// The judge is the real body.text length, not sizeBytes (sizeBytes may be inflated
// storage metadata; a preview:true lightweight JSON should still show its JSON tree).
const previewText: FormattedLogBody | undefined = preview && (body?.text?.length ?? 0) > previewTextLimit
? { text: createLogBodyPreviewText(body, previewTextLimit) }
: undefined;
const formattedBodyView = previewText ?? formatLogBodyView(body);
const bodyView = preview && formattedBodyView.json === undefined
? { text: createLogBodyPreviewText(body, previewTextLimit) }
: formattedBodyView;
@@ -50,3 +50,32 @@ test("request log preview bodies still format parseable JSON as JSON", () => {
});
assert.match(view.text, /"model": "test-model"/);
});
test("preview mode truncates an over-large JSON text body instead of parsing it", () => {
const hugeText = JSON.stringify({
model: "test-model",
messages: Array.from({ length: 4000 }, (_, i) => ({
role: i % 2 === 0 ? "user" : "assistant",
content: `message body number ${i} `.repeat(20)
}))
});
// Far beyond previewTextLimit, simulating a real ~308KB request body (issue #1694)
assert.ok(hugeText.length > 300 * 1024, "fixture should exceed 300KB");
const body: RequestLogBody = {
bodyRef: "large-json-body",
contentType: "application/json",
encoding: "utf8",
preview: true,
sizeBytes: hugeText.length,
text: hugeText,
truncated: false
};
const view = formatLogBodyForWorker(body, "preview", 256 * 1024, 160 * 1024);
assert.equal(view.preview, true);
// Over-length text is truncated instead of fully parsed/pretty-printed, avoiding the worker crash
assert.equal(view.json, undefined);
assert.ok(view.text.length < hugeText.length, "should be truncated");
assert.match(view.text, /characters omitted from preview/);
});