commit 17b8f2f85bc2d35f13375d2dde45e7c23203d483
parent ae9c610377718bc0cae69d32519e23eb2daadea4
Author: Julian Descottes <jdescottes@mozilla.com>
Date: Thu, 8 Jan 2026 11:05:30 +0000
Bug 2004973 - [devtools] Chunk calls to String.fromCharCode in NetworkUtils r=devtools-reviewers,bomsy
Need to chunk calls to String.fromCharCode because data might be a very large array.
Differential Revision: https://phabricator.services.mozilla.com/D277897
Diffstat:
2 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/devtools/shared/network-observer/NetworkUtils.sys.mjs b/devtools/shared/network-observer/NetworkUtils.sys.mjs
@@ -867,7 +867,15 @@ async function decodeCompressedStream(stream, length, encodings) {
_length,
data
) {
- resolve(String.fromCharCode.apply(this, data));
+ // `data`` might be a very large array, chunk calls to fromCharCode to
+ // avoid "RangeError: too many arguments provided for a function call".
+ const CHUNK_SIZE = 65536;
+ let result = "";
+ for (let i = 0; i < data.length; i += CHUNK_SIZE) {
+ const chunk = data.slice(i, i + CHUNK_SIZE);
+ result += String.fromCharCode.apply(null, chunk);
+ }
+ resolve(result);
},
});
});
diff --git a/devtools/shared/network-observer/test/browser/browser_networkobserver_response_body_limit.js b/devtools/shared/network-observer/test/browser/browser_networkobserver_response_body_limit.js
@@ -51,6 +51,7 @@ const BYTES_1000 = 1000;
const smallSize = BYTES_1000 / 2;
const bigSize = BYTES_1000 * 2;
const hugeSize = BYTES_1000 * 20;
+const tooManyArgumentsSize = BYTES_1000 * 1000;
add_task(async function testNetworkObserverWithResponseBodyLimit1000() {
info("Test a network observer with specific response body limit (1000)");
@@ -126,23 +127,40 @@ add_task(async function testNetworkObserverWithResponseBodyLimitZero() {
info("Test a network observer with a response body limit = zero (unlimited)");
const tab = await addTab(TEST_URL);
- const events = [];
- const noLimitNetworkObserver = createNetworkObserver({
- events,
- responseBodyLimit: 0,
- decodeResponseBodies: true,
- });
-
- await performGetDataRequest(gBrowser, events, smallSize);
- await assertNetworkEventContent(events.at(-1), smallSize, false);
-
- await performGetDataRequest(gBrowser, events, bigSize);
- await assertNetworkEventContent(events.at(-1), bigSize, false);
-
- await performGetDataRequest(gBrowser, events, hugeSize);
- await assertNetworkEventContent(events.at(-1), hugeSize, false);
-
- noLimitNetworkObserver.destroy();
+ for (const useGzip of [true, false]) {
+ for (const decodeResponseBodies of [true, false]) {
+ info("Test with decodeResponseBodies=" + decodeResponseBodies);
+ const events = [];
+ const noLimitNetworkObserver = createNetworkObserver({
+ events,
+ responseBodyLimit: 0,
+ decodeResponseBodies,
+ });
+
+ await performGetDataRequest(gBrowser, events, smallSize, useGzip);
+ await assertNetworkEventContent(events.at(-1), smallSize, false);
+
+ await performGetDataRequest(gBrowser, events, bigSize, useGzip);
+ await assertNetworkEventContent(events.at(-1), bigSize, false);
+
+ await performGetDataRequest(gBrowser, events, hugeSize, useGzip);
+ await assertNetworkEventContent(events.at(-1), hugeSize, false);
+
+ await performGetDataRequest(
+ gBrowser,
+ events,
+ tooManyArgumentsSize,
+ useGzip
+ );
+ await assertNetworkEventContent(
+ events.at(-1),
+ tooManyArgumentsSize,
+ false
+ );
+
+ noLimitNetworkObserver.destroy();
+ }
+ }
gBrowser.removeTab(tab);
});