I have been working on this problem for two days now, and I am stuck. I am using Node.js with Express, and I am trying to implement an upload form. Basically, I want the form to
I will attempt to answer my own question...
So after some trial and error with Formidable, I simply gave up on it and switched over to Multiparty. Multiparty ACTUALLY cancels the upload when an error is emitted which was huge.
My Solution
So my solution utilizes client-side size and type checking (not shown in code). The request is then sent to the server. At the server, I check again if the file size and type are correct BEFORE WRITING TO DISK. I am able to do this by using Multiparty's part
event. If they are not correct then I simply send a response with a 413 error. (Thanks to josh3736 for clarifying what is supposed to happen in the browser.) After sending back a 413, the behavior of the browser is a little sporadic. For the browser that I was testing in, it just showed a pending
post request. I believe this behavior is due to the fact that the entirety of the form has not be handled, therefore, it will not accept any responses. This may not seem like the most elegant way to deal with it since no error code is displayed, but this behavior will only be encountered by malicious users who bypass the client-side checking (my site is dependent on Javascript so all users will have it enabled if they want to use my site). So that is my solution in words, now for some code...
app.post('/profile/profile_pic', urlencoded, function (req, res) {
var path = absolutePath + '/public/images/users/' + req.session.userId + '/';
var maxSize = 3146000; // 3MB
var options = {uploadDir: path};
var form = new multiparty.Form();
form.on('error', function(message) {
res.status = 413;
res.send(413, 'Upload too large');
res.end();
});
form.on('file', function(name, file) {
var type = file.headers['content-type'];
type = type.split('/');
type = type[1];
fs.rename(file.path, path + 'profile.' + type);
path = '/images/users/' + req.session.userId + '/profile.' + type;
});
form.on('part', function(part) {
var type = part.headers['content-type'];
var size = part.byteCount - part.byteOffset;
if(type != 'image/jpeg' && type != 'image/png' && type != 'image/gif' != 'application/pdf' || size > maxSize)
{
this.emit('error');
}
});
form.on('close', function(){
res.json({err: 0, path: path});
});
form.parse(req);
});