




























@@ -36,6 +36,7 @@
36363737import * as crypto from "node:crypto";
3838import type { FileHandle } from "node:fs/promises";
39+import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
3940import type { MediaSource, OpenedLocalFile } from "../messaging/media-source.js";
4041import { openLocalFile } from "../messaging/media-source.js";
4142import {
@@ -564,30 +565,38 @@ async function putToPresignedUrl(
564565) as ArrayBuffer;
565566566567const startTime = Date.now();
567-const response = await fetch(presignedUrl, {
568-method: "PUT",
569-body: new Blob([ab]),
570-headers: { "Content-Length": String(data.length) },
568+const { response, release } = await fetchWithSsrFGuard({
569+url: presignedUrl,
570+auditContext: "qqbot-media-part-upload",
571+init: {
572+method: "PUT",
573+body: new Blob([ab]),
574+headers: { "Content-Length": String(data.length) },
575+},
571576signal: controller.signal,
572577});
573-const elapsed = Date.now() - startTime;
574-const requestId = response.headers.get("x-cos-request-id") ?? "-";
575-const etag = response.headers.get("ETag") ?? "-";
576-577-if (!response.ok) {
578-const body = await response.text().catch(() => "");
579-logger?.error?.(
580-`${prefix} PUT part ${partIndex}/${totalParts}: HTTP ${response.status} ${response.statusText} (${elapsed}ms, requestId=${requestId}) body=${body.slice(0, 160)}`,
581-);
582-throw new Error(
583-`COS PUT failed: ${response.status} ${response.statusText} - ${body.slice(0, 120)}`,
578+try {
579+const elapsed = Date.now() - startTime;
580+const requestId = response.headers.get("x-cos-request-id") ?? "-";
581+const etag = response.headers.get("ETag") ?? "-";
582+583+if (!response.ok) {
584+const body = await response.text().catch(() => "");
585+logger?.error?.(
586+`${prefix} PUT part ${partIndex}/${totalParts}: HTTP ${response.status} ${response.statusText} (${elapsed}ms, requestId=${requestId}) body=${body.slice(0, 160)}`,
587+);
588+throw new Error(
589+`COS PUT failed: ${response.status} ${response.statusText} - ${body.slice(0, 120)}`,
590+);
591+}
592+593+logger?.debug?.(
594+`${prefix} PUT part ${partIndex}/${totalParts} OK (${elapsed}ms ETag=${etag} requestId=${requestId})`,
584595);
596+return;
597+} finally {
598+await release();
585599}
586-587-logger?.debug?.(
588-`${prefix} PUT part ${partIndex}/${totalParts} OK (${elapsed}ms ETag=${etag} requestId=${requestId})`,
589-);
590-return;
591600} catch (err) {
592601lastError = err instanceof Error ? err : new Error(String(err));
593602if (lastError.name === "AbortError") {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。