@@ -4,22 +4,81 @@ const net = require('net')
4
4
const assert = require ( 'assert' )
5
5
const util = require ( './util' )
6
6
const { InvalidArgumentError, ConnectTimeoutError } = require ( './errors' )
7
+
7
8
let tls // include tls conditionally since it is not always available
8
9
9
10
// TODO: session re-use does not wait for the first
10
11
// connection to resolve the session and might therefore
11
12
// resolve the same servername multiple times even when
12
13
// re-use is enabled.
13
14
15
+ let SessionCache
16
+ if ( global . FinalizationRegistry ) {
17
+ SessionCache = class WeakSessionCache {
18
+ constructor ( maxCachedSessions ) {
19
+ this . _maxCachedSessions = maxCachedSessions
20
+ this . _sessionCache = new Map ( )
21
+ this . _sessionRegistry = new global . FinalizationRegistry ( ( key ) => {
22
+ if ( this . _sessionCache . size < this . _maxCachedSessions ) {
23
+ return
24
+ }
25
+
26
+ const ref = this . _sessionCache . get ( key )
27
+ if ( ref !== undefined && ref . deref ( ) === undefined ) {
28
+ this . _sessionCache . delete ( key )
29
+ }
30
+ } )
31
+ }
32
+
33
+ get ( sessionKey ) {
34
+ const ref = this . _sessionCache . get ( sessionKey )
35
+ return ref ? ref . deref ( ) : null
36
+ }
37
+
38
+ set ( sessionKey , session ) {
39
+ if ( this . _maxCachedSessions === 0 ) {
40
+ return
41
+ }
42
+
43
+ this . _sessionCache . set ( sessionKey , new WeakRef ( session ) )
44
+ this . _sessionRegistry . register ( session , sessionKey )
45
+ }
46
+ }
47
+ } else {
48
+ SessionCache = class SimpleSessionCache {
49
+ constructor ( maxCachedSessions ) {
50
+ this . _maxCachedSessions = maxCachedSessions
51
+ this . _sessionCache = new Map ( )
52
+ }
53
+
54
+ get ( sessionKey ) {
55
+ return this . _sessionCache . get ( sessionKey )
56
+ }
57
+
58
+ set ( sessionKey , session ) {
59
+ if ( this . _maxCachedSessions === 0 ) {
60
+ return
61
+ }
62
+
63
+ if ( this . _sessionCache . size >= this . _maxCachedSessions ) {
64
+ // remove the oldest session
65
+ const { value : oldestKey } = this . _sessionCache . keys ( ) . next ( )
66
+ this . _sessionCache . delete ( oldestKey )
67
+ }
68
+
69
+ this . _sessionCache . set ( sessionKey , session )
70
+ }
71
+ }
72
+ }
73
+
14
74
function buildConnector ( { maxCachedSessions, socketPath, timeout, ...opts } ) {
15
75
if ( maxCachedSessions != null && ( ! Number . isInteger ( maxCachedSessions ) || maxCachedSessions < 0 ) ) {
16
76
throw new InvalidArgumentError ( 'maxCachedSessions must be a positive integer or zero' )
17
77
}
18
78
19
79
const options = { path : socketPath , ...opts }
20
- const sessionCache = new Map ( )
80
+ const sessionCache = new SessionCache ( maxCachedSessions == null ? 100 : maxCachedSessions )
21
81
timeout = timeout == null ? 10e3 : timeout
22
- maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions
23
82
24
83
return function connect ( { hostname, host, protocol, port, servername, localAddress, httpSocket } , callback ) {
25
84
let socket
@@ -47,25 +106,9 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
47
106
48
107
socket
49
108
. on ( 'session' , function ( session ) {
50
- // cache is disabled
51
- if ( maxCachedSessions === 0 ) {
52
- return
53
- }
54
-
55
- if ( sessionCache . size >= maxCachedSessions ) {
56
- // remove the oldest session
57
- const { value : oldestKey } = sessionCache . keys ( ) . next ( )
58
- sessionCache . delete ( oldestKey )
59
- }
60
-
109
+ // TODO (fix): Can a session become invalid once established? Don't think so?
61
110
sessionCache . set ( sessionKey , session )
62
111
} )
63
- . on ( 'error' , function ( err ) {
64
- if ( sessionKey && err . code !== 'UND_ERR_INFO' ) {
65
- // TODO (fix): Only delete for session related errors.
66
- sessionCache . delete ( sessionKey )
67
- }
68
- } )
69
112
} else {
70
113
assert ( ! httpSocket , 'httpSocket can only be sent on TLS update' )
71
114
socket = net . connect ( {
0 commit comments