question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

File.resume() docx file busboy finish event

See original GitHub issue

Hello!

In order to discard not allowed extensions I use file.resume() to get off not allowed files and let start with another or finish the form upload.

All went smooth until some type of .docx knock my door.

The problem is when we upload this type of file, Busboy never gets finish signal and browser connection hangs until time out, with other not allowed files they get rejected, Busboy knows when the upload finished.

$> node -v
    v10.15.0

Busboy version:

    "busboy": "^0.3.0",

To reproduce this behaviour:

$> curl https://transfer.sh/K1mPC/f2.docx -o f2.docx
$> file -bi 'f2.docx' 
    application/zip; charset=binary
$> node server.bug.js 
$> curl -i -X POST -H "Content-Type: multipart/form-data" -F "data=@f2.docx" http://localhost:3000/busboy

    HTTP/1.1 100 Continue

    curl: (56) Recv failure: Connection reinitialized by the remote machine

-Server Output:

    readFirstBytes...
    File [data]: filename: f2.docx, encoding: 7bit, mimetype: application/octet-stream
    readFirstBytes...
    Rejected file of type docx
    File ON ERROR [f2.docx] ERROR ->  EXT NOT ALLOWED
    File ON END [f2.docx] Finished
    Reached the end, but did not read anything.

I can upload other doc or docx files and they get rejected and busboy.on(‘finish’) gets executed:

$> curl https://transfer.sh/pyFD3/f1.docx -o f1.docx
$> file -bi 'f1.docx' 
    application/octet-stream; charset=binary
$> curl -i -X POST -H "Content-Type: multipart/form-data" -F "data=@f1.docx" http://localhost:3000/busboy

    HTTP/1.1 100 Continue

    HTTP/1.1 200 OK
    Date: Tue, 22 Jan 2019 07:35:28 GMT
    Connection: keep-alive
    Content-Length: 18

    Done parsing form!

-Server Output:

    readFirstBytes...
    File [data]: filename: f1.docx, encoding: 7bit, mimetype: application/octet-stream
    readFirstBytes...
    Rejected file of type docx
    File ON ERROR [f1.docx] ERROR ->  EXT NOT ALLOWED
    File ON END [f1.docx] Finished
    Reached the end, but did not read anything.
    Done parsing form!

server.js

const http = require('http');
const fs = require('fs');
const path = require('path');
const Busboy = require('busboy');
const fileType = require('file-type');
const port = 3000;
const host = "localhost";

/**
 * Create Server
 */
const server = http.createServer((req, res) => {
   const url = req.url;
   if (url === '/') {
      return renderForm(res);
   } else if (url === '/busboy' && req.method === 'POST') {
      return uploadFiles(req, res);
   } else {
      return notFound(res);
   }
})

server.listen(port, host, () => {
   console.log(`Server running at http://${host}:${port}/`);
 });


/**
 * Upload Files
 * 
 * @param {*} req 
 * @param {*} res 
 */
const uploadFiles = (req, res) => {
   const opt = {
      dest: path.join(__dirname, '.'),
      limits: {
         fileSize: 1024 * 1024,
         files: 2
      }
   };

   var busboy = new Busboy({
      headers: req.headers,
      opt: opt
   });


   busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {

      function readFirstBytes() {
         console.log("readFirstBytes...")
         var chunk = file.read(fileType.minimumBytes);
         if (!chunk) return file.once('readable', readFirstBytes);
         const type = fileType(chunk);
         let ext = "foo";
         if (type) ext = type.ext
         file.unshift(chunk);

         if (ext === 'jpeg' || ext === 'jpg' || ext === 'png') {
            console.log("checkExtention allow ---> ", ext)
            file.pipe(fs.createWriteStream('./' + filename));
         } else {
            console.log('Rejected file of type ' + ext);
            file.resume().on('end', () => {
               console.log('Reached the end, but did not read anything.');
            }); // Drain file stream to continue processing form
            file.emit('error', 'EXT NOT ALLOWED')
            file.emit('close')
            file.emit('end')
         }
      }

      readFirstBytes();

      console.log('File [' + fieldname + ']: filename: ' + filename + ', encoding: ' + encoding + ', mimetype: ' + mimetype);

      file.on('error', function (e) {
         console.log('File ON ERROR [' + filename + '] ERROR -> ', e);
      }).on('end', function () {
         console.log('File ON END [' + filename + '] Finished');
      }).on('limit', () => {
         console.log(`bytes limit ${opt.limits.fileSize} exceeded on File: ${filename}`);
         file.resume(); //fires finish
      });

   }).on('filesLimit', () => {
      console.log('MAX FILES REACHED, LIMIT IS: ', opt.limits.files)
   }).on('finish', (f) => {
      console.log('Done parsing form!');
      return res.end('Done parsing form!');
   });

   req.pipe(busboy);

}

/**
 * Not Found Res
 * 
 * @param {*} res 
 */
const notFound = (res) => {
   res.statusCode = 404;
   res.setHeader('Content-Type', 'text/html');
   res.end('<h1>404 NOT FOUND</h1>');
}

/**
 * Render Upload Form
 * 
 * @param {*} res 
 */
const renderForm = (res) => {
   res.write('<h1>Upload Files<h1>'); 
   res.end(
      '<form action="/busboy" enctype="multipart/form-data" method="post">' +
      '<input type="text" name="title"><br>' +
      '<input type="file" name="upload" multiple="multiple"><br>' +
      '<input type="submit" value="Upload">' +
      '</form>'
   );
}

Thanks for reading.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
mscdexcommented, Feb 9, 2019

Alright as noted in the upstream issue, this should’ve been fixed in node v10.15.1.

1reaction
mscdexcommented, Jan 22, 2019
Read more comments on GitHub >

github_iconTop Results From Across the Web

busboy not firing finish event - Stack Overflow
You need to consume the file stream somehow. For testing purposes you can ignore the data by adding file.resume(); inside the file event...
Read more >
busboy, upload few files, 'finish' event doesn't work properly
Hello,. I trying to upload few files through one input[type=file] with attribue 'multiple'. All work fine but 'finish' event firing ...
Read more >
Resumable Multi-File Uploader using XMLHttpRequest ...
A detailed walkthrough on how to create a resumable multi- file uploader, ... Uploader using XMLHttpRequest, NodeJs Express and Busboy.
Read more >
How to Create a Resumable MultiFile Uploader with NodeJs
For this project, I'll show you how to build a file uploader that handles multiple files at once with the ability to pause...
Read more >
File uploads using Node.js - CodeForGeek
In HTML form you must mention enctype=”multipart/form-data” else multer will not work. Performing file validation: To perform validation on Server end, multer ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found