bare-http1 4.2.3 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.d.ts +3 -0
  2. package/lib/agent.js +78 -48
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -99,6 +99,9 @@ export interface HTTPAgentOptions {
99
99
  }
100
100
 
101
101
  export interface HTTPAgent {
102
+ readonly sockets: IterableIterator<TCPSocket>
103
+ readonly freeSockets: IterableIterator<TCPSocket>
104
+
102
105
  createConnection(opts?: TCPSocketOptions & TCPSocketConnectOptions): TCPSocket
103
106
 
104
107
  reuseSocket(socket: TCPSocket, req?: HTTPClientRequest): void
package/lib/agent.js CHANGED
@@ -2,20 +2,77 @@ const EventEmitter = require('bare-events')
2
2
  const tcp = require('bare-tcp')
3
3
  const HTTPClientConnection = require('./client-connection')
4
4
 
5
+ class HTTPSocketSet {
6
+ constructor() {
7
+ this._sockets = new Map()
8
+ }
9
+
10
+ add(name, socket) {
11
+ const sockets = this._sockets.get(name)
12
+
13
+ if (sockets === undefined) this._sockets.set(name, [socket])
14
+ else sockets.push(socket)
15
+ }
16
+
17
+ pop(name) {
18
+ const sockets = this._sockets.get(name)
19
+ if (sockets === undefined || sockets.length === 0) return null
20
+
21
+ const last = sockets.pop()
22
+
23
+ if (sockets.length === 0) this._sockets.delete(name)
24
+
25
+ return last
26
+ }
27
+
28
+ delete(name, socket) {
29
+ const sockets = this._sockets.get(name)
30
+ if (sockets === undefined) return
31
+
32
+ const i = sockets.indexOf(socket)
33
+ if (i === -1) return
34
+
35
+ const last = sockets.pop()
36
+ if (last !== socket) sockets[i] = last
37
+
38
+ if (sockets.length === 0) this._sockets.delete(name)
39
+ }
40
+
41
+ *sockets() {
42
+ for (const sockets of this._sockets.values()) {
43
+ yield* sockets
44
+ }
45
+ }
46
+
47
+ *[Symbol.iterator]() {
48
+ for (const [name, sockets] of this._sockets) {
49
+ for (const socket of sockets) yield [name, socket]
50
+ }
51
+ }
52
+ }
53
+
5
54
  module.exports = class HTTPAgent extends EventEmitter {
6
55
  constructor(opts = {}) {
7
56
  super()
8
57
 
9
58
  const { keepAlive = false, keepAliveMsecs = 1000 } = opts
10
59
 
11
- this._sockets = new Map()
12
- this._freeSockets = new Map()
60
+ this._sockets = new HTTPSocketSet()
61
+ this._freeSockets = new HTTPSocketSet()
13
62
 
14
63
  this._keepAlive = typeof keepAlive === 'number' ? keepAlive : keepAlive ? keepAliveMsecs : -1
15
64
 
16
65
  this._opts = { ...opts }
17
66
  }
18
67
 
68
+ get sockets() {
69
+ return this._sockets.sockets()
70
+ }
71
+
72
+ get freeSockets() {
73
+ return this._freeSockets.sockets()
74
+ }
75
+
19
76
  createConnection(opts) {
20
77
  return tcp.createConnection(opts)
21
78
  }
@@ -42,31 +99,26 @@ module.exports = class HTTPAgent extends EventEmitter {
42
99
 
43
100
  const name = this.getName(opts)
44
101
 
45
- let socket
46
-
47
- if (this._freeSockets.has(name)) {
48
- const sockets = this._freeSockets.get(name)
49
-
50
- socket = sockets.pop()
102
+ let socket = this._freeSockets.pop(name)
51
103
 
52
- if (sockets.length === 0) this._freeSockets.delete(name)
53
-
54
- this.reuseSocket(socket, req)
55
- } else {
104
+ if (socket) this.reuseSocket(socket, req)
105
+ else {
56
106
  const agent = this
57
107
 
58
108
  socket = this.createConnection(opts)
59
109
 
60
- socket.on('free', onfree).on('end', onremove).on('finish', onremove).on('timeout', ontimeout)
110
+ socket
111
+ .on('free', onfree)
112
+ .on('end', onremove)
113
+ .on('finish', onremove)
114
+ .on('close', onremove)
115
+ .on('timeout', ontimeout)
61
116
 
62
117
  function onfree() {
63
- if (agent.keepSocketAlive(socket)) {
64
- onremove(false)
65
-
66
- const sockets = agent._freeSockets.get(name)
118
+ if (socket.destroyed) return
67
119
 
68
- if (sockets === undefined) agent._freeSockets.set(name, [socket])
69
- else sockets.push(socket)
120
+ if (agent.keepSocketAlive(socket)) {
121
+ agent._freeSockets.add(name, socket)
70
122
  } else {
71
123
  socket.end()
72
124
  }
@@ -74,39 +126,19 @@ module.exports = class HTTPAgent extends EventEmitter {
74
126
  agent.emit('free', socket)
75
127
  }
76
128
 
77
- function onremove(destroy = true) {
78
- for (const set of destroy ? [agent._sockets, agent._freeSockets] : [agent._sockets]) {
79
- const sockets = set.get(name)
80
- if (sockets === undefined) continue
81
-
82
- const i = sockets.indexOf(socket)
83
- if (i === -1) continue
84
-
85
- const last = sockets.pop()
86
- if (last !== socket) sockets[i] = last
129
+ function onremove() {
130
+ socket.off('free', onfree)
87
131
 
88
- if (sockets.length === 0) set.delete(name)
89
- }
132
+ agent._sockets.delete(name, socket)
133
+ agent._freeSockets.delete(name, socket)
90
134
  }
91
135
 
92
136
  function ontimeout() {
93
- const sockets = agent._freeSockets.get(name)
94
- if (sockets === undefined) return
95
-
96
- const i = sockets.indexOf(socket)
97
- if (i === -1) return
98
-
99
- const last = sockets.pop()
100
- if (last !== socket) sockets[i] = last
101
-
102
- if (sockets.length === 0) agent._freeSockets.delete(name)
137
+ agent._freeSockets.delete(name, socket)
103
138
  }
104
139
  }
105
140
 
106
- const sockets = this._sockets.get(name)
107
-
108
- if (sockets === undefined) this._sockets.set(name, [socket])
109
- else sockets.push(socket)
141
+ this._sockets.add(name, socket)
110
142
 
111
143
  req.socket = socket
112
144
 
@@ -117,9 +149,7 @@ module.exports = class HTTPAgent extends EventEmitter {
117
149
 
118
150
  destroy() {
119
151
  for (const set of [this._sockets, this._freeSockets]) {
120
- for (const [, sockets] of set) {
121
- for (const socket of sockets) socket.destroy()
122
- }
152
+ for (const socket of set) socket.destroy()
123
153
  }
124
154
  }
125
155
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-http1",
3
- "version": "4.2.3",
3
+ "version": "4.3.0",
4
4
  "description": "Native HTTP/1 library for JavaScript",
5
5
  "exports": {
6
6
  "./package": "./package.json",