

























@@ -28,6 +28,10 @@ const INSTALL_TIMEOUT_MS = readPositiveInt(
2828);
2929const RPC_TIMEOUT_MS = readPositiveInt(process.env.OPENCLAW_KITCHEN_SINK_RPC_CALL_MS, 60000);
3030const FETCH_TIMEOUT_MS = readPositiveInt(process.env.OPENCLAW_KITCHEN_SINK_RPC_FETCH_MS, 10000);
31+const FETCH_BODY_MAX_BYTES = readPositiveInt(
32+process.env.OPENCLAW_KITCHEN_SINK_RPC_FETCH_BODY_BYTES,
33+1024 * 1024,
34+);
3135const MAX_RSS_MIB = readPositiveInt(process.env.OPENCLAW_KITCHEN_SINK_MAX_RSS_MIB, 2048);
3236const GATEWAY_TEARDOWN_GRACE_MS = 10000;
3337const GATEWAY_TEARDOWN_KILL_GRACE_MS = 2000;
@@ -461,6 +465,7 @@ function isRetryableTransientNetworkError(error, seen = new Set()) {
461465export async function fetchJson(url, options = {}) {
462466const attempts = Math.max(1, options.attempts ?? 3);
463467const timeoutMs = Math.max(1, options.timeoutMs ?? FETCH_TIMEOUT_MS);
468+const maxBodyBytes = Math.max(1, options.maxBodyBytes ?? FETCH_BODY_MAX_BYTES);
464469let lastError;
465470for (let attempt = 1; attempt <= attempts; attempt += 1) {
466471const controller = new AbortController();
@@ -480,7 +485,10 @@ export async function fetchJson(url, options = {}) {
480485(options.fetchImpl ?? fetch)(url, { signal: controller.signal }),
481486timeoutPromise,
482487]);
483-const text = await Promise.race([response.text(), timeoutPromise]);
488+const text = await Promise.race([
489+readBoundedResponseText(response, maxBodyBytes),
490+timeoutPromise,
491+]);
484492let body = null;
485493try {
486494body = text ? JSON.parse(text) : null;
@@ -503,6 +511,31 @@ export async function fetchJson(url, options = {}) {
503511throw lastError ?? new Error(`fetch ${url} failed`);
504512}
505513514+export async function readBoundedResponseText(response, byteLimit = FETCH_BODY_MAX_BYTES) {
515+const reader = response.body?.getReader?.();
516+if (!reader) {
517+return await response.text();
518+}
519+const chunks = [];
520+let totalBytes = 0;
521+for (;;) {
522+const { done, value } = await reader.read();
523+if (done) {
524+break;
525+}
526+const chunk = Buffer.from(value);
527+totalBytes += chunk.byteLength;
528+if (totalBytes > byteLimit) {
529+await reader.cancel().catch(() => undefined);
530+throw Object.assign(new Error(`fetch response body exceeded ${byteLimit} bytes`), {
531+code: "ETOOBIG",
532+});
533+}
534+chunks.push(chunk);
535+}
536+return Buffer.concat(chunks, totalBytes).toString("utf8");
537+}
538+506539function configureKitchenSink(env, port) {
507540const configPath = env.OPENCLAW_CONFIG_PATH;
508541const config = fs.existsSync(configPath) ? readJson(configPath) : {};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。