Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Response 'finish' sometimes called before stream completely written #5712

Closed
geek opened this issue Jun 17, 2013 · 7 comments
Closed

Response 'finish' sometimes called before stream completely written #5712

geek opened this issue Jun 17, 2013 · 7 comments

Comments

@geek
Copy link
Member

geek commented Jun 17, 2013

This is a difficult issue to reproduce, but I have narrowed it down to the following reproducing code:

var Assert = require('assert');
var Fs = require('fs');
var Http = require('http');
var Stream = require('stream');


var chunkTimes = 5;
var readTimes = 0;
var filePath = __dirname + '/biggie.js';
var responseJs = Fs.readFileSync(filePath).toString();

var expectedBody = '';
for (var i = 0, il = chunkTimes; i < il; ++i) {
    expectedBody += responseJs;
}

var streamServer = Http.createServer(function (req, res) {

    var fileStream = new Stream.Readable();
    fileStream._read = function (n) {

        if (readTimes++ === chunkTimes) {
            fileStream.push(null);
        }
        else {
            fileStream.push(responseJs);
        }
    };

    res.once('finish', function () {

        req.destroy();
    });

    fileStream.pipe(res);
}).listen(0);


streamServer.once('listening', function () {

    Http.get('http://127.0.0.1:' + streamServer.address().port, function (res) {

        var receivedFile = '';
        res.on('readable', function () {

            receivedFile += res.read().toString();
        });

        res.once('end', function () {

            Assert(receivedFile === expectedBody, 'Not equal results');
            process.exit();
        });
    }).on('error', function (err) {

        console.log(err);
    });
});

The key is to have a decent sized biggie.js file to try sending, mine needed to be over 2mb.

When you run the above code you should see the exception, if not try increasing the size of biggie.js.

@tjfontaine
Copy link

I believe this is a dup of #5688 can you apply 3c7945b and see if it solves it for you?

@geek geek closed this as completed Jun 17, 2013
@geek geek reopened this Jun 17, 2013
@geek
Copy link
Member Author

geek commented Jun 17, 2013

Actually, no this didn't fix the issue.

@geek
Copy link
Member Author

geek commented Jun 17, 2013

if instead of calling req.destroy() req.socket.destroySoon is called it works.

@geek
Copy link
Member Author

geek commented Jun 18, 2013

I tried upgrading to node 0.10.12 and this is still an issue.

@isaacs
Copy link

isaacs commented Jun 21, 2013

Confirmed. This is definitely a bug, and not a dupe.

@isaacs
Copy link

isaacs commented Jun 23, 2013

To clarify: 'finish' should not happen before the last written chunk is flushed.

isaacs added a commit to isaacs/node-v0.x-archive that referenced this issue Jun 24, 2013
Closes nodejs#5712

When ending, if there is a pending write, don't emit finish until the
subsequent close or drain event, so that we know it's fully flushed.
@isaacs
Copy link

isaacs commented Jun 25, 2013

See #5739 (comment)

Bottom line: We can't make this guarantee for HTTP streams. When 'finish' emits, it means that it's been sent to the socket, but NOT that it's necessarily made it to the client successfully.

I think that this sucks. But, if we try to make this guarantee, it'll fail for HTTPS streams anyway, and there's no way to fix that prior to 0.12.

@isaacs isaacs closed this as completed Jun 25, 2013
tjfontaine added a commit to tjfontaine/node that referenced this issue Jul 1, 2013
A pooled https agent may get a Connection: close, but never finish
destroying the socket as the prior request had already emitted finish
likely from a pipe.

Since the socket is not marked as destroyed it may get reused by the
agent pool and result in an ECONNRESET.

re: nodejs#5712 nodejs#5739
tjfontaine added a commit that referenced this issue Jul 9, 2013
A pooled https agent may get a Connection: close, but never finish
destroying the socket as the prior request had already emitted finish
likely from a pipe.

Since the socket is not marked as destroyed it may get reused by the
agent pool and result in an ECONNRESET.

re: #5712 #5739
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants