@@ -197,6 +197,9 @@ const onServerStreamErrorChannel = dc.channel('http2.server.stream.error');
197
197
const onServerStreamFinishChannel = dc . channel ( 'http2.server.stream.finish' ) ;
198
198
const onServerStreamCloseChannel = dc . channel ( 'http2.server.stream.close' ) ;
199
199
200
+ const clientTracingChannels = dc . tracingChannel ( 'http2.client' ) ;
201
+ const serverTracingChannels = dc . tracingChannel ( 'http2.server' ) ;
202
+
200
203
let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'http2' , ( fn ) => {
201
204
debug = fn ;
202
205
} ) ;
@@ -258,6 +261,7 @@ const kSentHeaders = Symbol('sent-headers');
258
261
const kSentTrailers = Symbol ( 'sent-trailers' ) ;
259
262
const kServer = Symbol ( 'server' ) ;
260
263
const kState = Symbol ( 'state' ) ;
264
+ const kTracingContext = Symbol ( 'tracing-context' ) ;
261
265
const kType = Symbol ( 'type' ) ;
262
266
const kWriteGeneric = Symbol ( 'write-generic' ) ;
263
267
@@ -341,6 +345,31 @@ function emit(self, ...args) {
341
345
ReflectApply ( self . emit , self , args ) ;
342
346
}
343
347
348
+ function createServerStream ( session , handle , id , options , headers , endOfStream ) {
349
+ // eslint-disable-next-line no-use-before-define
350
+ const stream = new ServerHttp2Stream ( session , handle , id , options , headers ) ;
351
+ if ( endOfStream ) {
352
+ stream . push ( null ) ;
353
+ stream [ kState ] . endAfterHeaders = true ;
354
+ }
355
+
356
+ if ( headers [ HTTP2_HEADER_METHOD ] === HTTP2_METHOD_HEAD ) {
357
+ // For head requests, there must not be a body...
358
+ // end the writable side immediately.
359
+ stream . end ( ) ;
360
+ stream [ kState ] . flags |= STREAM_FLAGS_HEAD_REQUEST ;
361
+ }
362
+
363
+ if ( onServerStreamStartChannel . hasSubscribers ) {
364
+ onServerStreamStartChannel . publish ( {
365
+ stream,
366
+ headers,
367
+ } ) ;
368
+ }
369
+
370
+ return stream ;
371
+ }
372
+
344
373
// Called when a new block of headers has been received for a given
345
374
// stream. The stream may or may not be new. If the stream is new,
346
375
// create the associated Http2Stream instance and emit the 'stream'
@@ -373,23 +402,24 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
373
402
}
374
403
// session[kType] can be only one of two possible values
375
404
if ( type === NGHTTP2_SESSION_SERVER ) {
376
- // eslint-disable-next-line no-use-before-define
377
- stream = new ServerHttp2Stream ( session , handle , id , { } , obj ) ;
378
- if ( endOfStream ) {
379
- stream . push ( null ) ;
380
- }
381
- if ( obj [ HTTP2_HEADER_METHOD ] === HTTP2_METHOD_HEAD ) {
382
- // For head requests, there must not be a body...
383
- // end the writable side immediately.
384
- stream . end ( ) ;
385
- stream [ kState ] . flags |= STREAM_FLAGS_HEAD_REQUEST ;
386
- }
387
-
388
- if ( onServerStreamStartChannel . hasSubscribers ) {
389
- onServerStreamStartChannel . publish ( {
390
- stream,
391
- headers : obj ,
405
+ if ( serverTracingChannels . hasSubscribers ) {
406
+ const context = { headers : obj , flags } ;
407
+ serverTracingChannels . start . runStores ( context , ( ) => {
408
+ try {
409
+ stream = createServerStream ( session , handle , id , { } , obj ) ;
410
+ stream [ kTracingContext ] = context ;
411
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
412
+ } catch ( e ) {
413
+ context . error = e ;
414
+ serverTracingChannels . error . publish ( context ) ;
415
+ throw e ;
416
+ } finally {
417
+ serverTracingChannels . end . publish ( context ) ;
418
+ }
392
419
} ) ;
420
+ } else {
421
+ stream = createServerStream ( session , handle , id , { } , obj , endOfStream ) ;
422
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
393
423
}
394
424
} else {
395
425
// eslint-disable-next-line no-use-before-define
@@ -405,10 +435,10 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
405
435
stream . push ( null ) ;
406
436
}
407
437
stream . end ( ) ;
438
+ if ( endOfStream )
439
+ stream [ kState ] . endAfterHeaders = true ;
440
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
408
441
}
409
- if ( endOfStream )
410
- stream [ kState ] . endAfterHeaders = true ;
411
- process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
412
442
} else {
413
443
let event ;
414
444
const status = obj [ HTTP2_HEADER_STATUS ] ;
@@ -444,9 +474,10 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
444
474
} ) ;
445
475
}
446
476
}
447
- }
448
- if ( endOfStream ) {
449
- stream . push ( null ) ;
477
+
478
+ if ( endOfStream ) {
479
+ stream . push ( null ) ;
480
+ }
450
481
}
451
482
}
452
483
@@ -1786,7 +1817,31 @@ class ClientHttp2Session extends Http2Session {
1786
1817
// associated Http2Stream instance.
1787
1818
request ( headers , options ) {
1788
1819
debugSessionObj ( this , 'initiating request' ) ;
1820
+ headers = ObjectAssign ( { __proto__ : null } , headers ) ;
1821
+ options = { ...options } ;
1822
+ if ( ! clientTracingChannels . hasSubscribers ) {
1823
+ this . _requestPrepare ( headers , options ) ;
1824
+ return this . _requestFinalize ( headers , options ) ;
1825
+ }
1826
+
1827
+ this . _requestPrepare ( headers , options ) ;
1828
+ const context = { headers, options } ;
1829
+ return clientTracingChannels . start . runStores ( context , ( ) => {
1830
+ try {
1831
+ const stream = this . _requestFinalize ( context . headers , context . options ) ;
1832
+ stream [ kTracingContext ] = context ;
1833
+ return stream ;
1834
+ } catch ( e ) {
1835
+ context . error = e ;
1836
+ clientTracingChannels . error . publish ( context ) ;
1837
+ throw e ;
1838
+ } finally {
1839
+ clientTracingChannels . end . publish ( context ) ;
1840
+ }
1841
+ } ) ;
1842
+ }
1789
1843
1844
+ _requestPrepare ( headers , options ) {
1790
1845
if ( this . destroyed )
1791
1846
throw new ERR_HTTP2_INVALID_SESSION ( ) ;
1792
1847
@@ -1809,9 +1864,6 @@ class ClientHttp2Session extends Http2Session {
1809
1864
assertIsObject ( headers , 'headers' ) ;
1810
1865
assertIsObject ( options , 'options' ) ;
1811
1866
1812
- headers = ObjectAssign ( { __proto__ : null } , headers ) ;
1813
- options = { ...options } ;
1814
-
1815
1867
if ( headers [ HTTP2_HEADER_METHOD ] === undefined )
1816
1868
headers [ HTTP2_HEADER_METHOD ] = HTTP2_METHOD_GET ;
1817
1869
@@ -1843,7 +1895,9 @@ class ClientHttp2Session extends Http2Session {
1843
1895
} else {
1844
1896
validateBoolean ( options . endStream , 'options.endStream' ) ;
1845
1897
}
1898
+ }
1846
1899
1900
+ _requestFinalize ( headers , options ) {
1847
1901
const headersList = mapToHeaders ( headers ) ;
1848
1902
1849
1903
// eslint-disable-next-line no-use-before-define
@@ -1859,6 +1913,13 @@ class ClientHttp2Session extends Http2Session {
1859
1913
if ( options . waitForTrailers )
1860
1914
stream [ kState ] . flags |= STREAM_FLAGS_HAS_TRAILERS ;
1861
1915
1916
+ if ( onClientStreamCreatedChannel . hasSubscribers ) {
1917
+ onClientStreamCreatedChannel . publish ( {
1918
+ stream,
1919
+ headers,
1920
+ } ) ;
1921
+ }
1922
+
1862
1923
const { signal } = options ;
1863
1924
if ( signal ) {
1864
1925
validateAbortSignal ( signal , 'options.signal' ) ;
@@ -1888,17 +1949,11 @@ class ClientHttp2Session extends Http2Session {
1888
1949
onConnect ( ) ;
1889
1950
}
1890
1951
1891
- if ( onClientStreamCreatedChannel . hasSubscribers ) {
1892
- onClientStreamCreatedChannel . publish ( {
1893
- stream,
1894
- headers,
1895
- } ) ;
1896
- }
1897
-
1898
1952
return stream ;
1899
1953
}
1900
1954
}
1901
1955
1956
+
1902
1957
function trackWriteState ( stream , bytes ) {
1903
1958
const session = stream [ kSession ] ;
1904
1959
stream [ kState ] . writeQueueSize += bytes ;
@@ -2001,18 +2056,31 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
2001
2056
stream . once ( 'finish' , finishFn ) ;
2002
2057
}
2003
2058
2059
+ const context = stream [ kTracingContext ] ;
2004
2060
if ( type === NGHTTP2_SESSION_CLIENT ) {
2005
2061
if ( onClientStreamCloseChannel . hasSubscribers ) {
2006
2062
onClientStreamCloseChannel . publish ( {
2007
2063
stream,
2008
2064
code,
2009
2065
} ) ;
2010
2066
}
2011
- } else if ( onServerStreamCloseChannel . hasSubscribers ) {
2012
- onServerStreamCloseChannel . publish ( {
2013
- stream,
2014
- code,
2015
- } ) ;
2067
+
2068
+ if ( context ) {
2069
+ context . result = code ;
2070
+ clientTracingChannels . asyncEnd . publish ( context ) ;
2071
+ }
2072
+ } else {
2073
+ if ( onServerStreamCloseChannel . hasSubscribers ) {
2074
+ onServerStreamCloseChannel . publish ( {
2075
+ stream,
2076
+ code,
2077
+ } ) ;
2078
+ }
2079
+
2080
+ if ( context ) {
2081
+ context . result = code ;
2082
+ serverTracingChannels . asyncEnd . publish ( context ) ;
2083
+ }
2016
2084
}
2017
2085
}
2018
2086
@@ -2408,6 +2476,41 @@ class Http2Stream extends Duplex {
2408
2476
}
2409
2477
const hasHandle = handle !== undefined ;
2410
2478
2479
+ // RST code 8 not emitted as an error as its used by clients to signify
2480
+ // abort and is already covered by aborted event, also allows more
2481
+ // seamless compatibility with http1
2482
+ if ( err == null && code !== NGHTTP2_NO_ERROR && code !== NGHTTP2_CANCEL )
2483
+ err = new ERR_HTTP2_STREAM_ERROR ( nameForErrorCode [ code ] || code ) ;
2484
+
2485
+ if ( err ) {
2486
+ const context = this [ kTracingContext ] ;
2487
+ if ( session [ kType ] === NGHTTP2_SESSION_CLIENT ) {
2488
+ if ( onClientStreamErrorChannel . hasSubscribers ) {
2489
+ onClientStreamErrorChannel . publish ( {
2490
+ stream : this ,
2491
+ error : err ,
2492
+ } ) ;
2493
+ }
2494
+
2495
+ if ( context ) {
2496
+ context . error = err ;
2497
+ clientTracingChannels . error . publish ( context ) ;
2498
+ }
2499
+ } else {
2500
+ if ( onServerStreamErrorChannel . hasSubscribers ) {
2501
+ onServerStreamErrorChannel . publish ( {
2502
+ stream : this ,
2503
+ error : err ,
2504
+ } ) ;
2505
+ }
2506
+
2507
+ if ( context ) {
2508
+ context . error = err ;
2509
+ serverTracingChannels . error . publish ( context ) ;
2510
+ }
2511
+ }
2512
+ }
2513
+
2411
2514
if ( ! this . closed )
2412
2515
closeStream ( this , code , hasHandle ? kForceRstStream : kNoRstStream ) ;
2413
2516
this . push ( null ) ;
@@ -2423,12 +2526,6 @@ class Http2Stream extends Duplex {
2423
2526
sessionState . writeQueueSize -= state . writeQueueSize ;
2424
2527
state . writeQueueSize = 0 ;
2425
2528
2426
- // RST code 8 not emitted as an error as its used by clients to signify
2427
- // abort and is already covered by aborted event, also allows more
2428
- // seamless compatibility with http1
2429
- if ( err == null && code !== NGHTTP2_NO_ERROR && code !== NGHTTP2_CANCEL )
2430
- err = new ERR_HTTP2_STREAM_ERROR ( nameForErrorCode [ code ] || code ) ;
2431
-
2432
2529
this [ kSession ] = undefined ;
2433
2530
this [ kHandle ] = undefined ;
2434
2531
@@ -2440,21 +2537,6 @@ class Http2Stream extends Duplex {
2440
2537
setImmediate ( ( ) => {
2441
2538
session [ kMaybeDestroy ] ( ) ;
2442
2539
} ) ;
2443
- if ( err ) {
2444
- if ( session [ kType ] === NGHTTP2_SESSION_CLIENT ) {
2445
- if ( onClientStreamErrorChannel . hasSubscribers ) {
2446
- onClientStreamErrorChannel . publish ( {
2447
- stream : this ,
2448
- error : err ,
2449
- } ) ;
2450
- }
2451
- } else if ( onServerStreamErrorChannel . hasSubscribers ) {
2452
- onServerStreamErrorChannel . publish ( {
2453
- stream : this ,
2454
- error : err ,
2455
- } ) ;
2456
- }
2457
- }
2458
2540
callback ( err ) ;
2459
2541
}
2460
2542
// The Http2Stream can be destroyed if it has closed and if the readable
0 commit comments