mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-09 05:19:32 +08:00
fix(tlon): add timeout to SSE client fetch calls (CWE-400) (#5926)
Add timeout protection to prevent indefinite hangs when Urbit server becomes unresponsive or network partition occurs. Changes: - Add AbortSignal.timeout(30_000) to 7 one-shot fetch calls - Add AbortController with 60s connection timeout to SSE stream fetch (clears timeout after headers received to avoid aborting active stream) Affected methods: sendSubscription, connect, openStream, poke, scry, close Fixes #5266 Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,7 @@ export class UrbitSSEClient {
|
||||
Cookie: this.cookie,
|
||||
},
|
||||
body: JSON.stringify([subscription]),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
|
||||
if (!response.ok && response.status !== 204) {
|
||||
@@ -130,6 +131,7 @@ export class UrbitSSEClient {
|
||||
Cookie: this.cookie,
|
||||
},
|
||||
body: JSON.stringify(this.subscriptions),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
|
||||
if (!createResp.ok && createResp.status !== 204) {
|
||||
@@ -152,6 +154,7 @@ export class UrbitSSEClient {
|
||||
json: "Opening API channel",
|
||||
},
|
||||
]),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
|
||||
if (!pokeResp.ok && pokeResp.status !== 204) {
|
||||
@@ -164,14 +167,23 @@ export class UrbitSSEClient {
|
||||
}
|
||||
|
||||
async openStream() {
|
||||
// Use AbortController with manual timeout so we only abort during initial connection,
|
||||
// not after the SSE stream is established and actively streaming.
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 60_000);
|
||||
|
||||
const response = await fetch(this.channelUrl, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "text/event-stream",
|
||||
Cookie: this.cookie,
|
||||
},
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
// Clear timeout once connection established (headers received)
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Stream connection failed: ${response.status}`);
|
||||
}
|
||||
@@ -279,6 +291,7 @@ export class UrbitSSEClient {
|
||||
Cookie: this.cookie,
|
||||
},
|
||||
body: JSON.stringify([pokeData]),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
|
||||
if (!response.ok && response.status !== 204) {
|
||||
@@ -296,6 +309,7 @@ export class UrbitSSEClient {
|
||||
headers: {
|
||||
Cookie: this.cookie,
|
||||
},
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -364,6 +378,7 @@ export class UrbitSSEClient {
|
||||
Cookie: this.cookie,
|
||||
},
|
||||
body: JSON.stringify(unsubscribes),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
|
||||
await fetch(this.channelUrl, {
|
||||
@@ -371,6 +386,7 @@ export class UrbitSSEClient {
|
||||
headers: {
|
||||
Cookie: this.cookie,
|
||||
},
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error?.(`Error closing channel: ${String(error)}`);
|
||||
|
||||
Reference in New Issue
Block a user