mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix(clawrouter): cancel non-OK usage response body before throwing (#109525)
* fix(clawrouter): cancel non-OK usage response body before throwing When fetchClawRouterUsage receives a non-OK response, it throws without cancelling the response body. The finally block calls release() which cleans up the dispatcher, but the unconsumed body stays open. Cancel the body before throwing, matching the pattern in guard-adapters (#109196) and fetchOpenRouterModels. * test: use explicit ClawRouter placeholder token --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
co-authored by
Peter Steinberger
parent
f0aa2c892f
commit
ea6ed38e20
@@ -205,14 +205,49 @@ describe("ClawRouter usage", () => {
|
||||
expect(snapshot.billing).toEqual([{ type: "spend", amount: 0, unit: "USD" }]);
|
||||
});
|
||||
|
||||
it("does not expose an upstream error body", async () => {
|
||||
it("cancels non-OK usage response body before throwing", async () => {
|
||||
let cancelled = false;
|
||||
const response = new Response(
|
||||
new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(new TextEncoder().encode("unauthorized"));
|
||||
},
|
||||
cancel() {
|
||||
cancelled = true;
|
||||
},
|
||||
}),
|
||||
{ status: 403 },
|
||||
);
|
||||
await expect(
|
||||
fetchClawRouterUsage({
|
||||
token: "proxy-key",
|
||||
timeoutMs: 5000,
|
||||
fetchGuard: mockFetchGuard(new Response("secret details", { status: 403 })),
|
||||
fetchGuard: mockFetchGuard(response),
|
||||
}),
|
||||
).rejects.toThrow("ClawRouter usage request failed (HTTP 403)");
|
||||
expect(cancelled).toBe(true);
|
||||
});
|
||||
|
||||
it("observes peer closure when a real loopback server returns non-OK", async () => {
|
||||
let responseClosed = false;
|
||||
const { baseUrl, requests } = await startUsageServer((_req, res) => {
|
||||
res.on("close", () => {
|
||||
responseClosed = true;
|
||||
});
|
||||
res.writeHead(503, { "content-type": "text/plain" });
|
||||
res.write("service unavailable");
|
||||
});
|
||||
|
||||
await expect(
|
||||
fetchClawRouterUsage({
|
||||
token: "test-auth-token",
|
||||
baseUrl,
|
||||
timeoutMs: 5000,
|
||||
}),
|
||||
).rejects.toThrow("ClawRouter usage request failed (HTTP 503)");
|
||||
|
||||
expect(requests).toEqual(["GET /v1/usage"]);
|
||||
expect(responseClosed).toBe(true);
|
||||
});
|
||||
|
||||
it("bounds successful usage response bodies", async () => {
|
||||
|
||||
@@ -113,6 +113,7 @@ export async function fetchClawRouterUsage(params: {
|
||||
);
|
||||
try {
|
||||
if (!response.ok) {
|
||||
await response.body?.cancel().catch(() => undefined);
|
||||
throw new Error(`ClawRouter usage request failed (HTTP ${response.status})`);
|
||||
}
|
||||
const payload = await readClawRouterUsagePayload(response, params.timeoutMs);
|
||||
|
||||
Reference in New Issue
Block a user