Skip to content

Commit 225ddd5

Browse files
ronagtargos
authored andcommittedApr 22, 2020
http: move free socket error handling to agent
The http client should not know anything about free sockets. Let the agent handle its pool of sockets. PR-URL: #32003 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent a40e7da commit 225ddd5

File tree

2 files changed

+21
-10
lines changed

2 files changed

+21
-10
lines changed
 

‎lib/_http_agent.js

+14
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ class ReusedHandle {
6060
}
6161
}
6262

63+
function freeSocketErrorListener(err) {
64+
const socket = this;
65+
debug('SOCKET ERROR on FREE socket:', err.message, err.stack);
66+
socket.destroy();
67+
socket.emit('agentRemove');
68+
}
69+
6370
function Agent(options) {
6471
if (!(this instanceof Agent))
6572
return new Agent(options);
@@ -85,6 +92,11 @@ function Agent(options) {
8592
const name = this.getName(options);
8693
debug('agent.on(free)', name);
8794

95+
// TODO(ronag): socket.destroy(err) might have been called
96+
// before coming here and have an 'error' scheduled. In the
97+
// case of socket.destroy() below this 'error' has no handler
98+
// and could cause unhandled exception.
99+
88100
if (socket.writable &&
89101
this.requests[name] && this.requests[name].length) {
90102
const req = this.requests[name].shift();
@@ -121,6 +133,7 @@ function Agent(options) {
121133
socket.setTimeout(agentTimeout);
122134
}
123135

136+
socket.once('error', freeSocketErrorListener);
124137
freeSockets.push(socket);
125138
} else {
126139
// Implementation doesn't want to keep socket alive
@@ -391,6 +404,7 @@ Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) {
391404

392405
Agent.prototype.reuseSocket = function reuseSocket(socket, req) {
393406
debug('have free socket');
407+
socket.removeListener('error', freeSocketErrorListener);
394408
req.reusedSocket = true;
395409
socket.ref();
396410
};

‎lib/_http_client.js

+7-10
Original file line numberDiff line numberDiff line change
@@ -441,13 +441,6 @@ function socketErrorListener(err) {
441441
socket.destroy();
442442
}
443443

444-
function freeSocketErrorListener(err) {
445-
const socket = this;
446-
debug('SOCKET ERROR on FREE socket:', err.message, err.stack);
447-
socket.destroy();
448-
socket.emit('agentRemove');
449-
}
450-
451444
function socketOnEnd() {
452445
const socket = this;
453446
const req = this._httpMessage;
@@ -622,8 +615,11 @@ function responseKeepAlive(req) {
622615
socket.removeListener('error', socketErrorListener);
623616
socket.removeListener('data', socketOnData);
624617
socket.removeListener('end', socketOnEnd);
625-
socket.once('error', freeSocketErrorListener);
626-
// There are cases where _handle === null. Avoid those. Passing null to
618+
619+
// TODO(ronag): Between here and emitFreeNT the socket
620+
// has no 'error' handler.
621+
622+
// There are cases where _handle === null. Avoid those. Passing undefined to
627623
// nextTick() will call getDefaultTriggerAsyncId() to retrieve the id.
628624
const asyncId = socket._handle ? socket._handle.getAsyncId() : undefined;
629625
// Mark this socket as available, AFTER user-added end
@@ -692,7 +688,6 @@ function tickOnSocket(req, socket) {
692688
}
693689

694690
parser.onIncoming = parserOnIncomingClient;
695-
socket.removeListener('error', freeSocketErrorListener);
696691
socket.on('error', socketErrorListener);
697692
socket.on('data', socketOnData);
698693
socket.on('end', socketOnEnd);
@@ -732,6 +727,8 @@ function listenSocketTimeout(req) {
732727
}
733728

734729
ClientRequest.prototype.onSocket = function onSocket(socket) {
730+
// TODO(ronag): Between here and onSocketNT the socket
731+
// has no 'error' handler.
735732
process.nextTick(onSocketNT, this, socket);
736733
};
737734

0 commit comments

Comments
 (0)
Please sign in to comment.