node-tar icon indicating copy to clipboard operation
node-tar copied to clipboard

[BUG] Pipeline stream unexpectly being closed when using `extract`

Open jeferson-sb opened this issue 3 years ago • 4 comments

What / Why

When you attempt to extract a tarball through streams sometimes it will be closed with an error: [ERR_STREAM_PREMATURE_CLOSE]: Premature close, although the files are successfully extracted. No Errors Codes are shown in the process.

It seems to happen only on newer versions of Node > v18 Looking at the spec it seems now that streams that emit a close event before a end event trigger this error, so worth taking a look on that.

When

  • n/a

Where

  • n/a

How

Current Behavior

  • It throws an ERR_STREAM_PREMATURE_CLOSE Error when trying to extract

Steps to Reproduce

$ nvm install 18.7.0
$ npm install tar got
$ mkdir output
import stream from 'node:stream';
import { promisify } from 'util';
import tar from 'tar';
import got from 'got';

const pipeline = promisify(stream.pipeline);

pipeline(
  got.stream('https://codeload.github.com/npm/node-tar/tar.gz/main'),
  tar.extract({ cwd: './output' }, ['node-tar-main/lib'])
)

Expected Behavior

  • It should extract the content of the archive without any issues

References

  • Related to Next.js Issue #39321

jeferson-sb avatar Aug 09 '22 01:08 jeferson-sb

does this mean instead of https://github.com/npm/node-tar/blob/9d71c5673683d6309c75e6a85e78fa285dbe9a2d/lib/parse.js#L85-L94 you would do

    this.on('end', () => setTimeout(() => this.emit('close')))
    
    if (opt.ondone) {
      this.on(DONE, opt.ondone)
    } else {
      this.on(DONE, _ => {
        this.emit('prefinish')
        this.emit('finish')
        this.emit('end')
      })
    }

essentially? @jeferson-sb @lukekarrys

that seems on odd addition :/

webark avatar Oct 04 '22 22:10 webark

@webark yeah looks like it is related to that one line

jeferson-sb avatar Oct 05 '22 01:10 jeferson-sb

meant to say "odd" addition. I was going to try to add a test case.

webark avatar Oct 05 '22 01:10 webark

I tried adding this test

t.test('ensure an open stream is not prematuraly closed', t => {
  const file = path.resolve(tars, 'body-byte-counts.tar')
  const dir = path.resolve(extractdir, 'basic-with-stream')

  t.beforeEach(async () => {
    await rimraf(dir)
    await mkdirp(dir)
  })

  const check = async t => {
    t.equal(fs.lstatSync(path.resolve(dir, '1024-bytes.txt')).size, 1024)
    await rimraf(dir)
    t.end()
  }

  t.test('async promisey', t => {
    return pipeline(
      fs.createReadStream(file),
      x({ cwd: dir }, ['1024-bytes.txt'])
    ).then(_ => check(t))
  })

  t.end()
})

But it is still passing without any modifications to the code 🤔😔 Any ideas?

webark avatar Oct 05 '22 19:10 webark

I'm experiencing this. Is there a workaround or an expected fix?

timd73 avatar Oct 25 '22 09:10 timd73

I opened up the PR #332 which fixes the issue. I'm using my fork in a project and it is working. Hopefully it will get merged and released soon.

webark avatar Oct 25 '22 13:10 webark