Skip to content

Commit 8f5a5af

Browse files
committed
implement file count limit
1 parent ca5a7a2 commit 8f5a5af

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

src/index.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,13 @@ const getBoundary = (contentType: string) => {
9191
return match ? `--${match[1]}` : null
9292
}
9393

94-
const parseMultipart = (body: string, boundary: string) => {
94+
const parseMultipart = (body: string, boundary: string, { fileCountLimit }: MultipartOptions) => {
9595
// Split the body into an array of parts
9696
const parts = body.split(new RegExp(`${boundary}(--)?`)).filter((part) => !!part && /content-disposition/i.test(part))
9797
const parsedBody: Record<string, (File | string)[]> = {}
98+
99+
if (fileCountLimit && parts.length > fileCountLimit) throw new Error(`Too many files. Limit: ${fileCountLimit}`)
100+
98101
// Parse each part into a form data object
99102
// biome-ignore lint/complexity/noForEach: <explanation>
100103
parts.forEach((part) => {
@@ -126,13 +129,13 @@ type MultipartOptions = Partial<{
126129
}>
127130

128131
const multipart =
129-
(opts: MultipartOptions = {}) =>
132+
({ limit, errorFn, ...opts }: MultipartOptions & ParserOptions = {}) =>
130133
async (req: ReqWithBody, res: Response, next: NextFunction) => {
131134
if (hasBody(req.method!)) {
132135
req.body = await p((x) => {
133136
const boundary = getBoundary(req.headers['content-type']!)
134-
if (boundary) return parseMultipart(x, boundary)
135-
})(req, res, next)
137+
if (boundary) return parseMultipart(x, boundary, opts)
138+
}, limit, errorFn)(req, res, next)
136139
next()
137140
} else next()
138141
}

test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,4 +442,23 @@ test('should throw on limit with custom error message', async () => {
442442
}).expect(413, 'Payload too large. Limit: 1KB')
443443
})
444444

445+
test('should throw multipart if amount of files exceeds limit', async () => {
446+
const server = createServer(async (req: ReqWithBody, res) => {
447+
await multipart({ fileCountLimit: 1 })(req, res, (err) => {
448+
if (err) res.writeHead(413).end(err.message)
449+
else res.end(req.body)
450+
})
451+
})
452+
453+
const fd = new FormData()
454+
455+
fd.set('file1', new File(['hello world'], 'hello.txt', { type: 'text/plain' }))
456+
fd.set('file2', new File(['bye world'], 'bye.txt', { type: 'text/plain' }))
457+
458+
await makeFetch(server)('/', {
459+
body: fd,
460+
method: 'POST',
461+
}).expect(413, 'Too many files. Limit: 1')
462+
})
463+
445464
test.run()

0 commit comments

Comments
 (0)