Skip to content

Commit 567ced9

Browse files
jfromanielloMyles Borins
authored and
Myles Borins
committed
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 51c8bc8 commit 567ced9

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

lib/_http_client.js

+9
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ function socketErrorListener(err) {
274274
socket.destroy();
275275
}
276276

277+
function freeSocketErrorListener(err) {
278+
var socket = this;
279+
debug('SOCKET ERROR on FREE socket:', err.message, err.stack);
280+
socket.destroy();
281+
socket.emit('agentRemove');
282+
}
283+
277284
function socketOnEnd() {
278285
var socket = this;
279286
var req = this._httpMessage;
@@ -440,6 +447,7 @@ function responseOnEnd() {
440447
}
441448
socket.removeListener('close', socketCloseListener);
442449
socket.removeListener('error', socketErrorListener);
450+
socket.once('error', freeSocketErrorListener);
443451
// Mark this socket as available, AFTER user-added end
444452
// handlers have a chance to run.
445453
process.nextTick(emitFreeNT, socket);
@@ -474,6 +482,7 @@ function tickOnSocket(req, socket) {
474482
}
475483

476484
parser.onIncoming = parserOnIncomingClient;
485+
socket.removeListener('error', freeSocketErrorListener);
477486
socket.on('error', socketErrorListener);
478487
socket.on('data', socketOnData);
479488
socket.on('end', socketOnEnd);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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 server = http.createServer(function(req, res) {
25+
res.end('hello world');
26+
});
27+
28+
server.listen(common.PORT, function() {
29+
get(function(res) {
30+
assert.equal(res.statusCode, 200);
31+
res.resume();
32+
res.on('end', function() {
33+
process.nextTick(function() {
34+
var freeSockets = agent.freeSockets[socketKey];
35+
assert.equal(freeSockets.length, 1,
36+
'expect a free socket on ' + socketKey);
37+
38+
//generate a random error on the free socket
39+
var freeSocket = freeSockets[0];
40+
freeSocket.emit('error', new Error('ECONNRESET: test'));
41+
42+
get(done);
43+
});
44+
});
45+
});
46+
});
47+
48+
function done() {
49+
assert.equal(Object.keys(agent.freeSockets).length, 0,
50+
'expect the freeSockets pool to be empty');
51+
52+
agent.destroy();
53+
server.close();
54+
process.exit(0);
55+
}

0 commit comments

Comments
 (0)