-
-
Notifications
You must be signed in to change notification settings - Fork 33.5k
Closed
Labels
confirmed-bugIssues with confirmed bugs.Issues with confirmed bugs.httpIssues or PRs related to the http subsystem.Issues or PRs related to the http subsystem.
Description
When tracking requests of a HTTP-Server - with server.on('request') and res.on('finish', ...) or res.on('close', ...) - we noticed inconsistent results over time (requests that are never finished or closed).
We tracked this race condition down to the following reproducable test case:
- connection is aborted from client side
- socket gets destroyed (but socket-"close"-event still not delivered)
- trying to send response
- socket-"close" event delivered
-> No "close" and no "finish" event on response!
var common = require('../common');
var assert = require('assert');
var http = require('http');
var clientRequest = null;
var serverResponseFinishedOrClosed = 0;
var server = http.createServer(function (req, res) {
console.log('server: request');
res.on('finish', function () {
console.log('server: response finish');
serverResponseFinishedOrClosed++;
});
res.on('close', function () {
console.log('server: response close');
serverResponseFinishedOrClosed++;
});
console.log('client: aborting request');
clientRequest.abort();
setImmediate(function() {
console.log('server: tick 1' + (req.connection.destroyed ? ' (connection destroyed!)' : ''));
setImmediate(function () {
console.log('server: tick 2' + (req.connection.destroyed ? ' (connection destroyed!)' : ''));
console.log('server: sending response');
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Response\n');
console.log('server: res.end() returned');
setImmediate(function () {
server.close();
});
});
});
});
server.on('listening', function () {
console.log('server: listening on port ' + common.PORT);
console.log('client: starting request');
var options = {port: common.PORT, path: '/'};
clientRequest = http.get(options, function () {});
clientRequest.on('error', function () {});
});
server.on('connection', function (connection) {
console.log('server: connection');
connection.on('close', function () { console.log('server: connection close'); });
});
server.on('close', function () {
console.log('server: close');
assert.equal(serverResponseFinishedOrClosed, 1, 'Expected either one "finish" or one "close" event on the response for aborted connections (got ' + serverResponseFinishedOrClosed + ')');
});
server.listen(common.PORT);- With one more
setImmediate()call, you get a response close event (which is fine) - With one less
setImmediate()call, you get a response finish event (which is fine) - Reproducable with io.js 1.6.3, io.js 1.3.0, io.js 1.1.0, node 0.12.0
- In node 0.10 the race-condition was different: This test case works fine, but with one more
setImmediate(), two events are delivered (finish AND close)
Metadata
Metadata
Assignees
Labels
confirmed-bugIssues with confirmed bugs.Issues with confirmed bugs.httpIssues or PRs related to the http subsystem.Issues or PRs related to the http subsystem.