isaacs/node-tar — pull request #32 by afischer-sfly (2014-03-26 05:03:28+00:00)
Title: Extract stream can emit eof error after .end() is called

Backstory: We're deploying a lot of .tgz files using NPM. We recently started observing an intermittent issue where NPM will occasionally fail to install a .tgz, with an error of "unexpected eof", even though we're able to independently verify that the .tgz file is fine. Full NPM error message is here: https://gist.github.com/afischer-sfly/9776992

I traced it down to node-tar incorrectly emitting an "unexpected eof" error in some cases. I think the following series of events can occasionally happen:

0) Data from input stream is happily piped through Extract
1) Input stream ends and calls `.end()` (at parse.js line 85) which sets `._ended` to true.
2) The `.end()` function also calls BlockStream.end(), which causes it to emit one last 'data' event followed by an 'end' event.
2) Incoming 'data' event from step 2 is handled. It happens to be the tarball's first null block, so _process (at parse.js line 121) sets `._ended` to false, because it's still waiting for the second null block. (in other words `_eofStarted` is currently false)
3) Incoming 'end' event from step 2 is handled. This triggers `_streamEnd` (which is either defined in parse.js or extract.js) which notices that `._ended `is unexpectedly false, and emits an "unexpected eof" error.
4) NPM sees the emitted error and quits

In this fix, the `._ended` flag doesn't go back to false after `.end()` sets it true. In testing it seems to fix our NPM error.