The declared data-URL MIME was a claim the boundary believed. Every image decision now comes from the bytes: the container is sniffed, walked to its own end marker, refused when metadata segments remain, and refused above a 4096px edge or 16MP. The request path adds a per-caller sliding-window budget (429 + Retry-After) and a body deadline (408), so a flood, a stalled body, or a decode bomb fails before a provider call. Log hygiene is part of the contract: refusal copy is fixed prose, the bucket key is a salted hash kept in memory only, and the acceptance test asserts no image bytes reach the process log.
59 lines
1.9 KiB
JavaScript
59 lines
1.9 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { PassThrough } from 'node:stream';
|
|
|
|
import { BodyError, readJsonBody } from '../src/http-body.js';
|
|
|
|
const bodyStream = chunks => {
|
|
const stream = new PassThrough();
|
|
for (const chunk of chunks) stream.write(chunk);
|
|
stream.end();
|
|
return stream;
|
|
};
|
|
|
|
test('reads a bounded JSON request body', async () => {
|
|
const parsed = await readJsonBody(bodyStream([Buffer.from('{"consent":'), Buffer.from('true}')]), { maxBytes: 1024 });
|
|
assert.deepEqual(parsed, { consent: true });
|
|
});
|
|
|
|
test('refuses a body above the byte limit instead of buffering it', async () => {
|
|
await assert.rejects(
|
|
() => readJsonBody(bodyStream([Buffer.alloc(64, 0x61)]), { maxBytes: 16 }),
|
|
error => {
|
|
assert.ok(error instanceof BodyError);
|
|
assert.equal(error.code, 'too_large');
|
|
assert.equal(error.status, 413);
|
|
return true;
|
|
},
|
|
);
|
|
});
|
|
|
|
test('refuses malformed JSON with a client error', async () => {
|
|
await assert.rejects(
|
|
() => readJsonBody(bodyStream([Buffer.from('{not json')]), { maxBytes: 1024 }),
|
|
error => {
|
|
assert.ok(error instanceof BodyError);
|
|
assert.equal(error.code, 'invalid_json');
|
|
assert.equal(error.status, 400);
|
|
return true;
|
|
},
|
|
);
|
|
});
|
|
|
|
test('gives up on a body that never finishes and stops reading it', async () => {
|
|
const stalled = new PassThrough();
|
|
stalled.write(Buffer.from('{"consent":true'));
|
|
const started = Date.now();
|
|
await assert.rejects(
|
|
() => readJsonBody(stalled, { maxBytes: 1024, timeoutMs: 40 }),
|
|
error => {
|
|
assert.ok(error instanceof BodyError);
|
|
assert.equal(error.code, 'body_timeout');
|
|
assert.equal(error.status, 408);
|
|
return true;
|
|
},
|
|
);
|
|
assert.ok(Date.now() - started < 2_000, 'the deadline must fire promptly');
|
|
assert.equal(stalled.isPaused(), true, 'the stalled body must stop being read after the deadline');
|
|
});
|