{"action":"created","issue":{"url":"https://api.github.com/repos/joyent/node/issues/9066","labels_url":"https://api.github.com/repos/joyent/node/issues/9066/labels{/name}","comments_url":"https://api.github.com/repos/joyent/node/issues/9066/comments","events_url":"https://api.github.com/repos/joyent/node/issues/9066/events","html_url":"https://github.com/joyent/node/issues/9066","id":54892103,"number":9066,"title":"http server close() doesn't end http keep-alive connections","user":{"login":"kanongil","id":753512,"avatar_url":"https://avatars.githubusercontent.com/u/753512?v=3","gravatar_id":"","url":"https://api.github.com/users/kanongil","html_url":"https://github.com/kanongil","followers_url":"https://api.github.com/users/kanongil/followers","following_url":"https://api.github.com/users/kanongil/following{/other_user}","gists_url":"https://api.github.com/users/kanongil/gists{/gist_id}","starred_url":"https://api.github.com/users/kanongil/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kanongil/subscriptions","organizations_url":"https://api.github.com/users/kanongil/orgs","repos_url":"https://api.github.com/users/kanongil/repos","events_url":"https://api.github.com/users/kanongil/events{/privacy}","received_events_url":"https://api.github.com/users/kanongil/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":16,"created_at":"2015-01-20T14:54:44Z","updated_at":"2015-05-15T07:11:49Z","closed_at":null,"body":"When a http client uses `Connection: keep-alive`, `http.Server#close()` doesn't end stale/free keep-alive connections, thus preventing the process from exiting. I can replicate the behavior on both 0.10.x and master.\r\n\r\n### Failing test\r\n\r\nserver.js:\r\n```javascript\r\nvar fork = require('child_process').fork;\r\nvar http = require('http');\r\n\r\nhttp.createServer(function(req, res) {\r\n  this.close();\r\n  res.end('test\\n');\r\n}).listen(8000, '127.0.0.1', function() {\r\n  fork('./client.js');\r\n});\r\n\r\nprocess.on('exit', function(code) {\r\n  console.log('server exit', code);\r\n});\r\n```\r\n\r\nclient.js:\r\n```javascript\r\nvar http = require('http');\r\nvar Agent = require('forever-agent');\r\nvar agent = new Agent();\r\n\r\nhttp.get({ port: 8000, agent: agent }, function(res) {\r\n  res.pipe(process.stdout);\r\n  setTimeout(function() {\r\n    console.log('timeout');\r\n    agent.sockets['localhost:8000'].forEach(function(socket) {\r\n      socket.destroy();\r\n    })\r\n  }, 5000);\r\n});\r\n\r\nprocess.on('exit', function(code) {\r\n  console.log('client exit', code);\r\n});\r\n```\r\n\r\n#### Result on node 0.10.35\r\n```\r\n$ NODE_DEBUG=net node server.js \r\nNET: 3110 listen2 127.0.0.1 8000 4 false\r\nNET: 3110 _listen2: create a handle\r\nNET: 3110 bind to 127.0.0.1\r\nNET: 3111 connect: find host localhost\r\nNET: 3110 onconnection\r\nNET: 3111 afterConnect\r\nNET: 3111 _read\r\nNET: 3110 _read\r\nNET: 3110 Socket._read readStart\r\nNET: 3111 Socket._read readStart\r\nNET: 3111 afterWrite 0 { domain: null, bytes: 64, oncomplete: [Function: afterWrite] }\r\nNET: 3111 afterWrite call cb\r\nNET: 3110 onread undefined 0 64 64\r\nNET: 3110 got data\r\nNET: 3110 SERVER _emitCloseIfDrained\r\nNET: 3110 SERVER handle? false   connections? 1\r\nNET: 3111 onread undefined 0 123 123\r\nNET: 3111 got data\r\nNET: 3110 afterWrite 0 { domain: null, bytes: 118, oncomplete: [Function: afterWrite] }\r\nNET: 3110 afterWrite call cb\r\nNET: 3110 afterWrite 0 { domain: null, bytes: 5, oncomplete: [Function: afterWrite] }\r\nNET: 3110 afterWrite call cb\r\ntest\r\ntimeout\r\nNET: 3111 destroy undefined\r\nNET: 3111 destroy\r\nNET: 3111 close\r\nNET: 3111 close handle\r\nNET: 3111 emit close\r\nNET: 3110 onread EOF undefined undefined NaN\r\nNET: 3110 EOF\r\nclient exit 0\r\nNET: 3110 onSocketEnd { highWaterMark: 16384,\r\n  buffer: [],\r\n  length: 0,\r\n  pipes: null,\r\n  pipesCount: 0,\r\n  flowing: false,\r\n  ended: true,\r\n  endEmitted: false,\r\n  reading: false,\r\n  calledRead: true,\r\n  sync: false,\r\n  needReadable: true,\r\n  emittedReadable: false,\r\n  readableListening: false,\r\n  objectMode: false,\r\n  defaultEncoding: 'utf8',\r\n  ranOut: false,\r\n  awaitDrain: 0,\r\n  readingMore: false,\r\n  decoder: null,\r\n  encoding: null }\r\nNET: 3110 onSocketFinish\r\nNET: 3110 oSF: ended, destroy { highWaterMark: 16384,\r\n  buffer: [],\r\n  length: 0,\r\n  pipes: null,\r\n  pipesCount: 0,\r\n  flowing: false,\r\n  ended: true,\r\n  endEmitted: true,\r\n  reading: false,\r\n  calledRead: true,\r\n  sync: false,\r\n  needReadable: false,\r\n  emittedReadable: true,\r\n  readableListening: false,\r\n  objectMode: false,\r\n  defaultEncoding: 'utf8',\r\n  ranOut: false,\r\n  awaitDrain: 0,\r\n  readingMore: false,\r\n  decoder: null,\r\n  encoding: null }\r\nNET: 3110 destroy undefined\r\nNET: 3110 destroy\r\nNET: 3110 close\r\nNET: 3110 close handle\r\nNET: 3110 has server\r\nNET: 3110 SERVER _emitCloseIfDrained\r\nNET: 3110 SERVER: emit close\r\nNET: 3110 emit close\r\nserver exit 0\r\n```\r\n\r\n#### Expected result\r\nServer exits immediately after the client has received the response data.\r\n\r\n#### Observed result\r\nServer is kept alive until the client destroys the http keep-alive socket. Similar behavior is observed in master when using this client script:\r\n```javascript\r\nvar http = require('http');\r\nvar agent = new http.Agent({ keepAlive:true });\r\n\r\nhttp.get({ port: 8000, agent: agent }, function(res) {\r\n  res.pipe(process.stdout);\r\n  setTimeout(function() {\r\n    console.log('timeout');\r\n    agent.destroy();\r\n  }, 5000);\r\n});\r\n\r\nprocess.on('exit', function(code) {\r\n  console.log('client exit', code);\r\n});\r\n```"},"comment":{"url":"https://api.github.com/repos/joyent/node/issues/comments/102295816","html_url":"https://github.com/joyent/node/issues/9066#issuecomment-102295816","issue_url":"https://api.github.com/repos/joyent/node/issues/9066","id":102295816,"user":{"login":"ygt-mikekchar","id":3168656,"avatar_url":"https://avatars.githubusercontent.com/u/3168656?v=3","gravatar_id":"","url":"https://api.github.com/users/ygt-mikekchar","html_url":"https://github.com/ygt-mikekchar","followers_url":"https://api.github.com/users/ygt-mikekchar/followers","following_url":"https://api.github.com/users/ygt-mikekchar/following{/other_user}","gists_url":"https://api.github.com/users/ygt-mikekchar/gists{/gist_id}","starred_url":"https://api.github.com/users/ygt-mikekchar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ygt-mikekchar/subscriptions","organizations_url":"https://api.github.com/users/ygt-mikekchar/orgs","repos_url":"https://api.github.com/users/ygt-mikekchar/repos","events_url":"https://api.github.com/users/ygt-mikekchar/events{/privacy}","received_events_url":"https://api.github.com/users/ygt-mikekchar/received_events","type":"User","site_admin":false},"created_at":"2015-05-15T07:11:49Z","updated_at":"2015-05-15T07:11:49Z","body":"I haven't looked at the node source code yet, but I'm pretty sure that the problem described by @cepharum is not to do with keep-alive connections.  What's happening is that the server is set to stop accepting connections, but it *is still listening*.  It will serve exactly 1 more connection, or it will timeout when the socket times out (and then actually close).\r\n\r\nYou can observe this behaviour yourself by calling close() on the server and then send it one more request.  It will accept that request and then close immediately.  If you don't send it a request it will close when the socket times out (2 minutes after the last request by default).\r\n\r\nI think this is a bug in Node, but as I've said, I haven't looked at the code to convince myself that it isn't the desired behaviour (despite the documentation ;-) )."}}