feat: Allow custom storage engines to prematurely terminate stream without calling cb(err) #1277
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Greetings,
I added a single line of code which allows authors of custom storage engines to call
file.stream.destroy()
to terminate the stream and still allow them to callcb(null, info)
instead ofcb(err)
in events such asfile.stream.on('data', (data: Buffer) => {})
Without this feature, to accomplish this goal, multer has to pipe the entire stream which is costly (performance/bandwidth/time) for bigger files.
Since the
destroy
method is not utilized in the code as is, this should not affect current users and their storage engines.After debugging the code, the only difference using this feature is that busboy's
finish
event is not triggered (which is the primary issue since the variablereadFinished
isn't set totrue
). However, this should be fine as thedone
function is still called which triggersreq.unpipe(busboy)
and removes all event listeners.The
finish
event still triggers normally when you don't destroy the stream.I also placed the line of code at the end of the
_handleFile
callback to ensure the author's custom_handleFile
already executes. All an author has to do is destroy the stream at some point before callingcb(null, info)
.I'd greatly appreciate it if you can review this! Thanks!
Edit:
I should also note that when using
file.stream.destory()
on larger files (roughly >3MB from my experience), Fetch/XHR requests will still hang onto their connection unlessres.header('Connection', 'close')
is called at some point.However, doing the above will result in FF and Chrome returning
Network Reset
errors rather than whatever the programmer returns as the status code and response body. See here for details. A proper response is generated with Postman (which I can confirm from testing) so it's 100% a browser issue. As such, Multer could add that header to the response object, but due to this issue, I think it's best to temporarily leave that portion in the hands of the authors of custom storage engines or their consumers.Edit 2:
To those interested, I opened issues with Mozilla and Chromium to address the issue of XHR/Fetch requests resulting in network errors instead of producing the expected API response when large file uploads are terminated when setting the
Connection
response header toclose