Skip to content

Commit 0cab306

Browse files
authored
backport: fix: make sure the handler resolves in all cases (#515)
1 parent 4bacfd7 commit 0cab306

File tree

2 files changed

+65
-13
lines changed

2 files changed

+65
-13
lines changed

index.js

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -232,27 +232,27 @@ function fastifyMultipart (fastify, options, done) {
232232
bb
233233
.on('field', onField)
234234
.on('file', onFile)
235+
.on('end', cleanup)
236+
.on('finish', cleanup)
235237
.on('close', cleanup)
236-
.on('error', onEnd)
237-
.on('end', onEnd)
238-
.on('finish', onEnd)
238+
.on('error', cleanup)
239239

240240
bb.on('partsLimit', function () {
241241
const err = new PartsLimitError()
242242
onError(err)
243-
process.nextTick(() => onEnd(err))
243+
process.nextTick(() => cleanup(err))
244244
})
245245

246246
bb.on('filesLimit', function () {
247247
const err = new FilesLimitError()
248248
onError(err)
249-
process.nextTick(() => onEnd(err))
249+
process.nextTick(() => cleanup(err))
250250
})
251251

252252
bb.on('fieldsLimit', function () {
253253
const err = new FieldsLimitError()
254254
onError(err)
255-
process.nextTick(() => onEnd(err))
255+
process.nextTick(() => cleanup(err))
256256
})
257257

258258
request.pipe(bb)
@@ -378,18 +378,15 @@ function fastifyMultipart (fastify, options, done) {
378378
currentFile = null
379379
}
380380

381-
function onEnd (err) {
382-
cleanup()
383-
384-
ch(err || lastError)
385-
}
386-
387381
function cleanup (err) {
388382
request.unpipe(bb)
389-
// in node 10 it seems that error handler is not called but request.aborted is set
383+
390384
if ((err || request.aborted) && currentFile) {
391385
currentFile.destroy()
386+
currentFile = null
392387
}
388+
389+
ch(err || lastError || null)
393390
}
394391

395392
return parts

test/multipart.test.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,3 +634,58 @@ test('should not miss fields if part handler takes much time than formdata parsi
634634
await once(res, 'end')
635635
t.pass('res ended successfully')
636636
})
637+
638+
test('should not freeze when error is thrown during processing', { skip: process.versions.node.startsWith('14') }, async function (t) {
639+
t.plan(2)
640+
const app = Fastify()
641+
642+
app
643+
.register(multipart)
644+
645+
app
646+
.post('/', async (request, reply) => {
647+
const files = request.files()
648+
649+
for await (const { file } of files) {
650+
try {
651+
const storage = new stream.Writable({
652+
write (chunk, encoding, callback) {
653+
// trigger error:
654+
callback(new Error('write error'))
655+
}
656+
})
657+
658+
await pump(file, storage)
659+
} catch {}
660+
}
661+
662+
return { message: 'done' }
663+
})
664+
665+
await app.listen()
666+
667+
const { port } = app.server.address()
668+
669+
const form = new FormData()
670+
const opts = {
671+
hostname: '127.0.0.1',
672+
port,
673+
path: '/',
674+
headers: form.getHeaders(),
675+
method: 'POST'
676+
}
677+
const req = http.request(opts)
678+
679+
try {
680+
form.append('upload', fs.createReadStream(filePath))
681+
form.pipe(req)
682+
} catch {}
683+
684+
const [res] = await once(req, 'response')
685+
t.equal(res.statusCode, 200)
686+
res.resume()
687+
await once(res, 'end')
688+
t.pass('res ended successfully!')
689+
690+
await app.close()
691+
})

0 commit comments

Comments
 (0)