diff --git a/backend/src/common/body-parsers.spec.ts b/backend/src/common/body-parsers.spec.ts index ecde076..d64b859 100644 --- a/backend/src/common/body-parsers.spec.ts +++ b/backend/src/common/body-parsers.spec.ts @@ -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', diff --git a/backend/src/common/body-parsers.ts b/backend/src/common/body-parsers.ts index c845d91..97278da 100644 --- a/backend/src/common/body-parsers.ts +++ b/backend/src/common/body-parsers.ts @@ -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); }