8000
We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent 55486bc commit 1ffa9f3Copy full SHA for 1ffa9f3
doc/api/http.md
@@ -239,6 +239,9 @@ added: v0.11.4
239
An object which contains arrays of sockets currently awaiting use by
240
the agent when `keepAlive` is enabled. Do not modify.
241
242
+Sockets in the `freeSockets` list will be automatically destroyed and
243
+removed from the array on `'timeout'`.
244
+
245
### `agent.getName(options)`
246
<!-- YAML
247
added: v0.11.4
lib/_http_agent.js
@@ -120,6 +120,12 @@ function Agent(options) {
120
socket[async_id_symbol] = -1;
121
socket._httpMessage = null;
122
this.removeSocket(socket, options);
123
124
+ const agentTimeout = this.options.timeout || 0;
125
+ if (socket.timeout !== agentTimeout) {
126
+ socket.setTimeout(agentTimeout);
127
+ }
128
129
freeSockets.push(socket);
130
} else {
131
// Implementation doesn't want to keep socket alive
@@ -202,12 +208,21 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */,
202
208
this.sockets[name] = [];
203
209
}
204
210
205
- const freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0;
211
+ const freeSockets = this.freeSockets[name];
212
+ let socket;
213
+ if (freeSockets) {
214
+ while (freeSockets.length && freeSockets[0].destroyed) {
215
+ freeSockets.shift();
216
217
+ socket = freeSockets.shift();
218
+ if (!freeSockets.length)
219
+ delete this.freeSockets[name];
220
221
222
+ const freeLen = freeSockets ? freeSockets.length : 0;
206
223
const sockLen = freeLen + this.sockets[name].length;
207
224
- if (freeLen) {
- // We have a free socket, so use that.
- const socket = this.freeSockets[name].shift();
225
+ if (socket) {
226
// Guard against an uninitialized or user supplied Socket.
227
const handle = socket._handle;
228
if (handle && typeof handle.asyncReset === 'function') {
@@ -216,10 +231,6 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */,
231
socket[async_id_symbol] = handle.getAsyncId();
232
233
- // don't leak
- if (!this.freeSockets[name].length)
- delete this.freeSockets[name];
-
234
this.reuseSocket(socket, req);
235
setRequestSocket(this, req, socket);
236
this.sockets[name].push(socket);
@@ -319,6 +330,20 @@ function installListeners(agent, s, options) {
319
330
320
331
s.on('close', onClose);
321
332
333
+ function onTimeout() {
334
+ debug('CLIENT socket onTimeout');
335
336
+ // Destroy if in free list.
337
+ // TODO(ronag): Always destroy, even if not in free list.
338
+ const sockets = agent.freeSockets;
339
+ for (const name of ObjectKeys(sockets)) {
340
+ if (sockets[name].includes(s)) {
341
+ return s.destroy();
342
343
344
345
+ s.on('timeout', onTimeout);
346
322
347
function onRemove() {
323
348
// We need this function for cases like HTTP 'upgrade'
324
349
// (defined by WebSockets) where we need to remove a socket from the
@@ -327,6 +352,7 @@ function installListeners(agent, s, options) {
327
352
agent.removeSocket(s, options);
328
353
s.removeListener('close', onClose);
329
354
s.removeListener('free', onFree);
355
+ s.removeListener('timeout', onTimeout);
356
s.removeListener('agentRemove', onRemove);
357
358
s.on('agentRemove', onRemove);
@@ -409,14 +435,6 @@ function setRequestSocket(agent, req, socket) {
409
435
return;
410
436
411
437
socket.setTimeout(req.timeout);
412
- // Reset timeout after response end
413
- req.once('response', (res) => {
414
- res.once('end', () => {
415
- if (socket.timeout !== agentTimeout) {
416
- socket.setTimeout(agentTimeout);
417
- }
418
- });
419
420
438
421
439
422
440
function emitErrorNT(emitter, err) {
test/parallel/test-http-agent-timeout-option.js
@@ -18,6 +18,6 @@ request.on('socket', mustCall((socket) => {
18
19
const listeners = socket.listeners('timeout');
20
21
- strictEqual(listeners.length, 1);
22
- strictEqual(listeners[0], request.timeoutCb);
+ strictEqual(listeners.length, 2);
+ strictEqual(listeners[1], request.timeoutCb);
23
}));
test/parallel/test-http-agent-timeout.js
@@ -0,0 +1,94 @@
1
+'use strict';
2
3
+const common = require('../common');
4
+const assert = require('assert');
5
+const http = require('http');
6
7
+{
8
+ // Ensure reuse of successful sockets.
9
10
+ const agent = new http.Agent({ keepAlive: true });
11
12
+ const server = http.createServer((req, res) => {
13
+ res.end();
14
+ });
15
16
+ server.listen(0, common.mustCall(() => {
17
+ http.get({ port: server.address().port, agent })
+ .on('response', common.mustCall((res) => {
+ socket = res.socket;
+ assert(socket);
+ res.resume();
+ socket.on('free', common.mustCall(() => {
24
25
26
+ assert.strictEqual(socket, res.socket);
27
28
+ agent.destroy();
29
+ server.close();
30
+ }));
31
32
33
34
+}
35
36
37
+ // Ensure that timeouted sockets are not reused.
38
39
+ const agent = new http.Agent({ keepAlive: true, timeout: 50 });
40
41
42
43
44
45
46
47
48
+ const socket = res.socket;
49
50
+ 55C6 res.resume();
51
52
+ socket.on('timeout', common.mustCall(() => {
53
54
55
+ assert.notStrictEqual(socket, res.socket);
56
+ assert.strictEqual(socket.destroyed, true);
57
58
59
60
61
62
63
64
65
66
67
+ // Ensure that destroyed sockets are not reused.
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
+ socket.destroy();
84
85
86
87
88
89
90
91
92
93
94
test/parallel/test-http-client-set-timeout-after-end.js
@@ -20,7 +20,7 @@ server.listen(0, () => {
const req = get({ agent, port }, (res) => {
res.on('end', () => {
strictEqual(req.setTimeout(0), req);
- strictEqual(socket.listenerCount('timeout'), 0);
+ strictEqual(socket.listenerCount('timeout'), 1);
agent.destroy();
server.close();
});
test/parallel/test-http-client-set-timeout.js
@@ -42,7 +42,7 @@ server.listen(0, mustCall(() => {
req.on('timeout', mustCall(() => {
- strictEqual(req.socket.listenerCount('timeout'), 0);
+ strictEqual(req.socket.listenerCount('timeout'), 1);
req.destroy();
test/parallel/test-http-client-timeout-option-listeners.js
@@ -24,9 +24,9 @@ const options = {
server.listen(0, options.host, common.mustCall(() => {
options.port = server.address().port;
doRequest(common.mustCall((numListeners) => {
- assert.strictEqual(numListeners, 1);
+ assert.strictEqual(numListeners, 2);
test/parallel/test-http-client-timeout-option-with-agent.js