Skip to content

Commit 1dd2d01

Browse files
jfromanielloFishrock123
authored andcommitted
http: handle errors on idle sockets
This change adds a new event handler to the `error` event of the socket after it has been used by the http_client. The purpose of this change is to catch errors on *keep alived* connections from idle sockets that otherwise will cause an uncaugh error event on the application. Fix: #3595 PR-URL: #4482 Reviewed-By: Fedor Indutny <[email protected]>
1 parent 30b0d75 commit 1dd2d01

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

lib/_http_client.js

+9
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,13 @@ function socketErrorListener(err) {
282282
socket.destroy();
283283
}
284284

285+
function freeSocketErrorListener(err) {
286+
var socket = this;
287+
debug('SOCKET ERROR on FREE socket:', err.message, err.stack);
288+
socket.destroy();
289+
socket.emit('agentRemove');
290+
}
291+
285292
function socketOnEnd() {
286293
var socket = this;
287294
var req = this._httpMessage;
@@ -448,6 +455,7 @@ function responseOnEnd() {
448455
}
449456
socket.removeListener('close', socketCloseListener);
450457
socket.removeListener('error', socketErrorListener);
458+
socket.once('error', freeSocketErrorListener);
451459
// Mark this socket as available, AFTER user-added end
452460
// handlers have a chance to run.
453461
process.nextTick(emitFreeNT, socket);
@@ -482,6 +490,7 @@ function tickOnSocket(req, socket) {
482490
}
483491

484492
parser.onIncoming = parserOnIncomingClient;
493+
socket.removeListener('error', freeSocketErrorListener);
485494
socket.on('error', socketErrorListener);
486495
socket.on('data', socketOnData);
487496
socket.on('end', socketOnEnd);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
var common = require('../common');
3+
var assert = require('assert');
4+
var http = require('http');
5+
var Agent = http.Agent;
6+
7+
var agent = new Agent({
8+
keepAlive: true,
9+
});
10+
11+
var requestParams = {
12+
host: 'localhost',
13+
port: common.PORT,
14+
agent: agent,
15+
path: '/'
16+
};
17+
18+
var socketKey = agent.getName(requestParams);
19+
20+
function get(callback) {
21+
return http.get(requestParams, callback);
22+
}
23+
24+
var destroy_queue = {};
25+
var server = http.createServer(function(req, res) {
26+
res.end('hello world');
27+
});
28+
29+
server.listen(common.PORT, function() {
30+
get(function(res) {
31+
assert.equal(res.statusCode, 200);
32+
res.resume();
33+
res.on('end', function() {
34+
process.nextTick(function() {
35+
var freeSockets = agent.freeSockets[socketKey];
36+
assert.equal(freeSockets.length, 1,
37+
'expect a free socket on ' + socketKey);
38+
39+
//generate a random error on the free socket
40+
var freeSocket = freeSockets[0];
41+
freeSocket.emit('error', new Error('ECONNRESET: test'));
42+
43+
get(done);
44+
});
45+
});
46+
});
47+
});
48+
49+
function done() {
50+
assert.equal(Object.keys(agent.freeSockets).length, 0,
51+
'expect the freeSockets pool to be empty');
52+
53+
agent.destroy();
54+
server.close();
55+
process.exit(0);
56+
}

0 commit comments

Comments
 (0)