Skip to content

Commit 7cff78d

Browse files
committed
add fileSizeLimit
1 parent eafa122 commit 7cff78d

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const hasBody = (method: string) => ['POST', 'PUT', 'PATCH', 'DELETE'].in
1212

1313
const defaultPayloadLimit = 104857600 // 100KB
1414

15-
export type LimitErrorFn = (payloadLimit: number) => Error
15+
export type LimitErrorFn = (limit: number) => Error
1616

1717
export type ParserOptions = Partial<{
1818
payloadLimit: number
@@ -91,7 +91,9 @@ const getBoundary = (contentType: string) => {
9191
return match ? `--${match[1]}` : null
9292
}
9393

94-
const parseMultipart = (body: string, boundary: string, { fileCountLimit }: MultipartOptions) => {
94+
const defaultFileSizeLimitErrorFn: LimitErrorFn = (limit) => new Error(`File too large. Limit: ${limit} bytes`)
95+
96+
const parseMultipart = (body: string, boundary: string, { fileCountLimit, fileSizeLimit, fileSizeLimitErrorFn = defaultFileSizeLimitErrorFn }: MultipartOptions) => {
9597
// Split the body into an array of parts
9698
const parts = body.split(new RegExp(`${boundary}(--)?`)).filter((part) => !!part && /content-disposition/i.test(part))
9799
const parsedBody: Record<string, (File | string)[]> = {}
@@ -104,6 +106,8 @@ const parseMultipart = (body: string, boundary: string, { fileCountLimit }: Mult
104106
const [headers, ...lines] = part.split('\r\n').filter((part) => !!part)
105107
const data = lines.join('\r\n').trim()
106108

109+
if (fileSizeLimit && data.length > fileSizeLimit) throw fileSizeLimitErrorFn(fileSizeLimit)
110+
107111
// Extract the name and filename from the headers
108112
const name = /name="(.+?)"/.exec(headers)![1]
109113
const filename = /filename="(.+?)"/.exec(headers)
@@ -126,6 +130,7 @@ const parseMultipart = (body: string, boundary: string, { fileCountLimit }: Mult
126130
type MultipartOptions = Partial<{
127131
fileCountLimit: number
128132
fileSizeLimit: number
133+
fileSizeLimitErrorFn: LimitErrorFn
129134
}>
130135

131136
const multipart =

test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,3 +459,39 @@ test('should throw multipart if amount of files exceeds limit', async () => {
459459
method: 'POST',
460460
}).expect(413, 'Too many files. Limit: 1')
461461
})
462+
463+
test('should throw multipart if exceeds allowed file size', async () => {
464+
const server = createServer(async (req: ReqWithBody, res) => {
465+
await multipart({ fileSizeLimit: 10 })(req, res, (err) => {
466+
if (err) res.writeHead(413).end(err.message)
467+
else res.end(req.body)
468+
})
469+
})
470+
471+
const fd = new FormData()
472+
473+
fd.set('file', new File(['hello world'], 'hello.txt', { type: 'text/plain' }))
474+
475+
await makeFetch(server)('/', {
476+
body: fd,
477+
method: 'POST',
478+
}).expect(413, 'File too large. Limit: 10 bytes')
479+
})
480+
481+
test('should throw multipart if exceeds allowed file size with a custom error', async () => {
482+
const server = createServer(async (req: ReqWithBody, res) => {
483+
await multipart({ fileSizeLimit: 10, fileSizeLimitErrorFn: (limit) => new Error(`File too large. Limit: ${limit / 1024}KB`) })(req, res, (err) => {
484+
if (err) res.writeHead(413).end(err.message)
485+
else res.end(req.body)
486+
})
487+
})
488+
489+
const fd = new FormData()
490+
491+
fd.set('file', new File(['hello world'], 'hello.txt', { type: 'text/plain' }))
492+
493+
await makeFetch(server)('/', {
494+
body: fd,
495+
method: 'POST',
496+
}).expect(413, 'File too large. Limit: 0.009765625KB')
497+
})

0 commit comments

Comments
 (0)