feat(console): enforce 10mb request body limit on zen api
This commit is contained in:
parent
436cd39d14
commit
9e39f1c8c7
5 changed files with 109 additions and 1 deletions
55
packages/console/app/test/body.test.ts
Normal file
55
packages/console/app/test/body.test.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import { MAX_BODY_BYTES, readJsonBody } from "../src/routes/zen/util/body"
|
||||
import { BodyLimitError } from "../src/routes/zen/util/error"
|
||||
|
||||
function post(body: BodyInit, headers?: Record<string, string>) {
|
||||
return new Request("https://opencode.ai/zen/v1/chat/completions", { method: "POST", body, headers })
|
||||
}
|
||||
|
||||
function streamOf(...chunks: Uint8Array[]) {
|
||||
return new ReadableStream<Uint8Array>({
|
||||
start(c) {
|
||||
for (const chunk of chunks) c.enqueue(chunk)
|
||||
c.close()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
describe("readJsonBody", () => {
|
||||
test("parses a body within the limit", async () => {
|
||||
const body = await readJsonBody(post(JSON.stringify({ model: "test", messages: [] })))
|
||||
expect(body).toEqual({ model: "test", messages: [] })
|
||||
})
|
||||
|
||||
test("parses a body of exactly the limit", async () => {
|
||||
const wrapper = '{"padding":""}'
|
||||
const json = `{"padding":"${"x".repeat(MAX_BODY_BYTES - wrapper.length)}"}`
|
||||
const body = await readJsonBody(post(json))
|
||||
expect(body.padding.length).toBe(MAX_BODY_BYTES - wrapper.length)
|
||||
})
|
||||
|
||||
test("parses a streamed body split mid multi-byte character", async () => {
|
||||
const bytes = new TextEncoder().encode('{"name":"café"}')
|
||||
// 13 splits the two-byte "é", exercising incremental decoding
|
||||
const body = await readJsonBody(post(streamOf(bytes.slice(0, 13), bytes.slice(13))))
|
||||
expect(body).toEqual({ name: "café" })
|
||||
})
|
||||
|
||||
test("rejects when the declared content-length exceeds the limit", async () => {
|
||||
const request = post("{}", { "content-length": String(MAX_BODY_BYTES + 1) })
|
||||
await expect(readJsonBody(request)).rejects.toThrow(BodyLimitError)
|
||||
})
|
||||
|
||||
test("rejects an oversized stream without a content-length header", async () => {
|
||||
const chunk = new TextEncoder().encode("x".repeat(1024 * 1024))
|
||||
let sent = 0
|
||||
const stream = new ReadableStream<Uint8Array>({
|
||||
pull(c) {
|
||||
if (sent > MAX_BODY_BYTES) return c.close()
|
||||
sent += chunk.length
|
||||
c.enqueue(chunk)
|
||||
},
|
||||
})
|
||||
await expect(readJsonBody(post(stream))).rejects.toThrow(BodyLimitError)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue