fix(e2e): reject declared oversized probe bodies · openclaw/openclaw@7f1fa65
vincentkoc
·
2026-06-19
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -20,6 +20,15 @@ if (!Number.isFinite(maxBodyBytes) || maxBodyBytes <= 0) {
|
20 | 20 | } |
21 | 21 | |
22 | 22 | async function readBoundedResponseText(response, byteLimit) { |
| 23 | +const contentLength = response.headers?.get?.("content-length"); |
| 24 | +if (contentLength && /^\d+$/u.test(contentLength)) { |
| 25 | +const parsedContentLength = Number(contentLength); |
| 26 | +if (Number.isSafeInteger(parsedContentLength) && parsedContentLength > byteLimit) { |
| 27 | +await response.body?.cancel().catch(() => undefined); |
| 28 | +throw new Error(`chat completions response body exceeded ${byteLimit} bytes`); |
| 29 | +} |
| 30 | +} |
| 31 | + |
23 | 32 | const reader = response.body?.getReader(); |
24 | 33 | if (!reader) { |
25 | 34 | return ""; |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -105,6 +105,15 @@ function matchesDegradedReadyExpectation(body) {
|
105 | 105 | } |
106 | 106 | |
107 | 107 | async function readBoundedResponseText(response, byteLimit) { |
| 108 | +const contentLength = response.headers?.get?.("content-length"); |
| 109 | +if (contentLength && /^\d+$/u.test(contentLength)) { |
| 110 | +const parsedContentLength = Number(contentLength); |
| 111 | +if (Number.isSafeInteger(parsedContentLength) && parsedContentLength > byteLimit) { |
| 112 | +await response.body?.cancel().catch(() => undefined); |
| 113 | +throw new Error(`${url} probe body exceeded ${byteLimit} bytes`); |
| 114 | +} |
| 115 | +} |
| 116 | + |
108 | 117 | const reader = response.body?.getReader(); |
109 | 118 | if (!reader) { |
110 | 119 | return ""; |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -336,4 +336,26 @@ describe("scripts/e2e/lib/openai-chat-tools/client.mjs", () => {
|
336 | 336 | server.close(); |
337 | 337 | } |
338 | 338 | }); |
| 339 | + |
| 340 | +it("rejects declared oversized chat completion bodies before waiting on the stream", async () => { |
| 341 | +const server = createServer((_request, response) => { |
| 342 | +response.writeHead(200, { |
| 343 | +"content-length": "65", |
| 344 | +"content-type": "application/json", |
| 345 | +}); |
| 346 | +response.flushHeaders(); |
| 347 | +}); |
| 348 | +const port = await listen(server); |
| 349 | +try { |
| 350 | +const startedAt = Date.now(); |
| 351 | +const result = await runClient(port, { OPENCLAW_OPENAI_CHAT_TOOLS_MAX_BODY_BYTES: "64" }); |
| 352 | + |
| 353 | +expect(result.error).toBeUndefined(); |
| 354 | +expect(result.status).not.toBe(0); |
| 355 | +expect(result.stderr).toContain("chat completions response body exceeded 64 bytes"); |
| 356 | +expect(Date.now() - startedAt).toBeLessThan(3_500); |
| 357 | +} finally { |
| 358 | +server.close(); |
| 359 | +} |
| 360 | +}); |
339 | 361 | }); |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -259,6 +259,45 @@ describe("scripts/e2e/lib/upgrade-survivor/probe-gateway.mjs", () => {
|
259 | 259 | } |
260 | 260 | }); |
261 | 261 | |
| 262 | +it("rejects declared oversized probe bodies before waiting on the stream", async () => { |
| 263 | +const server = createHttpServer((_request, response) => { |
| 264 | +response.writeHead(200, { |
| 265 | +"content-length": "65", |
| 266 | +"content-type": "application/json", |
| 267 | +}); |
| 268 | +response.flushHeaders(); |
| 269 | +}); |
| 270 | +const baseUrl = await listen(server); |
| 271 | +const out = path.join(makeTempDir(), "oversized.json"); |
| 272 | +const startedAt = Date.now(); |
| 273 | +try { |
| 274 | +const result = await runProbe( |
| 275 | +[ |
| 276 | +"--base-url", |
| 277 | +baseUrl, |
| 278 | +"--path", |
| 279 | +"/healthz", |
| 280 | +"--expect", |
| 281 | +"live", |
| 282 | +"--out", |
| 283 | +out, |
| 284 | +"--timeout-ms", |
| 285 | +"1000", |
| 286 | +], |
| 287 | +5_000, |
| 288 | +{ OPENCLAW_UPGRADE_SURVIVOR_PROBE_MAX_BODY_BYTES: "64" }, |
| 289 | +); |
| 290 | + |
| 291 | +expect(result.error).toBeUndefined(); |
| 292 | +expect(result.status).not.toBe(0); |
| 293 | +expect(result.stderr).toContain(`${baseUrl}/healthz probe body exceeded 64 bytes`); |
| 294 | +expect(fs.existsSync(out)).toBe(false); |
| 295 | +expect(Date.now() - startedAt).toBeLessThan(3_500); |
| 296 | +} finally { |
| 297 | +server.close(); |
| 298 | +} |
| 299 | +}); |
| 300 | + |
262 | 301 | it("bounds probes when a server accepts the connection but never responds", async () => { |
263 | 302 | const sockets = new Set<Socket>(); |
264 | 303 | const server = createTcpServer((socket) => { |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。