@@ -52,10 +52,12 @@ const {
52
52
} = require ( 'internal/http2/util' ) ;
53
53
54
54
const {
55
- _unrefActive,
56
- enroll,
57
- unenroll
58
- } = require ( 'timers' ) ;
55
+ kTimeout,
56
+ setUnrefTimeout,
57
+ validateTimerDuration
58
+ } = require ( 'internal/timers' ) ;
59
+
60
+ const { _unrefActive } = require ( 'timers' ) ;
59
61
60
62
const { ShutdownWrap, WriteWrap } = process . binding ( 'stream_wrap' ) ;
61
63
const { constants } = binding ;
@@ -280,8 +282,8 @@ function onStreamClose(code, hasData) {
280
282
` [has data? ${ hasData } ]` ) ;
281
283
282
284
if ( ! stream . closed ) {
283
- // Unenroll from timeouts
284
- unenroll ( stream ) ;
285
+ // Clear timeout and remove timeout listeners
286
+ stream . setTimeout ( 0 ) ;
285
287
stream . removeAllListeners ( 'timeout' ) ;
286
288
287
289
// Set the state flags
@@ -788,6 +790,7 @@ class Http2Session extends EventEmitter {
788
790
this [ kType ] = type ;
789
791
this [ kProxySocket ] = null ;
790
792
this [ kSocket ] = socket ;
793
+ this [ kTimeout ] = null ;
791
794
792
795
// Do not use nagle's algorithm
793
796
if ( typeof socket . setNoDelay === 'function' )
@@ -828,7 +831,7 @@ class Http2Session extends EventEmitter {
828
831
[ kUpdateTimer ] ( ) {
829
832
if ( this . destroyed )
830
833
return ;
831
- _unrefActive ( this ) ;
834
+ if ( this [ kTimeout ] ) _unrefActive ( this [ kTimeout ] ) ;
832
835
}
833
836
834
837
// Sets the id of the next stream to be created by this Http2Session.
@@ -1019,7 +1022,7 @@ class Http2Session extends EventEmitter {
1019
1022
state . flags |= SESSION_FLAGS_DESTROYED ;
1020
1023
1021
1024
// Clear timeout and remove timeout listeners
1022
- unenroll ( this ) ;
1025
+ this . setTimeout ( 0 ) ;
1023
1026
this . removeAllListeners ( 'timeout' ) ;
1024
1027
1025
1028
// Destroy any pending and open streams
@@ -1322,6 +1325,8 @@ class Http2Stream extends Duplex {
1322
1325
this [ kSession ] = session ;
1323
1326
session [ kState ] . pendingStreams . add ( this ) ;
1324
1327
1328
+ this [ kTimeout ] = null ;
1329
+
1325
1330
this [ kState ] = {
1326
1331
flags : STREAM_FLAGS_PENDING ,
1327
1332
rstCode : NGHTTP2_NO_ERROR ,
@@ -1336,9 +1341,10 @@ class Http2Stream extends Duplex {
1336
1341
[ kUpdateTimer ] ( ) {
1337
1342
if ( this . destroyed )
1338
1343
return ;
1339
- _unrefActive ( this ) ;
1340
- if ( this [ kSession ] )
1341
- _unrefActive ( this [ kSession ] ) ;
1344
+ if ( this [ kTimeout ] )
1345
+ _unrefActive ( [ kTimeout ] ) ;
1346
+ if ( this [ kSession ] && this [ kSession ] [ kTimeout ] )
1347
+ _unrefActive ( this [ kSession ] [ kTimeout ] ) ;
1342
1348
}
1343
1349
1344
1350
[ kInit ] ( id , handle ) {
@@ -1560,7 +1566,7 @@ class Http2Stream extends Duplex {
1560
1566
1561
1567
// Close initiates closing the Http2Stream instance by sending an RST_STREAM
1562
1568
// frame to the connected peer. The readable and writable sides of the
1563
- // Http2Stream duplex are closed and the timeout timer is unenrolled . If
1569
+ // Http2Stream duplex are closed and the timeout timer is cleared . If
1564
1570
// a callback is passed, it is registered to listen for the 'close' event.
1565
1571
//
1566
1572
// If the handle and stream ID have not been assigned yet, the close
@@ -1577,8 +1583,8 @@ class Http2Stream extends Duplex {
1577
1583
if ( code < 0 || code > kMaxInt )
1578
1584
throw new errors . RangeError ( 'ERR_OUT_OF_RANGE' , 'code' ) ;
1579
1585
1580
- // Unenroll the timeout.
1581
- unenroll ( this ) ;
1586
+ // Clear timeout and remove timeout listeners
1587
+ this . setTimeout ( 0 ) ;
1582
1588
this . removeAllListeners ( 'timeout' ) ;
1583
1589
1584
1590
// Close the writable
@@ -1637,8 +1643,10 @@ class Http2Stream extends Duplex {
1637
1643
handle . destroy ( ) ;
1638
1644
session [ kState ] . streams . delete ( id ) ;
1639
1645
} else {
1640
- unenroll ( this ) ;
1646
+ // Clear timeout and remove timeout listeners
1647
+ this . setTimeout ( 0 ) ;
1641
1648
this . removeAllListeners ( 'timeout' ) ;
1649
+
1642
1650
state . flags |= STREAM_FLAGS_CLOSED ;
1643
1651
abort ( this ) ;
1644
1652
this . end ( ) ;
@@ -2216,21 +2224,24 @@ const setTimeout = {
2216
2224
value : function ( msecs , callback ) {
2217
2225
if ( this . destroyed )
2218
2226
return ;
2219
- if ( typeof msecs !== 'number' ) {
2220
- throw new errors . TypeError ( 'ERR_INVALID_ARG_TYPE' ,
2221
- 'msecs' ,
2222
- 'number' ) ;
2223
- }
2227
+
2228
+ // Type checking identical to timers.enroll()
2229
+ msecs = validateTimerDuration ( msecs ) ;
2230
+
2231
+ // Attempt to clear an existing timer lear in both cases -
2232
+ // even if it will be rescheduled we don't want to leak an existing timer.
2233
+ clearTimeout ( this [ kTimeout ] ) ;
2234
+
2224
2235
if ( msecs === 0 ) {
2225
- unenroll ( this ) ;
2226
2236
if ( callback !== undefined ) {
2227
2237
if ( typeof callback !== 'function' )
2228
2238
throw new errors . TypeError ( 'ERR_INVALID_CALLBACK' ) ;
2229
2239
this . removeListener ( 'timeout' , callback ) ;
2230
2240
}
2231
2241
} else {
2232
- enroll ( this , msecs ) ;
2233
- this [ kUpdateTimer ] ( ) ;
2242
+ this [ kTimeout ] = setUnrefTimeout ( this . _onTimeout . bind ( this ) , msecs ) ;
2243
+ if ( this [ kSession ] ) this [ kSession ] [ kUpdateTimer ] ( ) ;
2244
+
2234
2245
if ( callback !== undefined ) {
2235
2246
if ( typeof callback !== 'function' )
2236
2247
throw new errors . TypeError ( 'ERR_INVALID_CALLBACK' ) ;
0 commit comments