-
Notifications
You must be signed in to change notification settings - Fork 7.3k
streams: swallows consumed data when destination stream ends #7151
Comments
IMO they are more than reasonable. I had saw a similar problem when I was replacing response.end implementation. Seems a similar problem happening here that the socket is getting closed before the message is sent. Great catch. |
I am looking into this, and I agree that on the http server side we should be sanely notifying of error states for socket level errors (see #7065) but that's not entirely what's happening in your test case. What you have is data ready to be consumed (the initial But before that happens you are ending the sink. If you listen for Can you be more explicit about the behavior you're expecting? |
After inspecting in details I realized something that the test cases assume the stream is synced but it should be async here to work properly. If you set (note, this is definitely not a cool hack though) |
That sometimes happens too but I haven't been able to capture that reliably in a test case yet.
Yes, I figured that out. :-) But having to take care of that manually makes it difficult to string random libraries together and it's almost impossible to debug when it goes wrong. To illustrate, I found out about this issue because of a web service proxy where the final chunk went missing once every few thousand requests. You can imagine what tracking down a bug like that is like.
I'm not sure. I think I would like res.end() to check for "primed" data and include that in the final chunk but I don't know whether that's a reasonable expectation. I suppose it could get complicated if you have chains or trees of streams. On the other hand, it seems reasonable (to me) insofar that http.OutgoingMessage#end() and net.Socket#destroySoon() are understood to be "finish at your leisure" signals.
Thanks for the suggestion. I've tried that and some other things but I can't make it work, the data is always lost. |
Okay, I have something of a test case for that. It's somewhat related to this issue so I'm posting it here. var http = require('http');
http.createServer(function(req, res) {
res.end('pong');
this.close();
}).listen(function() {
var options = {
agent: false,
host: this.address().address,
port: this.address().port,
method: 'POST',
};
var req = http.request(options);
req.on('response', function(res) {
res.on('data', ondata);
res.on('end', function() {
console.log('end');
res.removeListener('data', ondata);
});
function ondata() {
console.log('data');
req.write('ping');
}
});
req.write('ping');
}); Prints:
And when you strace it:
(I'm somewhat disappointed that Linux doesn't return EPIPE for the last write, it knows that the peer is already gone.) The second ping is sent at a time when node knows that the socket has been closed by the remote side. I suppose it's more complicated when /cc @indutny - you can probably make this work on Linux by adding EPOLLRDHUP to the event mask. Behavior with master is identical, by the way. |
@bnoordhuis ... I haven't run the case myself yet but I assume this is still an issue? |
Yes, all three still fail with v0.10 and io.js v2.x. I didn't test v0.12 but it's probably safe to assume it's not fixed there either. |
The test cases are contrived for brevity but reflect a real world (and IMO reasonable) use case.
Second test case:
http.OutgoingMessage#pipe() consumes the data from the Readable but no data is sent when http.OutgoingMessage#end() is called. No error is generated either, the data just silently disappears.
The story is pretty much the same for net.Socket. Seems like a fairly grave bug to me. Both master and v0.10 are affected.
The text was updated successfully, but these errors were encountered: