@@ -127,6 +127,11 @@ function sessionName(type) {
127127 }
128128}
129129
130+ // Top level to avoid creating a closure
131+ function emit ( ) {
132+ this . emit . apply ( this , arguments ) ;
133+ }
134+
130135// Called when a new block of headers has been received for a given
131136// stream. The stream may or may not be new. If the stream is new,
132137// create the associated Http2Stream instance and emit the 'stream'
@@ -168,7 +173,7 @@ function onSessionHeaders(id, cat, flags, headers) {
168173 'report this as a bug in Node.js' ) ;
169174 }
170175 streams . set ( id , stream ) ;
171- process . nextTick ( ( ) => owner . emit ( 'stream' , stream , obj , flags ) ) ;
176+ process . nextTick ( emit . bind ( owner , 'stream' , stream , obj , flags ) ) ;
172177 } else {
173178 let event ;
174179 let status ;
@@ -201,7 +206,7 @@ function onSessionHeaders(id, cat, flags, headers) {
201206 'report this as a bug in Node.js' ) ;
202207 }
203208 debug ( `[${ sessionName ( owner [ kType ] ) } ] emitting stream '${ event } ' event` ) ;
204- process . nextTick ( ( ) => stream . emit ( event , obj , flags ) ) ;
209+ process . nextTick ( emit . bind ( stream , event , obj , flags ) ) ;
205210 }
206211}
207212
@@ -252,16 +257,15 @@ function onSessionStreamClose(id, code) {
252257
253258 if ( state . fd !== undefined ) {
254259 debug ( `Closing fd ${ state . fd } for stream ${ id } ` ) ;
255- fs . close ( state . fd , ( err ) => {
256- if ( err )
257- process . nextTick ( ( ) => stream . emit ( 'error' , err ) ) ;
258- } ) ;
260+ fs . close ( state . fd , afterFDClose . bind ( stream ) ) ;
259261 }
260262
261- setImmediate ( ( ) => {
262- stream . destroy ( ) ;
263- debug ( `[${ sessionName ( owner [ kType ] ) } ] stream ${ id } is closed` ) ;
264- } ) ;
263+ setImmediate ( stream . destroy . bind ( stream ) ) ;
264+ }
265+
266+ function afterFDClose ( err ) {
267+ if ( err )
268+ process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
265269}
266270
267271// Called when an error event needs to be triggered
@@ -304,14 +308,21 @@ function onSettings(ack) {
304308 const owner = this [ kOwner ] ;
305309 debug ( `[${ sessionName ( owner [ kType ] ) } ] new settings received` ) ;
306310 _unrefActive ( this ) ;
311+ let fn ;
312+ let event = 'remoteSettings' ;
307313 if ( ack ) {
308314 if ( owner [ kState ] . pendingAck > 0 )
309315 owner [ kState ] . pendingAck -- ;
310316 owner [ kLocalSettings ] = undefined ;
311- process . nextTick ( ( ) => owner . emit ( 'localSettings' , owner . localSettings ) ) ;
317+ event = 'localSettings' ;
312318 } else {
313319 owner [ kRemoteSettings ] = undefined ;
314- process . nextTick ( ( ) => owner . emit ( 'remoteSettings' , owner . remoteSettings ) ) ;
320+ }
321+ // Only emit the event if there are listeners registered
322+ if ( owner . listenerCount ( event ) > 0 ) {
323+ const settings = event === 'localSettings' ?
324+ owner . localSettings : owner . remoteSettings ;
325+ process . nextTick ( emit . bind ( owner , event , settings ) ) ;
315326 }
316327}
317328
@@ -328,7 +339,15 @@ function onPriority(id, parent, weight, exclusive) {
328339 const stream = streams . get ( id ) ;
329340 const emitter = stream === undefined ? owner : stream ;
330341 process . nextTick (
331- ( ) => emitter . emit ( 'priority' , id , parent , weight , exclusive ) ) ;
342+ emit . bind ( emitter , 'priority' , id , parent , weight , exclusive ) ) ;
343+ }
344+
345+ function emitFrameError ( ) {
346+ if ( ! this . emit ( 'frameError' , type , code , id ) ) {
347+ const err = new errors . Error ( 'ERR_HTTP2_FRAME_ERROR' , type , code , id ) ;
348+ err . errno = code ;
349+ this . emit ( 'error' , err ) ;
350+ }
332351}
333352
334353// Called by the native layer when an error has occurred sending a
@@ -341,29 +360,25 @@ function onFrameError(id, type, code) {
341360 const streams = owner [ kState ] . streams ;
342361 const stream = streams . get ( id ) ;
343362 const emitter = stream !== undefined ? stream : owner ;
344- process . nextTick ( ( ) => {
345- if ( ! emitter . emit ( 'frameError' , type , code , id ) ) {
346- const err = new errors . Error ( 'ERR_HTTP2_FRAME_ERROR' , type , code , id ) ;
347- err . errno = code ;
348- emitter . emit ( 'error' , err ) ;
349- }
350- } ) ;
363+ process . nextTick ( emitFrameError . bind ( emitter ) ) ;
364+ }
365+
366+ function emitGoaway ( state , code , lastStreamID , buf ) {
367+ this . emit ( 'goaway' , code , lastStreamID , buf ) ;
368+ // Tear down the session or destroy
369+ if ( ! state . shuttingDown && ! state . shutdown ) {
370+ this . shutdown ( { } , this . destroy . bind ( this ) ) ;
371+ } else {
372+ this . destroy ( ) ;
373+ }
351374}
352375
353376// Called by the native layer when a goaway frame has been received
354377function onGoawayData ( code , lastStreamID , buf ) {
355378 const owner = this [ kOwner ] ;
356379 const state = owner [ kState ] ;
357380 debug ( `[${ sessionName ( owner [ kType ] ) } ] goaway data received` ) ;
358- process . nextTick ( ( ) => {
359- owner . emit ( 'goaway' , code , lastStreamID , buf ) ;
360- // Tear down the session or destroy
361- if ( ! state . shuttingDown && ! state . shutdown ) {
362- owner . shutdown ( { } , ( ) => { owner . destroy ( ) ; } ) ;
363- } else {
364- owner . destroy ( ) ;
365- }
366- } ) ;
381+ process . nextTick ( emitGoaway . bind ( owner , state , code , lastStreamID , buf ) ) ;
367382}
368383
369384// Returns the padding to use per frame. The selectPadding callback is set
@@ -524,7 +539,7 @@ function setupHandle(session, socket, type, options) {
524539 options . settings : Object . create ( null ) ;
525540
526541 session . settings ( settings ) ;
527- process . nextTick ( ( ) => session . emit ( 'connect' , session , socket ) ) ;
542+ process . nextTick ( emit . bind ( session , 'connect' , session , socket ) )
528543 } ;
529544}
530545
@@ -627,7 +642,7 @@ function doShutdown(options) {
627642 process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
628643 return ;
629644 }
630- process . nextTick ( ( ) => this . emit ( 'shutdown' , options ) ) ;
645+ process . nextTick ( emit . bind ( this , 'shutdown' , options ) ) ;
631646 debug ( `[${ sessionName ( this [ kType ] ) } ] shutdown is complete` ) ;
632647}
633648
@@ -1207,7 +1222,7 @@ function streamOnSessionConnect() {
12071222 debug ( `[${ sessionName ( session [ kType ] ) } ] session connected. emiting stream ` +
12081223 'connect' ) ;
12091224 this [ kState ] . connecting = false ;
1210- process . nextTick ( ( ) => this . emit ( 'connect' ) ) ;
1225+ process . nextTick ( emit . bind ( this , 'connect' ) ) ;
12111226}
12121227
12131228function streamOnceReady ( ) {
@@ -1318,7 +1333,7 @@ class Http2Stream extends Duplex {
13181333
13191334 _write ( data , encoding , cb ) {
13201335 if ( this [ kID ] === undefined ) {
1321- this . once ( 'ready' , ( ) => this . _write ( data , encoding , cb ) ) ;
1336+ this . once ( 'ready' , this . _write . bind ( this , data , encoding , cb ) ) ;
13221337 return ;
13231338 }
13241339 _unrefActive ( this ) ;
@@ -1341,7 +1356,7 @@ class Http2Stream extends Duplex {
13411356
13421357 _writev ( data , cb ) {
13431358 if ( this [ kID ] === undefined ) {
1344- this . once ( 'ready' , ( ) => this . _writev ( data , cb ) ) ;
1359+ this . once ( 'ready' , this . _writev . bindthis , data , cb ) ;
13451360 return ;
13461361 }
13471362 _unrefActive ( this ) ;
@@ -1368,7 +1383,7 @@ class Http2Stream extends Duplex {
13681383
13691384 _read ( nread ) {
13701385 if ( this [ kID ] === undefined ) {
1371- this . once ( 'ready' , ( ) => this . _read ( nread ) ) ;
1386+ this . once ( 'ready' , this . _read . bind ( this , nread ) ) ;
13721387 return ;
13731388 }
13741389 if ( this . destroyed ) {
@@ -1397,7 +1412,7 @@ class Http2Stream extends Duplex {
13971412 if ( this [ kID ] === undefined ) {
13981413 debug (
13991414 `[${ sessionName ( session [ kType ] ) } ] queuing rstStream for new stream` ) ;
1400- this . once ( 'ready' , ( ) => this . rstStream ( code ) ) ;
1415+ this . once ( 'ready' , this . rstStream . bind ( this , code ) ) ;
14011416 return ;
14021417 }
14031418 debug ( `[${ sessionName ( session [ kType ] ) } ] sending rstStream for stream ` +
@@ -1438,7 +1453,7 @@ class Http2Stream extends Duplex {
14381453 const session = this [ kSession ] ;
14391454 if ( this [ kID ] === undefined ) {
14401455 debug ( `[${ sessionName ( session [ kType ] ) } ] queuing priority for new stream` ) ;
1441- this . once ( 'ready' , ( ) => this . priority ( options ) ) ;
1456+ this . once ( 'ready' , this . priority . bind ( this , options ) ) ;
14421457 return ;
14431458 }
14441459 debug ( `[${ sessionName ( session [ kType ] ) } ] sending priority for stream ` +
@@ -1479,10 +1494,7 @@ class Http2Stream extends Duplex {
14791494 // Unenroll the timer
14801495 unenroll ( this ) ;
14811496
1482- setImmediate ( ( ) => {
1483- if ( handle !== undefined )
1484- handle . destroyStream ( this [ kID ] ) ;
1485- } ) ;
1497+ setImmediate ( finishStreamDestroy . bind ( this , handle ) ) ;
14861498 session [ kState ] . streams . delete ( this [ kID ] ) ;
14871499 delete this [ kSession ] ;
14881500
@@ -1493,12 +1505,17 @@ class Http2Stream extends Duplex {
14931505 const err = new errors . Error ( 'ERR_HTTP2_STREAM_ERROR' , code ) ;
14941506 process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
14951507 }
1496- process . nextTick ( ( ) => this . emit ( 'streamClosed' , code ) ) ;
1508+ process . nextTick ( emit . bind ( this , 'streamClosed' , code ) ) ;
14971509 debug ( `[${ sessionName ( session [ kType ] ) } ] stream ${ this [ kID ] } destroyed` ) ;
14981510 callback ( err ) ;
14991511 }
15001512}
15011513
1514+ function finishStreamDestroy ( handle ) {
1515+ if ( handle !== undefined )
1516+ handle . destroyStream ( this [ kID ] ) ;
1517+ }
1518+
15021519function processHeaders ( headers ) {
15031520 assertIsObject ( headers , 'headers' ) ;
15041521 headers = Object . assign ( Object . create ( null ) , headers ) ;
@@ -1545,6 +1562,53 @@ function processRespondWithFD(fd, headers) {
15451562 }
15461563}
15471564
1565+ function doSendFD ( session , options , fd , headers , err , stat ) {
1566+ if ( this . destroyed || session . destroyed ) {
1567+ abort ( this ) ;
1568+ return ;
1569+ }
1570+ if ( err ) {
1571+ process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
1572+ return ;
1573+ }
1574+ if ( ! stat . isFile ( ) ) {
1575+ err = new errors . Error ( 'ERR_HTTP2_SEND_FILE' ) ;
1576+ process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
1577+ return ;
1578+ }
1579+
1580+ // Set the content-length by default
1581+ headers [ HTTP2_HEADER_CONTENT_LENGTH ] = stat . size ;
1582+ if ( typeof options . statCheck === 'function' &&
1583+ options . statCheck . call ( this , stat , headers ) === false ) {
1584+ return ;
1585+ }
1586+
1587+ const headersList = mapToHeaders ( headers ,
1588+ assertValidPseudoHeaderResponse ) ;
1589+ if ( ! Array . isArray ( headersList ) ) {
1590+ throw headersList ;
1591+ }
1592+
1593+ processRespondWithFD . call ( this , fd , headersList ) ;
1594+ }
1595+
1596+ function afterOpen ( session , options , headers , err , fd ) {
1597+ const state = this [ kState ] ;
1598+ if ( this . destroyed || session . destroyed ) {
1599+ abort ( this ) ;
1600+ return ;
1601+ }
1602+ if ( err ) {
1603+ process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
1604+ return ;
1605+ }
1606+ state . fd = fd ;
1607+
1608+ fs . fstat ( fd , doSendFD . bind ( this , session , options , fd , headers ) ) ;
1609+ }
1610+
1611+
15481612class ServerHttp2Stream extends Http2Stream {
15491613 constructor ( session , id , options , headers ) {
15501614 super ( session , options ) ;
@@ -1795,48 +1859,7 @@ class ServerHttp2Stream extends Http2Stream {
17951859 throw new errors . Error ( 'ERR_HTTP2_PAYLOAD_FORBIDDEN' , statusCode ) ;
17961860 }
17971861
1798- fs . open ( path , 'r' , ( err , fd ) => {
1799- if ( this . destroyed || session . destroyed ) {
1800- abort ( this ) ;
1801- return ;
1802- }
1803- if ( err ) {
1804- process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
1805- return ;
1806- }
1807- state . fd = fd ;
1808-
1809- fs . fstat ( fd , ( err , stat ) => {
1810- if ( this . destroyed || session . destroyed ) {
1811- abort ( this ) ;
1812- return ;
1813- }
1814- if ( err ) {
1815- process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
1816- return ;
1817- }
1818- if ( ! stat . isFile ( ) ) {
1819- err = new errors . Error ( 'ERR_HTTP2_SEND_FILE' ) ;
1820- process . nextTick ( ( ) => this . emit ( 'error' , err ) ) ;
1821- return ;
1822- }
1823-
1824- // Set the content-length by default
1825- headers [ HTTP2_HEADER_CONTENT_LENGTH ] = stat . size ;
1826- if ( typeof options . statCheck === 'function' &&
1827- options . statCheck . call ( this , stat , headers ) === false ) {
1828- return ;
1829- }
1830-
1831- const headersList = mapToHeaders ( headers ,
1832- assertValidPseudoHeaderResponse ) ;
1833- if ( ! Array . isArray ( headersList ) ) {
1834- throw headersList ;
1835- }
1836-
1837- processRespondWithFD . call ( this , fd , headersList ) ;
1838- } ) ;
1839- } ) ;
1862+ fs . open ( path , 'r' , afterOpen . bind ( this , session , options , headers ) ) ;
18401863 }
18411864
18421865 // Sends a block of informational headers. In theory, the HTTP/2 spec
@@ -2088,7 +2111,7 @@ function connectionListener(socket) {
20882111
20892112 socket [ kServer ] = this ;
20902113
2091- process . nextTick ( ( ) => this . emit ( 'session' , session ) ) ;
2114+ process . nextTick ( emit . bind ( this , 'session' , session ) ) ;
20922115}
20932116
20942117function initializeOptions ( options ) {
0 commit comments