| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 55486bc commit 1ffa9f3
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -239,6 +239,9 @@ added: v0.11.4 | |||
| 239 | 239 | An object which contains arrays of sockets currently awaiting use by | |
| 240 | 240 | the agent when `keepAlive` is enabled. Do not modify. | |
| 241 | 241 | ||
| 242 | + Sockets in the `freeSockets` list will be automatically destroyed and | ||
| 243 | + removed from the array on `'timeout'`. | ||
| 244 | + | ||
| 242 | 245 | ### `agent.getName(options)` | |
| 243 | 246 | <!-- YAML | |
| 244 | 247 | added: v0.11.4 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -120,6 +120,12 @@ function Agent(options) { | |||
| 120 | 120 | socket[async_id_symbol] = -1; | |
| 121 | 121 | socket._httpMessage = null; | |
| 122 | 122 | this.removeSocket(socket, options); | |
| 123 | + | ||
| 124 | + const agentTimeout = this.options.timeout || 0; | ||
| 125 | + if (socket.timeout !== agentTimeout) { | ||
| 126 | + socket.setTimeout(agentTimeout); | ||
| 127 | + } | ||
| 128 | + | ||
| 123 | 129 | freeSockets.push(socket); | |
| 124 | 130 | } else { | |
| 125 | 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 | ||
| 208 | - if (freeLen) { | ||
| 209 | - // We have a free socket, so use that. | ||
| 210 | - const socket = this.freeSockets[name].shift(); | ||
| 225 | + if (socket) { | ||
| 211 | 226 | // Guard against an uninitialized or user supplied Socket. | |
| 212 | 227 | const handle = socket._handle; | |
| 213 | 228 | if (handle && typeof handle.asyncReset === 'function') { | |
@@ -216,10 +231,6 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */, | |||
| 216 | 231 | socket[async_id_symbol] = handle.getAsyncId(); | |
| 217 | 232 | } | |
| 218 | 233 | ||
| 219 | - // don't leak | ||
| 220 | - if (!this.freeSockets[name].length) | ||
| 221 | - delete this.freeSockets[name]; | ||
| 222 | - | ||
| 223 | 234 | this.reuseSocket(socket, req); | |
| 224 | 235 | setRequestSocket(this, req, socket); | |
| 225 | 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); | ||
| 330 | 356 | s.removeListener('agentRemove', onRemove); | |
| 331 | 357 | } | |
| 332 | 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) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,6 +18,6 @@ request.on('socket', mustCall((socket) => { | |||
| 18 | 18 | ||
| 19 | 19 | const listeners = socket.listeners('timeout'); | |
| 20 | 20 | ||
| 21 | - strictEqual(listeners.length, 1); | ||
| 22 | - strictEqual(listeners[0], request.timeoutCb); | ||
| 21 | + strictEqual(listeners.length, 2); | ||
| 22 | + strictEqual(listeners[1], request.timeoutCb); | ||
| 23 | 23 | })); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -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 | + let socket; | ||
| 18 | + http.get({ port: server.address().port, agent }) | ||
| 19 | + .on('response', common.mustCall((res) => { | ||
| 20 | + socket = res.socket; | ||
| 21 | + assert(socket); | ||
| 22 | + res.resume(); | ||
| 23 | + socket.on('free', common.mustCall(() => { | ||
| 24 | + http.get({ port: server.address().port, agent }) | ||
| 25 | + .on('response', common.mustCall((res) => { | ||
| 26 | + assert.strictEqual(socket, res.socket); | ||
| 27 | + assert(socket); | ||
| 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 | + const server = http.createServer((req, res) => { | ||
| 42 | + res.end(); | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + server.listen(0, common.mustCall(() => { | ||
| 46 | + http.get({ port: server.address().port, agent }) | ||
| 47 | + .on('response', common.mustCall((res) => { | ||
| 48 | + const socket = res.socket; | ||
| 49 | + assert(socket); | ||
| 50 | + res.resume(); | ||
| 51 | + socket.on('free', common.mustCall(() => { | ||
| 52 | + socket.on('timeout', common.mustCall(() => { | ||
| 53 | + http.get({ port: server.address().port, agent }) | ||
| 54 | + .on('response', common.mustCall((res) => { | ||
| 55 | + assert.notStrictEqual(socket, res.socket); | ||
| 56 | + assert.strictEqual(socket.destroyed, true); | ||
| 57 | + agent.destroy(); | ||
| 58 | + server.close(); | ||
| 59 | + })); | ||
| 60 | + })); | ||
| 61 | + })); | ||
| 62 | + })); | ||
| 63 | + })); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + { | ||
| 67 | + // Ensure that destroyed sockets are not reused. | ||
| 68 | + | ||
| 69 | + const agent = new http.Agent({ keepAlive: true }); | ||
| 70 | + | ||
| 71 | + const server = http.createServer((req, res) => { | ||
| 72 | + res.end(); | ||
| 73 | + }); | ||
| 74 | + | ||
| 75 | + server.listen(0, common.mustCall(() => { | ||
| 76 | + let socket; | ||
| 77 | + http.get({ port: server.address().port, agent }) | ||
| 78 | + .on('response', common.mustCall((res) => { | ||
| 79 | + socket = res.socket; | ||
| 80 | + assert(socket); | ||
| 81 | + res.resume(); | ||
| 82 | + socket.on('free', common.mustCall(() => { | ||
| 83 | + socket.destroy(); | ||
| 84 | + http.get({ port: server.address().port, agent }) | ||
| 85 | + .on('response', common.mustCall((res) => { | ||
| 86 | + assert.notStrictEqual(socket, res.socket); | ||
| 87 | + assert(socket); | ||
| 88 | + agent.destroy(); | ||
| 89 | + server.close(); | ||
| 90 | + })); | ||
| 91 | + })); | ||
| 92 | + })); | ||
| 93 | + })); | ||
| 94 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -20,7 +20,7 @@ server.listen(0, () => { | |||
| 20 | 20 | const req = get({ agent, port }, (res) => { | |
| 21 | 21 | res.on('end', () => { | |
| 22 | 22 | strictEqual(req.setTimeout(0), req); | |
| 23 | - strictEqual(socket.listenerCount('timeout'), 0); | ||
| 23 | + strictEqual(socket.listenerCount('timeout'), 1); | ||
| 24 | 24 | agent.destroy(); | |
| 25 | 25 | server.close(); | |
| 26 | 26 | }); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -42,7 +42,7 @@ server.listen(0, mustCall(() => { | |||
| 42 | 42 | })); | |
| 43 | 43 | ||
| 44 | 44 | req.on('timeout', mustCall(() => { | |
| 45 | - strictEqual(req.socket.listenerCount('timeout'), 0); | ||
| 45 | + strictEqual(req.socket.listenerCount('timeout'), 1); | ||
| 46 | 46 | req.destroy(); | |
| 47 | 47 | })); | |
| 48 | 48 | })); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,9 +24,9 @@ const options = { | |||
| 24 | 24 | server.listen(0, options.host, common.mustCall(() => { | |
| 25 | 25 | options.port = server.address().port; | |
| 26 | 26 | doRequest(common.mustCall((numListeners) => { | |
| 27 | - assert.strictEqual(numListeners, 1); | ||
| 27 | + assert.strictEqual(numListeners, 2); | ||
| 28 | 28 | doRequest(common.mustCall((numListeners) => { | |
| 29 | - assert.strictEqual(numListeners, 1); | ||
| 29 | + assert.strictEqual(numListeners, 2); | ||
| 30 | 30 | server.close(); | |
| 31 | 31 | agent.destroy(); | |
| 32 | 32 | })); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,6 +18,6 @@ request.on('socket', mustCall((socket) => { | |||
| 18 | 18 | ||
| 19 | 19 | const listeners = socket.listeners('timeout'); | |
| 20 | 20 | ||
| 21 | - strictEqual(listeners.length, 1); | ||
| 22 | - strictEqual(listeners[0], request.timeoutCb); | ||
| 21 | + strictEqual(listeners.length, 2); | ||
| 22 | + strictEqual(listeners[1], request.timeoutCb); | ||
| 23 | 23 | })); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments