Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

piped request end and close events seem not to be fired #295

Closed
abissens opened this issue Apr 18, 2022 · 8 comments
Closed

piped request end and close events seem not to be fired #295

abissens opened this issue Apr 18, 2022 · 8 comments

Comments

@abissens
Copy link

Hi,

Piping request stream to busboy seems to prevent request end and close event from firing
Could this indicate some leak issues ?

Test code

test('request end/close events are fired', done => {
      let [end, close] = [false, false];
      http.createServer((req, res) => {
          req.on('end', () => end = true)
              .on('close', () => close = true)
              .pipe(busboy({headers: req.headers}))
              .on('close', () => res.writeHead(204, {'Connection': 'close'}).end());
      }).listen(8080);
  
      const req = http.request({
          host: 'localhost',
          port: 8080,
          method: 'POST',
          headers: {
              'Content-Type': 'multipart/form-data; boundary=--------------------------719223781919663014682861'
          }
      }, (res) => {
          expect(res.statusCode).toEqual(204);
          expect([close, end]).toEqual([true, true]);
          done();
      });
      Readable.from(body).pipe(req);
  })
  
  const body = ['----------------------------719223781919663014682861',
      'Content-Disposition: form-data; name="file"; filename="test_file"',
      'Content-Type: application/octet-stream',
      '',
      'File content',
      '----------------------------719223781919663014682861--'].join('\r\n')

I also noticed that when the busboy stream forced end is commented out the test passes

System
Node v16.14.0
Busboy 1.5.0

PS: this also keeps from using the promisified stream.pipeline with busboy since the resulting promise wouldn't resolve

@mscdex
Copy link
Owner

mscdex commented Apr 18, 2022

You're not reading the file data from the busboy instance. If you don't do that then the busboy stream will never end/close.

At the very minimum you need something like:

const bb = busboy({headers: req.headers});
bb.on('file', (fieldName, file) => {
  file.resume(); // discards the file data
});
// ...
req.pipe(bb);

@abissens
Copy link
Author

abissens commented Apr 19, 2022

I think that it resumes by default. But still even when explicitly resuming the test don't pass
May be the request reader stream should be explicitly resumed when forcing busboy end
I've tried this : abissens@322c4cf

@mscdex
Copy link
Owner

mscdex commented Apr 19, 2022

AFAIK there is no leak happening here. Once you respond to the request from the busboy 'close' handler, the request goes away.

@mscdex
Copy link
Owner

mscdex commented Apr 19, 2022

I'll remove it anyway, it just means that useless (or potentially useful depending on your use case) data can possibly pass through busboy. If that ever becomes an issue for someone, we can revisit it I guess.

@mscdex mscdex closed this as completed in a8e2ac0 Apr 19, 2022
@slewsys
Copy link

slewsys commented Jul 10, 2022

Perhaps this.end() should be conditioned on something (maybe type of input)?

I'm using async-busboy patched for busboy version 1.5 (see, e.g., @revoinc/async-busboy). npm run test completes successfully, but times out with busboy version 1.6.

@mscdex
Copy link
Owner

mscdex commented Jul 10, 2022

@slewsys Does it work if you add stream.end() in your tests? If so, I don't think that is asking too much 🤷‍♂️ . It's hard to please everyone.

@slewsys
Copy link

slewsys commented Jul 11, 2022

Good exercise :) I'll try to provide a solution. In the mean time, I'm able to successfully use @revoinc/async-busboy with busboy v1.6 in another package, the Koa Joi router. So it would appear that it is indeed the async-busboy testsuite that is at fault.

@slewsys
Copy link

slewsys commented Jul 11, 2022

Yes, adding stream.end() works, thank you!

In particular, the async-busboy test suite defines a request as:

import Stream from "stream"
function request () {
  const stream = new Stream.PassThrough()
  stream.headers = {
    'content-type': 'multipart/form-data; boundary=---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
  }
  stream.write([
    '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
    'Content-Disposition: form-data; name="file_name_0"',
    '',
    'super alpha file',
    '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
    ...
    ].join('\r\n'))
  return stream
}
 

Inserting stream.end() after stream.write() and before return stream allows the tests to complete successfully with busboy v1.6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants