






















11// Mattermost plugin module implements client behavior.
22import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
3-import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
3+import {
4+readProviderJsonResponse,
5+readResponseTextLimited,
6+} from "openclaw/plugin-sdk/provider-http";
7+import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
48import { sleep } from "openclaw/plugin-sdk/runtime-env";
59import {
610fetchWithSsrFGuard,
@@ -13,6 +17,13 @@ import {
1317import { z } from "zod";
14181519const MATTERMOST_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
20+// Mattermost REST control-plane JSON (posts, users, channels, file-upload
21+// results) stays well under a megabyte; cap successful JSON the same way the
22+// shared provider path is capped so an untrusted/self-hosted homeserver cannot
23+// stream an unbounded body into the runtime before parsing.
24+// Non-JSON success bodies are a rare fallback (the API is JSON-first); keep a
25+// generous text budget but still bound it instead of buffering the whole stream.
26+const MATTERMOST_TEXT_RESPONSE_LIMIT_BYTES = 64 * 1024;
1627const NULL_BODY_STATUSES = new Set([101, 204, 205, 304]);
17281829export type MattermostFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
@@ -84,6 +95,14 @@ function buildMattermostApiUrl(baseUrl: string, path: string): string {
8495return `${normalized}/api/v4${suffix}`;
8596}
869798+async function readMattermostSuccessText(res: Response, path: string): Promise<string> {
99+const bytes = await readResponseWithLimit(res, MATTERMOST_TEXT_RESPONSE_LIMIT_BYTES, {
100+onOverflow: ({ maxBytes }) =>
101+new Error(`Mattermost API ${path}: text response exceeds ${maxBytes} bytes`),
102+});
103+return new TextDecoder().decode(bytes);
104+}
105+87106export async function readMattermostError(res: Response): Promise<string> {
88107const contentType = res.headers.get("content-type") ?? "";
89108if (!res.body) {
@@ -214,9 +233,9 @@ export function createMattermostClient(params: {
214233215234const contentType = res.headers.get("content-type") ?? "";
216235if (contentType.includes("application/json")) {
217-return (await res.json()) as T;
236+return await readProviderJsonResponse<T>(res, `Mattermost API ${path}`);
218237}
219-return (await res.text()) as T;
238+return (await readMattermostSuccessText(res, path)) as T;
220239};
221240222241return { baseUrl, apiBaseUrl, token, request, fetchImpl };
@@ -679,7 +698,10 @@ export async function uploadMattermostFile(
679698const detail = await readMattermostError(res);
680699throw new Error(`Mattermost API ${res.status} ${res.statusText}: ${detail || "unknown error"}`);
681700}
682-const data = (await res.json()) as { file_infos?: MattermostFileInfo[] };
701+const data = await readProviderJsonResponse<{ file_infos?: MattermostFileInfo[] }>(
702+res,
703+"Mattermost API /files",
704+);
683705const info = data.file_infos?.[0];
684706if (!info?.id) {
685707throw new Error("Mattermost file upload failed");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。