Skip to content

Commit 990916c

Browse files
Alix-007steipete
andauthored
fix(firecrawl): reject malformed 2xx response envelopes (#111210)
* fix(firecrawl): reject malformed JSON envelopes * test(firecrawl): use canonical plugin config fixture Co-authored-by: Alix-007 <[email protected]> --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent 792f5b7 commit 990916c

2 files changed

Lines changed: 78 additions & 9 deletions

File tree

extensions/firecrawl/src/firecrawl-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Firecrawl plugin module implements firecrawl client behavior.
22
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
3-
import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
3+
import { readProviderJsonObjectResponse } from "openclaw/plugin-sdk/provider-http";
44
import {
55
DEFAULT_CACHE_TTL_MINUTES,
66
markdownToText,
@@ -71,7 +71,7 @@ async function readFirecrawlJsonResponse(
7171
label: string,
7272
opts?: { maxBytes?: number },
7373
): Promise<Record<string, unknown>> {
74-
return await readProviderJsonResponse<Record<string, unknown>>(response, label, opts);
74+
return await readProviderJsonObjectResponse(response, label, opts);
7575
}
7676

7777
type FirecrawlSearchParams = {

extensions/firecrawl/src/firecrawl-tools.test.ts

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,39 @@ describe("firecrawl tools", () => {
11991199
).rejects.toThrow("Firecrawl Search API error: malformed JSON response");
12001200
});
12011201

1202+
it.each([
1203+
["null", "null"],
1204+
["array", "[]"],
1205+
])("rejects a %s Firecrawl search envelope with a stable provider error", async (kind, body) => {
1206+
global.fetch = vi.fn(
1207+
async () =>
1208+
new Response(body, {
1209+
status: 200,
1210+
headers: { "content-type": "application/json" },
1211+
}),
1212+
) as typeof fetch;
1213+
1214+
await expect(
1215+
runActualFirecrawlSearch({
1216+
cfg: {
1217+
plugins: {
1218+
entries: {
1219+
firecrawl: {
1220+
config: {
1221+
webSearch: {
1222+
baseUrl: "https://api.firecrawl.dev",
1223+
},
1224+
},
1225+
},
1226+
},
1227+
},
1228+
} as OpenClawConfig,
1229+
query: `openclaw malformed ${kind} search`,
1230+
access: "keyless",
1231+
}),
1232+
).rejects.toThrow("Firecrawl Search API error: malformed JSON response");
1233+
});
1234+
12021235
it("bounds successful Firecrawl JSON bodies before parsing", async () => {
12031236
const streamed = createStreamingResponse({
12041237
chunkCount: 32,
@@ -1251,15 +1284,51 @@ describe("firecrawl tools", () => {
12511284
).rejects.toThrow("Firecrawl fetch failed: malformed JSON response");
12521285
});
12531286

1287+
it.each([
1288+
["null", "null"],
1289+
["array", "[]"],
1290+
])("rejects a %s Firecrawl scrape envelope with a stable provider error", async (kind, body) => {
1291+
global.fetch = vi.fn(
1292+
async () =>
1293+
new Response(body, {
1294+
status: 200,
1295+
headers: { "content-type": "application/json" },
1296+
}),
1297+
) as typeof fetch;
1298+
1299+
await expect(
1300+
runActualFirecrawlScrape({
1301+
cfg: {
1302+
plugins: {
1303+
entries: {
1304+
firecrawl: {
1305+
config: {
1306+
webFetch: {
1307+
baseUrl: "https://api.firecrawl.dev",
1308+
},
1309+
},
1310+
},
1311+
},
1312+
},
1313+
} as OpenClawConfig,
1314+
url: `https://example.com/firecrawl-malformed-${kind}-scrape`,
1315+
extractMode: "markdown",
1316+
access: "keyless",
1317+
}),
1318+
).rejects.toThrow("Firecrawl fetch failed: malformed JSON response");
1319+
});
1320+
12541321
it("respects positive numeric overrides for scrape and cache behavior", () => {
12551322
const cfg = {
1256-
tools: {
1257-
web: {
1258-
fetch: {
1259-
firecrawl: {
1260-
onlyMainContent: false,
1261-
maxAgeMs: 1234,
1262-
timeoutSeconds: 42,
1323+
plugins: {
1324+
entries: {
1325+
firecrawl: {
1326+
config: {
1327+
webFetch: {
1328+
onlyMainContent: false,
1329+
maxAgeMs: 1234,
1330+
timeoutSeconds: 42,
1331+
},
12631332
},
12641333
},
12651334
},

0 commit comments

Comments
 (0)