fix(backend): apply the large-body limit to every spelling Express routes
req.path was compared to the canonical '/api/voice/extract' only, but Express routes case-insensitively and ignores a trailing slash by default. '/api/voice/extract/' therefore reached the controller with the 100 kb parser, and 413'd every recording past ~20 seconds — a failure that reads as a broken microphone rather than a routing detail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -74,6 +74,20 @@ describe('createJsonBodyParser', () => {
|
||||
expect((res.body as ProbeBody).keys).toBe(1);
|
||||
});
|
||||
|
||||
it('widens the limit for the spellings Express itself accepts', async () => {
|
||||
// Express routes case-insensitively and ignores a trailing slash by default, so these
|
||||
// all reach the voice controller. Any of them taking the 100 kb parser would 413 a
|
||||
// real recording and read as a broken microphone.
|
||||
for (const path of [
|
||||
'/api/voice/extract/',
|
||||
'/API/Voice/Extract',
|
||||
'/api/Voice/extract/',
|
||||
]) {
|
||||
const res = await request(buildApp()).post(path).send(bodyOfKb(300));
|
||||
expect(res.status).toBe(200);
|
||||
}
|
||||
});
|
||||
|
||||
it('does not widen the limit for a path that merely looks similar', async () => {
|
||||
for (const path of [
|
||||
'/api/voice/extract/extra',
|
||||
|
||||
@@ -24,12 +24,22 @@ export const VOICE_BODY_LIMIT = '10mb';
|
||||
* the endpoint rejected every real recording with a 500. One explicit branch has no such
|
||||
* coupling, and is covered by body-parsers.spec.ts.
|
||||
*/
|
||||
/**
|
||||
* Express routes case-insensitively and ignores a trailing slash unless configured
|
||||
* otherwise, so `/API/Voice/Extract/` reaches the same controller. Matching only the
|
||||
* canonical spelling would hand those requests the 100 kb parser and 413 every real
|
||||
* recording — a failure that looks like a broken microphone, not a routing detail.
|
||||
*/
|
||||
function isVoiceExtractPath(path: string): boolean {
|
||||
return path.toLowerCase().replace(/\/+$/, '') === VOICE_EXTRACT_PATH;
|
||||
}
|
||||
|
||||
export function createJsonBodyParser(): RequestHandler {
|
||||
const voiceParser = json({ limit: VOICE_BODY_LIMIT });
|
||||
const defaultParser = json();
|
||||
|
||||
return (req: Request, res: Response, next: NextFunction) =>
|
||||
req.path === VOICE_EXTRACT_PATH
|
||||
isVoiceExtractPath(req.path)
|
||||
? voiceParser(req, res, next)
|
||||
: defaultParser(req, res, next);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user