Skip to content

Commit ff3615d

Browse files
ronagaddaleax
authored andcommitted
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 <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent 73fec7c commit ff3615d

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
@@ -57,6 +57,13 @@ class ReusedHandle {
5757
}
5858
}
5959

60+
function freeSocketErrorListener(err) {
61+
const socket = this;
62+
debug('SOCKET ERROR on FREE socket:', err.message, err.stack);
63+
socket.destroy();
64+
socket.emit('agentRemove');
65+
}
66+
6067
function Agent(options) {
6168
if (!(this instanceof Agent))
6269
return new Agent(options);
@@ -82,6 +89,11 @@ function Agent(options) {
8289
const name = this.getName(options);
8390
debug('agent.on(free)', name);
8491

92+
// TODO(ronag): socket.destroy(err) might have been called
93+
// before coming here and have an 'error' scheduled. In the
94+
// case of socket.destroy() below this 'error' has no handler
95+
// and could cause unhandled exception.
96+
8597
if (socket.writable &&
8698
this.requests[name] && this.requests[name].length) {
8799
const req = this.requests[name].shift();
@@ -118,6 +130,7 @@ function Agent(options) {
118130
socket.setTimeout(agentTimeout);
119131
}
120132

133+
socket.once('error', freeSocketErrorListener);
121134
freeSockets.push(socket);
122135
} else {
123136
// Implementation doesn't want to keep socket alive
@@ -393,6 +406,7 @@ Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) {
393406

394407
Agent.prototype.reuseSocket = function reuseSocket(socket, req) {
395408
debug('have free socket');
409+
socket.removeListener('error', freeSocketErrorListener);
396410
req.reusedSocket = true;
397411
socket.ref();
398412
};

lib/_http_client.js

+7-10
Original file line numberDiff line numberDiff line change
@@ -444,13 +444,6 @@ function socketErrorListener(err) {
444444
socket.destroy();
445445
}
446446

447-
function freeSocketErrorListener(err) {
448-
const socket = this;
449-
debug('SOCKET ERROR on FREE socket:', err.message, err.stack);
450-
socket.destroy();
451-
socket.emit('agentRemove');
452-
}
453-
454447
function socketOnEnd() {
455448
const socket = this;
456449
const req = this._httpMessage;
@@ -629,8 +622,11 @@ function responseKeepAlive(req) {
629622
socket.removeListener('error', socketErrorListener);
630623
socket.removeListener('data', socketOnData);
631624
socket.removeListener('end', socketOnEnd);
632-
socket.once('error', freeSocketErrorListener);
633-
// There are cases where _handle === null. Avoid those. Passing null to
625+
626+
// TODO(ronag): Between here and emitFreeNT the socket
627+
// has no 'error' handler.
628+
629+
// There are cases where _handle === null. Avoid those. Passing undefined to
634630
// nextTick() will call getDefaultTriggerAsyncId() to retrieve the id.
635631
const asyncId = socket._handle ? socket._handle.getAsyncId() : undefined;
636632
// Mark this socket as available, AFTER user-added end
@@ -699,7 +695,6 @@ function tickOnSocket(req, socket) {
699695
}
700696

701697
parser.onIncoming = parserOnIncomingClient;
702-
socket.removeListener('error', freeSocketErrorListener);
703698
socket.on('error', socketErrorListener);
704699
socket.on('data', socketOnData);
705700
socket.on('end', socketOnEnd);
@@ -739,6 +734,8 @@ function listenSocketTimeout(req) {
739734
}
740735

741736
ClientRequest.prototype.onSocket = function onSocket(socket) {
737+
// TODO(ronag): Between here and onSocketNT the socket
738+
// has no 'error' handler.
742739
process.nextTick(onSocketNT, this, socket);
743740
};
744741

0 commit comments

Comments
 (0)