Skip to content

Commit f9ec561

Browse files
committed
fix(nextcloud-talk): bound error bodies via public readResponseTextLimited (no new plugin-SDK surface)
Re-exporting readResponseTextSnippet from plugin-sdk/response-limit-runtime pushed the public plugin-SDK export count past its surface budget, failing plugin-sdk-surface-report.test.ts. Drop that re-export and instead bound the Nextcloud Talk send/reaction error bodies through the already-public readResponseTextLimited (openclaw/plugin-sdk/provider-http), collapsing the bounded 8 KiB prefix to a short, log-safe snippet locally. Behavior is unchanged for callers; no new plugin-SDK surface is introduced. Success JSON still reads through readResponseWithLimit (16 MiB cap). The committed bounded-response-reads Vitest suite continues to prove the caps hold against 17 MiB streamed bodies with no content-length.
1 parent f366bd5 commit f9ec561

2 files changed

Lines changed: 19 additions & 13 deletions

File tree

extensions/nextcloud-talk/src/send.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// Nextcloud Talk plugin module implements send behavior.
22
import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
3-
import {
4-
readResponseTextSnippet,
5-
readResponseWithLimit,
6-
} from "openclaw/plugin-sdk/response-limit-runtime";
3+
import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
4+
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
75
import { stripNextcloudTalkTargetPrefix } from "./normalize.js";
86
import {
97
convertMarkdownTables,
@@ -22,15 +20,26 @@ import type { CoreConfig, NextcloudTalkSendResult } from "./types.js";
2220
// misbehaving endpoint cannot stream an unbounded body into memory.
2321
const NEXTCLOUD_TALK_JSON_MAX_BYTES = 16 * 1024 * 1024;
2422
const NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_BYTES = 8 * 1024;
23+
const NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS = 200;
24+
25+
/** Collapses whitespace and caps an error-body prefix to a short, log-safe snippet. */
26+
function collapseErrorSnippet(text: string): string {
27+
const collapsed = text.replace(/\s+/g, " ").trim();
28+
if (collapsed.length > NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS) {
29+
return `${collapsed.slice(0, NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS)}…`;
30+
}
31+
return collapsed;
32+
}
2533

2634
/** Reads a bounded, collapsed error-body snippet without buffering hostile responses. */
2735
async function readNextcloudTalkErrorSnippet(response: Response): Promise<string> {
2836
try {
29-
return (
30-
(await readResponseTextSnippet(response, {
31-
maxBytes: NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_BYTES,
32-
})) ?? ""
33-
);
37+
// readResponseTextLimited caps the read at the byte budget and cancels the
38+
// upstream stream once full, so a hostile endpoint cannot stream an
39+
// unbounded body into memory. Collapse the bounded prefix locally to keep a
40+
// short, log-safe error snippet (no new plugin SDK surface required).
41+
const text = await readResponseTextLimited(response, NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_BYTES);
42+
return collapseErrorSnippet(text);
3443
} catch {
3544
return "";
3645
}
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
// Narrow response-size reader for plugins that download bounded HTTP bodies.
22

33
export { readByteStreamWithLimit } from "@openclaw/media-core/read-byte-stream-with-limit";
4-
export {
5-
readResponseTextSnippet,
6-
readResponseWithLimit,
7-
} from "@openclaw/media-core/read-response-with-limit";
4+
export { readResponseWithLimit } from "@openclaw/media-core/read-response-with-limit";

0 commit comments

Comments
 (0)