-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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
Streams: req.on('end') is sometimes called, sometimes not #2156
Comments
I can confirm that sometimes the 'end' event is not emitted. Here is my testcase: var http = require('http');
var limit = 10;
var reqCount = 0;
var endCount = 0;
var server = http.createServer();
server.on('request', function (req, res) {
reqCount++;
var body = '';
req
.setEncoding('utf-8')
.on('data', function(data) {
body += data;
if (body.length === limit) {
res.statusCode = 413;
res.end('Your message is too big for my little chat');
}
})
.on('end', function() {
endCount++;
nextRequest();
});
});
server.on('listening', nextRequest);
function nextRequest() {
//limit++;
var r = http.request({
port: 8080,
method: 'POST'
}, function () {
if (reqCount !== endCount) {
console.error(`Missing END!\nRequests: ${reqCount}\nEnded: ${endCount}`);
process.exit(1);
}
});
r.write('a'.repeat(limit));
r.end();
}
server.listen(8080); |
This issue is labelled as "question", but it is actually a bug. |
@targos Thanks for the test case. I've confirmed the bug. |
I have tried to debug this but it is difficult because of all the async stuff (stack trace basically contains only the process.nextTick stuff). |
@targos I have been digging through the http module recently so I thought I'd give this a go but I'm not able to reproduce. I should be seeing the |
@matthewloring Try this. var http = require('http');
var limit = 10;
var length = 10000;
var reqCount = 0;
var endCount = 0;
var server = http.createServer();
server.on('request', function (req, res) {
reqCount++;
var body = '';
req
.setEncoding('utf-8')
.on('data', function(data) {
body += data;
if (body.length > limit) {
res.statusCode = 413;
res.end('Your message is too big for my little chat');
}
})
.on('end', function() {
endCount++;
nextRequest();
});
});
server.on('listening', nextRequest);
function nextRequest() {
length = length + 1000;
console.log(length, reqCount, endCount);
var r = http.request({
port: 8080,
method: 'POST'
}, function () {
if (reqCount !== endCount) {
console.error(`Missing END!\nRequests: ${reqCount}\nEnded: ${endCount}`);
process.exit(1);
}
});
r.write('a'.repeat(length));
r.end();
}
server.listen(8080); I get error (Error: read ECONNRESET), don't know why. |
Thanks! I am able to reproduce it with this example! |
With further testing I have found that req.on('end') stops being called when the data size is greater than 65435. When the data is longer than 65443 characters, it is broken up into two calls to req.on('data'). An 'end' event is only emitted once all data has been consumed through calls to on('data'). Since the res object is receiving an end event before all data is consumed from the req object, req.on('end') will not execute until after the callback that compares the counts. I'm not sure what exactly is happening in the 65435 to 65443 range but my guess is that it is related to event emitter buffering. Though counter intuitive, I think this is actually working as intended. |
@matthewloring it's great you found out why it happens. I felt like this is going on too. From the streams standpoint, |
@iliakan To the best of my understanding of the spec, readable streams are not required to call see: https://github.com/nodejs/io.js/blob/master/lib/_http_outgoing.js#L507 |
@matthewloring: well, But there's no Actually, the event flow for
Only these 2 events. Maybe the logic is like this?
Then it'd be sane to skip both events here. |
@iliakan After reading around here (https://github.com/nodejs/io.js/blob/master/lib/_http_server.js#L257) it appears that 'close' is only triggered when a client has opened a TCP connection (causing a 'connection' event to be fired) and the socket associated with that connection closes prematurely. |
@matthewloring Is it your opinion that this is not a bug? Although puzzling at first glance, it is working as intended? Or am I misunderstanding? /cc @trevnorris @targos |
IIRC |
Summary for your guys to triage more easily. Assuming that:
It is possible that if the data is not fully consumed and the connection is explicitly closed (for example, limit reached), then both events do not trigger. That is "an intended", right? P.S. It seems to me that "yes", so I'm closing this. |
here is a simple solution using Content-Length header, when the length of body >= content-length, we assume the stream end:
|
Let's say I have a
server.on('request')
handler, with the code:If the message is too big (413) should
on('end')
event trigger?P.S. I'm asking because it does trigger in this case (10 bytes limit), but it does not trigger in the case of a larger limit (1000000 bytes limit). The behavior - sometimes it triggers and sometimes not - seems weird.
The text was updated successfully, but these errors were encountered: