Skip to content

Commit 8cab136

Browse files
authored
fix: ensure maxSockets is respected (#7324)
Fixes #7072 deps: agent-base@7.1.1 chore: add smoke-test for large prod installs
1 parent 9bffa13 commit 8cab136

File tree

9 files changed

+16495
-20
lines changed

9 files changed

+16495
-20
lines changed

node_modules/agent-base/LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(The MIT License)
2+
3+
Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
'Software'), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

node_modules/agent-base/dist/index.js

+64-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
2727
};
2828
Object.defineProperty(exports, "__esModule", { value: true });
2929
exports.Agent = void 0;
30+
const net = __importStar(require("net"));
3031
const http = __importStar(require("http"));
32+
const https_1 = require("https");
3133
__exportStar(require("./helpers"), exports);
3234
const INTERNAL = Symbol('AgentBaseInternalState');
3335
class Agent extends http.Agent {
@@ -64,22 +66,83 @@ class Agent extends http.Agent {
6466
.some((l) => l.indexOf('(https.js:') !== -1 ||
6567
l.indexOf('node:https:') !== -1);
6668
}
69+
// In order to support async signatures in `connect()` and Node's native
70+
// connection pooling in `http.Agent`, the array of sockets for each origin
71+
// has to be updated synchronously. This is so the length of the array is
72+
// accurate when `addRequest()` is next called. We achieve this by creating a
73+
// fake socket and adding it to `sockets[origin]` and incrementing
74+
// `totalSocketCount`.
75+
incrementSockets(name) {
76+
// If `maxSockets` and `maxTotalSockets` are both Infinity then there is no
77+
// need to create a fake socket because Node.js native connection pooling
78+
// will never be invoked.
79+
if (this.maxSockets === Infinity && this.maxTotalSockets === Infinity) {
80+
return null;
81+
}
82+
// All instances of `sockets` are expected TypeScript errors. The
83+
// alternative is to add it as a private property of this class but that
84+
// will break TypeScript subclassing.
85+
if (!this.sockets[name]) {
86+
// @ts-expect-error `sockets` is readonly in `@types/node`
87+
this.sockets[name] = [];
88+
}
89+
const fakeSocket = new net.Socket({ writable: false });
90+
this.sockets[name].push(fakeSocket);
91+
// @ts-expect-error `totalSocketCount` isn't defined in `@types/node`
92+
this.totalSocketCount++;
93+
return fakeSocket;
94+
}
95+
decrementSockets(name, socket) {
96+
if (!this.sockets[name] || socket === null) {
97+
return;
98+
}
99+
const sockets = this.sockets[name];
100+
const index = sockets.indexOf(socket);
101+
if (index !== -1) {
102+
sockets.splice(index, 1);
103+
// @ts-expect-error `totalSocketCount` isn't defined in `@types/node`
104+
this.totalSocketCount--;
105+
if (sockets.length === 0) {
106+
// @ts-expect-error `sockets` is readonly in `@types/node`
107+
delete this.sockets[name];
108+
}
109+
}
110+
}
111+
// In order to properly update the socket pool, we need to call `getName()` on
112+
// the core `https.Agent` if it is a secureEndpoint.
113+
getName(options) {
114+
const secureEndpoint = typeof options.secureEndpoint === 'boolean'
115+
? options.secureEndpoint
116+
: this.isSecureEndpoint(options);
117+
if (secureEndpoint) {
118+
// @ts-expect-error `getName()` isn't defined in `@types/node`
119+
return https_1.Agent.prototype.getName.call(this, options);
120+
}
121+
// @ts-expect-error `getName()` isn't defined in `@types/node`
122+
return super.getName(options);
123+
}
67124
createSocket(req, options, cb) {
68125
const connectOpts = {
69126
...options,
70127
secureEndpoint: this.isSecureEndpoint(options),
71128
};
129+
const name = this.getName(connectOpts);
130+
const fakeSocket = this.incrementSockets(name);
72131
Promise.resolve()
73132
.then(() => this.connect(req, connectOpts))
74133
.then((socket) => {
134+
this.decrementSockets(name, fakeSocket);
75135
if (socket instanceof http.Agent) {
76136
// @ts-expect-error `addRequest()` isn't defined in `@types/node`
77137
return socket.addRequest(req, connectOpts);
78138
}
79139
this[INTERNAL].currentSocket = socket;
80140
// @ts-expect-error `createSocket()` isn't defined in `@types/node`
81141
super.createSocket(req, options, cb);
82-
}, cb);
142+
}, (err) => {
143+
this.decrementSockets(name, fakeSocket);
144+
cb(err);
145+
});
83146
}
84147
createConnection() {
85148
const socket = this[INTERNAL].currentSocket;

node_modules/agent-base/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "agent-base",
3-
"version": "7.1.0",
3+
"version": "7.1.1",
44
"description": "Turn a function into an `http.Agent` instance",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",

package-lock.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -2410,9 +2410,9 @@
24102410
}
24112411
},
24122412
"node_modules/agent-base": {
2413-
"version": "7.1.0",
2414-
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
2415-
"integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
2413+
"version": "7.1.1",
2414+
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
2415+
"integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
24162416
"inBundle": true,
24172417
"dependencies": {
24182418
"debug": "^4.3.4"

0 commit comments

Comments
 (0)