fix: parse discord retry delays strictly · openclaw/openclaw@1d28dd8
steipete
·
2026-05-29
·
via Recent Commits to openclaw:main
File tree
extensions/discord/src/internal
| Original file line number | Diff line number | Diff line change |
|---|
@@ -12,6 +12,9 @@ export function readDiscordCode(body: unknown): number | undefined {
|
12 | 12 | return undefined; |
13 | 13 | } |
14 | 14 | |
| 15 | +const RETRY_AFTER_HEADER_DELAY_RE = /^\d+$/; |
| 16 | +const RETRY_AFTER_BODY_SECONDS_RE = /^(?:\d+\.?\d*|\.\d+)$/; |
| 17 | + |
15 | 18 | export function readDiscordMessage(body: unknown, fallback: string): string { |
16 | 19 | const value = |
17 | 20 | body && typeof body === "object" && "message" in body |
@@ -24,19 +27,21 @@ function readRetryAfterHeader(value: string | null, now = Date.now()): number |
|
24 | 27 | if (!value) { |
25 | 28 | return undefined; |
26 | 29 | } |
27 | | -const seconds = Number(value); |
28 | | -if (Number.isFinite(seconds)) { |
29 | | -return seconds; |
| 30 | +const trimmed = value.trim(); |
| 31 | +if (RETRY_AFTER_HEADER_DELAY_RE.test(trimmed)) { |
| 32 | +return Number(trimmed); |
30 | 33 | } |
31 | | -const retryAt = Date.parse(value); |
| 34 | +const retryAt = Date.parse(trimmed); |
32 | 35 | return Number.isFinite(retryAt) ? (retryAt - now) / 1000 : undefined; |
33 | 36 | } |
34 | 37 | |
35 | 38 | function coerceRetryAfterSeconds(value: unknown): number | undefined { |
36 | | -if (typeof value !== "number" && typeof value !== "string") { |
37 | | -return undefined; |
38 | | -} |
39 | | -const seconds = typeof value === "number" ? value : Number(value); |
| 39 | +const seconds = |
| 40 | +typeof value === "number" |
| 41 | + ? value |
| 42 | + : typeof value === "string" && RETRY_AFTER_BODY_SECONDS_RE.test(value.trim()) |
| 43 | + ? Number(value.trim()) |
| 44 | + : undefined; |
40 | 45 | return Number.isFinite(seconds) && seconds >= 0 ? Math.max(0, seconds) : undefined; |
41 | 46 | } |
42 | 47 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -532,6 +532,19 @@ describe("RequestClient", () => {
|
532 | 532 | await expectRateLimitError(client.get("/channels/c1/messages"), { retryAfter: 7 }); |
533 | 533 | }); |
534 | 534 | |
| 535 | +it("rejects non-decimal Retry-After numeric strings", async () => { |
| 536 | +const client = new RequestClient("test-token", { |
| 537 | +queueRequests: false, |
| 538 | +fetch: async () => |
| 539 | +new Response(JSON.stringify({ message: "Slow down", retry_after: "1e3", global: false }), { |
| 540 | +status: 429, |
| 541 | +headers: { "Retry-After": "0x10" }, |
| 542 | +}), |
| 543 | +}); |
| 544 | + |
| 545 | +await expectRateLimitError(client.get("/channels/c1/messages"), { retryAfter: 1 }); |
| 546 | +}); |
| 547 | + |
535 | 548 | it("tracks invalid requests and exposes bucket scheduler metrics", async () => { |
536 | 549 | const client = new RequestClient("test-token", { |
537 | 550 | queueRequests: false, |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。