




























@@ -23,9 +23,8 @@ const DEFAULT_CLAWHUB_URL = "https://clawhub.ai";
2323const DEFAULT_GITHUB_CODELOAD_URL = "https://codeload.github.com";
2424const DEFAULT_FETCH_TIMEOUT_MS = 30_000;
2525const SKILL_CARD_MAX_BYTES = 256 * 1024;
26-// ClawHub is an external marketplace (untrusted source): bound JSON and error
27-// bodies so a hostile or malfunctioning host cannot exhaust memory by streaming
28-// an unbounded response. Mirrors the error-stream hardening landed in #95108.
26+// ClawHub is an external marketplace: bound untrusted JSON and error bodies so
27+// a hostile or malfunctioning host cannot exhaust memory with an endless stream.
2928const CLAWHUB_JSON_MAX_BYTES = 16 * 1024 * 1024;
3029const CLAWHUB_ERROR_BODY_MAX_BYTES = 8 * 1024;
3130const CLAWHUB_ERROR_BODY_MAX_CHARS = 400;
@@ -654,10 +653,7 @@ async function clawhubRequest(
654653const timeoutMs = resolveClawHubRequestTimeoutMs(params.timeoutMs);
655654const controller = new AbortController();
656655const timeout = setTimeout(
657-() =>
658-controller.abort(
659-new Error(`ClawHub request timed out after ${timeoutMs}ms`),
660-),
656+() => controller.abort(new Error(`ClawHub request timed out after ${timeoutMs}ms`)),
661657timeoutMs,
662658);
663659try {
@@ -682,12 +678,12 @@ async function clawhubRequest(
682678}
683679}
684680685-async function readErrorBody(response: Response): Promise<string> {
681+async function readErrorBody(response: Response, timeoutMs?: number): Promise<string> {
686682try {
687683const snippet = await readResponseTextSnippet(response, {
688684maxBytes: CLAWHUB_ERROR_BODY_MAX_BYTES,
689685maxChars: CLAWHUB_ERROR_BODY_MAX_CHARS,
690-chunkTimeoutMs: DEFAULT_FETCH_TIMEOUT_MS,
686+chunkTimeoutMs: resolveClawHubRequestTimeoutMs(timeoutMs),
691687});
692688return snippet || response.statusText || `HTTP ${response.status}`;
693689} catch {
@@ -699,8 +695,9 @@ async function buildClawHubError(
699695response: Response,
700696url: URL,
701697hasToken: boolean,
698+timeoutMs?: number,
702699): Promise<ClawHubRequestError> {
703-let body = await readErrorBody(response);
700+let body = await readErrorBody(response, timeoutMs);
704701if (response.status === 429) {
705702const suffix = formatRateLimitSuffix(response.headers, hasToken);
706703if (suffix) {
@@ -731,14 +728,18 @@ function formatRateLimitSuffix(headers: Headers, hasToken: boolean): string {
731728async function fetchJson<T>(params: ClawHubRequestParams): Promise<T> {
732729const { response, url, hasToken } = await clawhubRequest(params);
733730if (!response.ok) {
734-throw await buildClawHubError(response, url, hasToken);
731+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
735732}
736-return parseClawHubJsonBody<T>(response, url);
733+return parseClawHubJsonBody<T>(response, url, params.timeoutMs);
737734}
738735739-async function parseClawHubJsonBody<T>(response: Response, url: URL): Promise<T> {
736+async function parseClawHubJsonBody<T>(
737+response: Response,
738+url: URL,
739+timeoutMs?: number,
740+): Promise<T> {
740741const buffer = await readResponseWithLimit(response, CLAWHUB_JSON_MAX_BYTES, {
741-chunkTimeoutMs: DEFAULT_FETCH_TIMEOUT_MS,
742+chunkTimeoutMs: resolveClawHubRequestTimeoutMs(timeoutMs),
742743onOverflow: ({ size, maxBytes }) =>
743744new Error(
744745`ClawHub ${url.pathname} response exceeded ${maxBytes} bytes (${size} bytes received)`,
@@ -1016,9 +1017,13 @@ export async function fetchClawHubSkillInstallResolution(params: {
10161017});
10171018const isStructuredBlock = [403, 409, 410, 423].includes(response.status);
10181019if (!response.ok && !isStructuredBlock) {
1019-throw await buildClawHubError(response, url, hasToken);
1020+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
10201021}
1021-return parseClawHubJsonBody<ClawHubSkillInstallResolutionResponse>(response, url);
1022+return parseClawHubJsonBody<ClawHubSkillInstallResolutionResponse>(
1023+response,
1024+url,
1025+params.timeoutMs,
1026+);
10221027}
1023102810241029export async function fetchClawHubSkillVerification(params: {
@@ -1094,7 +1099,7 @@ export async function fetchClawHubSkillCard(params: {
10941099 skipAuth,
10951100});
10961101if (!response.ok) {
1097-throw await buildClawHubError(response, url, hasToken);
1102+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
10981103}
10991104const bytes = await readClawHubResponseBytes({
11001105 response,
@@ -1129,7 +1134,7 @@ export async function downloadClawHubPackageArchive(params: {
11291134fetchImpl: params.fetchImpl,
11301135});
11311136if (!response.ok) {
1132-throw await buildClawHubError(response, url, hasToken);
1137+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
11331138}
11341139const bytes = await readClawHubResponseBytes({
11351140 response,
@@ -1208,7 +1213,7 @@ export async function downloadClawHubPackageArchive(params: {
12081213fetchImpl: params.fetchImpl,
12091214});
12101215if (!response.ok) {
1211-throw await buildClawHubError(response, url, hasToken);
1216+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
12121217}
12131218const bytes = await readClawHubResponseBytes({
12141219 response,
@@ -1255,7 +1260,7 @@ export async function downloadClawHubSkillArchive(params: {
12551260},
12561261});
12571262if (!response.ok) {
1258-throw await buildClawHubError(response, url, hasToken);
1263+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
12591264}
12601265const bytes = await readClawHubResponseBytes({
12611266 response,
@@ -1298,7 +1303,7 @@ export async function downloadClawHubSkillArchiveUrl(params: {
12981303 skipAuth,
12991304});
13001305if (!response.ok) {
1301-throw await buildClawHubError(response, url, hasToken);
1306+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
13021307}
13031308const bytes = await readClawHubResponseBytes({
13041309 response,
@@ -1335,7 +1340,7 @@ export async function downloadClawHubGitHubSkillArchive(params: {
13351340fetchImpl: params.fetchImpl,
13361341});
13371342if (!response.ok) {
1338-throw await buildClawHubError(response, url, hasToken);
1343+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
13391344}
13401345const bytes = await readClawHubResponseBytes({
13411346 response,
@@ -1395,7 +1400,7 @@ export async function reportClawHubSkillInstallTelemetry(params: {
13951400},
13961401});
13971402if (!response.ok) {
1398-throw await buildClawHubError(response, url, hasToken);
1403+throw await buildClawHubError(response, url, hasToken, params.timeoutMs);
13991404}
14001405}
14011406此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。