@@ -52,10 +52,12 @@ const {
5252} = require ( 'internal/http2/util' ) ;
5353
5454const {
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' ) ;
5961
6062const { ShutdownWrap, WriteWrap } = process . binding ( 'stream_wrap' ) ;
6163const { constants } = binding ;
@@ -280,8 +282,8 @@ function onStreamClose(code, hasData) {
280282 ` [has data? ${ hasData } ]` ) ;
281283
282284 if ( ! stream . closed ) {
283- // Unenroll from timeouts
284- unenroll ( stream ) ;
285+ // Clear timeout and remove timeout listeners
286+ stream . setTimeout ( 0 ) ;
285287 stream . removeAllListeners ( 'timeout' ) ;
286288
287289 // Set the state flags
@@ -788,6 +790,7 @@ class Http2Session extends EventEmitter {
788790 this [ kType ] = type ;
789791 this [ kProxySocket ] = null ;
790792 this [ kSocket ] = socket ;
793+ this [ kTimeout ] = null ;
791794
792795 // Do not use nagle's algorithm
793796 if ( typeof socket . setNoDelay === 'function' )
@@ -828,7 +831,7 @@ class Http2Session extends EventEmitter {
828831 [ kUpdateTimer ] ( ) {
829832 if ( this . destroyed )
830833 return ;
831- _unrefActive ( this ) ;
834+ if ( this [ kTimeout ] ) _unrefActive ( this [ kTimeout ] ) ;
832835 }
833836
834837 // Sets the id of the next stream to be created by this Http2Session.
@@ -1019,7 +1022,7 @@ class Http2Session extends EventEmitter {
10191022 state . flags |= SESSION_FLAGS_DESTROYED ;
10201023
10211024 // Clear timeout and remove timeout listeners
1022- unenroll ( this ) ;
1025+ this . setTimeout ( 0 ) ;
10231026 this . removeAllListeners ( 'timeout' ) ;
10241027
10251028 // Destroy any pending and open streams
@@ -1322,6 +1325,8 @@ class Http2Stream extends Duplex {
13221325 this [ kSession ] = session ;
13231326 session [ kState ] . pendingStreams . add ( this ) ;
13241327
1328+ this [ kTimeout ] = null ;
1329+
13251330 this [ kState ] = {
13261331 flags : STREAM_FLAGS_PENDING ,
13271332 rstCode : NGHTTP2_NO_ERROR ,
@@ -1336,9 +1341,10 @@ class Http2Stream extends Duplex {
13361341 [ kUpdateTimer ] ( ) {
13371342 if ( this . destroyed )
13381343 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 ] ) ;
13421348 }
13431349
13441350 [ kInit ] ( id , handle ) {
@@ -1560,7 +1566,7 @@ class Http2Stream extends Duplex {
15601566
15611567 // Close initiates closing the Http2Stream instance by sending an RST_STREAM
15621568 // 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
15641570 // a callback is passed, it is registered to listen for the 'close' event.
15651571 //
15661572 // If the handle and stream ID have not been assigned yet, the close
@@ -1577,8 +1583,8 @@ class Http2Stream extends Duplex {
15771583 if ( code < 0 || code > kMaxInt )
15781584 throw new errors . RangeError ( 'ERR_OUT_OF_RANGE' , 'code' ) ;
15791585
1580- // Unenroll the timeout.
1581- unenroll ( this ) ;
1586+ // Clear timeout and remove timeout listeners
1587+ this . setTimeout ( 0 ) ;
15821588 this . removeAllListeners ( 'timeout' ) ;
15831589
15841590 // Close the writable
@@ -1637,8 +1643,10 @@ class Http2Stream extends Duplex {
16371643 handle . destroy ( ) ;
16381644 session [ kState ] . streams . delete ( id ) ;
16391645 } else {
1640- unenroll ( this ) ;
1646+ // Clear timeout and remove timeout listeners
1647+ this . setTimeout ( 0 ) ;
16411648 this . removeAllListeners ( 'timeout' ) ;
1649+
16421650 state . flags |= STREAM_FLAGS_CLOSED ;
16431651 abort ( this ) ;
16441652 this . end ( ) ;
@@ -2216,21 +2224,24 @@ const setTimeout = {
22162224 value : function ( msecs , callback ) {
22172225 if ( this . destroyed )
22182226 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+
22242235 if ( msecs === 0 ) {
2225- unenroll ( this ) ;
22262236 if ( callback !== undefined ) {
22272237 if ( typeof callback !== 'function' )
22282238 throw new errors . TypeError ( 'ERR_INVALID_CALLBACK' ) ;
22292239 this . removeListener ( 'timeout' , callback ) ;
22302240 }
22312241 } 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+
22342245 if ( callback !== undefined ) {
22352246 if ( typeof callback !== 'function' )
22362247 throw new errors . TypeError ( 'ERR_INVALID_CALLBACK' ) ;
0 commit comments