@@ -199,6 +199,9 @@ const onServerStreamErrorChannel = dc.channel('http2.server.stream.error');
199
199
const onServerStreamFinishChannel = dc . channel ( 'http2.server.stream.finish' ) ;
200
200
const onServerStreamCloseChannel = dc . channel ( 'http2.server.stream.close' ) ;
201
201
202
+ const clientTracingChannels = dc . tracingChannel ( 'http2.client' ) ;
203
+ const serverTracingChannels = dc . tracingChannel ( 'http2.server' ) ;
204
+
202
205
let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'http2' , ( fn ) => {
203
206
debug = fn ;
204
207
} ) ;
@@ -261,6 +264,7 @@ const kSentHeaders = Symbol('sent-headers');
261
264
const kSentTrailers = Symbol ( 'sent-trailers' ) ;
262
265
const kServer = Symbol ( 'server' ) ;
263
266
const kState = Symbol ( 'state' ) ;
267
+ const kTracingContext = Symbol ( 'tracing-context' ) ;
264
268
const kType = Symbol ( 'type' ) ;
265
269
const kWriteGeneric = Symbol ( 'write-generic' ) ;
266
270
@@ -344,6 +348,31 @@ function emit(self, ...args) {
344
348
ReflectApply ( self . emit , self , args ) ;
345
349
}
346
350
351
+ function createServerStream ( session , handle , id , options , headers , endOfStream ) {
352
+ // eslint-disable-next-line no-use-before-define
353
+ const stream = new ServerHttp2Stream ( session , handle , id , options , headers ) ;
354
+ if ( endOfStream ) {
355
+ stream . push ( null ) ;
356
+ stream [ kState ] . endAfterHeaders = true ;
357
+ }
358
+
359
+ if ( headers [ HTTP2_HEADER_METHOD ] === HTTP2_METHOD_HEAD ) {
360
+ // For head requests, there must not be a body...
361
+ // end the writable side immediately.
362
+ stream . end ( ) ;
363
+ stream [ kState ] . flags |= STREAM_FLAGS_HEAD_REQUEST ;
364
+ }
365
+
366
+ if ( onServerStreamStartChannel . hasSubscribers ) {
367
+ onServerStreamStartChannel . publish ( {
368
+ stream,
369
+ headers,
370
+ } ) ;
371
+ }
372
+
373
+ return stream ;
374
+ }
375
+
347
376
// Called when a new block of headers has been received for a given
348
377
// stream. The stream may or may not be new. If the stream is new,
349
378
// create the associated Http2Stream instance and emit the 'stream'
@@ -376,23 +405,24 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
376
405
}
377
406
// session[kType] can be only one of two possible values
378
407
if ( type === NGHTTP2_SESSION_SERVER ) {
379
- // eslint-disable-next-line no-use-before-define
380
- stream = new ServerHttp2Stream ( session , handle , id , { } , obj ) ;
381
- if ( endOfStream ) {
382
- stream . push ( null ) ;
383
- }
384
- if ( obj [ HTTP2_HEADER_METHOD ] === HTTP2_METHOD_HEAD ) {
385
- // For head requests, there must not be a body...
386
- // end the writable side immediately.
387
- stream . end ( ) ;
388
- stream [ kState ] . flags |= STREAM_FLAGS_HEAD_REQUEST ;
389
- }
390
-
391
- if ( onServerStreamStartChannel . hasSubscribers ) {
392
- onServerStreamStartChannel . publish ( {
393
- stream,
394
- headers : obj ,
408
+ if ( serverTracingChannels . hasSubscribers ) {
409
+ const context = { headers : obj , flags } ;
410
+ serverTracingChannels . start . runStores ( context , ( ) => {
411
+ try {
412
+ stream = createServerStream ( session , handle , id , { } , obj ) ;
413
+ stream [ kTracingContext ] = context ;
414
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
415
+ } catch ( e ) {
416
+ context . error = e ;
417
+ serverTracingChannels . error . publish ( context ) ;
418
+ throw e ;
419
+ } finally {
420
+ serverTracingChannels . end . publish ( context ) ;
421
+ }
395
422
} ) ;
423
+ } else {
424
+ stream = createServerStream ( session , handle , id , { } , obj , endOfStream ) ;
425
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
396
426
}
397
427
} else {
398
428
// eslint-disable-next-line no-use-before-define
@@ -408,10 +438,10 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
408
438
stream . push ( null ) ;
409
439
}
410
440
stream . end ( ) ;
441
+ if ( endOfStream )
442
+ stream [ kState ] . endAfterHeaders = true ;
443
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
411
444
}
412
- if ( endOfStream )
413
- stream [ kState ] . endAfterHeaders = true ;
414
- process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
415
445
} else {
416
446
let event ;
417
447
const status = obj [ HTTP2_HEADER_STATUS ] ;
@@ -452,9 +482,10 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
452
482
} ) ;
453
483
}
454
484
}
455
- }
456
- if ( endOfStream ) {
457
- stream . push ( null ) ;
485
+
486
+ if ( endOfStream ) {
487
+ stream . push ( null ) ;
488
+ }
458
489
}
459
490
}
460
491
@@ -1791,7 +1822,31 @@ class ClientHttp2Session extends Http2Session {
1791
1822
// associated Http2Stream instance.
1792
1823
request ( headers , options ) {
1793
1824
debugSessionObj ( this , 'initiating request' ) ;
1825
+ headers = ObjectAssign ( { __proto__ : null } , headers ) ;
1826
+ options = { ...options } ;
1827
+ if ( ! clientTracingChannels . hasSubscribers ) {
1828
+ this . _requestPrepare ( headers , options ) ;
1829
+ return this . _requestFinalize ( headers , options ) ;
1830
+ }
1831
+
1832
+ this . _requestPrepare ( headers , options ) ;
1833
+ const context = { headers, options } ;
1834
+ return clientTracingChannels . start . runStores ( context , ( ) => {
1835
+ try {
1836
+ const stream = this . _requestFinalize ( context . headers , context . options ) ;
1837
+ stream [ kTracingContext ] = context ;
1838
+ return stream ;
1839
+ } catch ( e ) {
1840
+ context . error = e ;
1841
+ clientTracingChannels . error . publish ( context ) ;
1842
+ throw e ;
1843
+ } finally {
1844
+ clientTracingChannels . end . publish ( context ) ;
1845
+ }
1846
+ } ) ;
1847
+ }
1794
1848
1849
+ _requestPrepare ( headers , options ) {
1795
1850
if ( this . destroyed )
1796
1851
throw new ERR_HTTP2_INVALID_SESSION ( ) ;
1797
1852
@@ -1814,9 +1869,6 @@ class ClientHttp2Session extends Http2Session {
1814
1869
assertIsObject ( headers , 'headers' ) ;
1815
1870
assertIsObject ( options , 'options' ) ;
1816
1871
1817
- headers = ObjectAssign ( { __proto__ : null } , headers ) ;
1818
- options = { ...options } ;
1819
-
1820
1872
if ( headers [ HTTP2_HEADER_METHOD ] === undefined )
1821
1873
headers [ HTTP2_HEADER_METHOD ] = HTTP2_METHOD_GET ;
1822
1874
@@ -1848,7 +1900,9 @@ class ClientHttp2Session extends Http2Session {
1848
1900
} else {
1849
1901
validateBoolean ( options . endStream , 'options.endStream' ) ;
1850
1902
}
1903
+ }
1851
1904
1905
+ _requestFinalize ( headers , options ) {
1852
1906
const headersList = mapToHeaders ( headers ) ;
1853
1907
1854
1908
// eslint-disable-next-line no-use-before-define
@@ -1866,6 +1920,13 @@ class ClientHttp2Session extends Http2Session {
1866
1920
if ( options . waitForTrailers )
1867
1921
stream [ kState ] . flags |= STREAM_FLAGS_HAS_TRAILERS ;
1868
1922
1923
+ if ( onClientStreamCreatedChannel . hasSubscribers ) {
1924
+ onClientStreamCreatedChannel . publish ( {
1925
+ stream,
1926
+ headers,
1927
+ } ) ;
1928
+ }
1929
+
1869
1930
const { signal } = options ;
1870
1931
if ( signal ) {
1871
1932
validateAbortSignal ( signal , 'options.signal' ) ;
@@ -1895,17 +1956,11 @@ class ClientHttp2Session extends Http2Session {
1895
1956
onConnect ( ) ;
1896
1957
}
1897
1958
1898
- if ( onClientStreamCreatedChannel . hasSubscribers ) {
1899
- onClientStreamCreatedChannel . publish ( {
1900
- stream,
1901
- headers,
1902
- } ) ;
1903
- }
1904
-
1905
1959
return stream ;
1906
1960
}
1907
1961
}
1908
1962
1963
+
1909
1964
function trackWriteState ( stream , bytes ) {
1910
1965
const session = stream [ kSession ] ;
1911
1966
stream [ kState ] . writeQueueSize += bytes ;
@@ -2008,18 +2063,31 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
2008
2063
stream . once ( 'finish' , finishFn ) ;
2009
2064
}
2010
2065
2066
+ const context = stream [ kTracingContext ] ;
2011
2067
if ( type === NGHTTP2_SESSION_CLIENT ) {
2012
2068
if ( onClientStreamCloseChannel . hasSubscribers ) {
2013
2069
onClientStreamCloseChannel . publish ( {
2014
2070
stream,
2015
2071
code,
2016
2072
} ) ;
2017
2073
}
2018
- } else if ( onServerStreamCloseChannel . hasSubscribers ) {
2019
- onServerStreamCloseChannel . publish ( {
2020
- stream,
2021
- code,
2022
- } ) ;
2074
+
2075
+ if ( context ) {
2076
+ context . result = code ;
2077
+ clientTracingChannels . asyncEnd . publish ( context ) ;
2078
+ }
2079
+ } else {
2080
+ if ( onServerStreamCloseChannel . hasSubscribers ) {
2081
+ onServerStreamCloseChannel . publish ( {
2082
+ stream,
2083
+ code,
2084
+ } ) ;
2085
+ }
2086
+
2087
+ if ( context ) {
2088
+ context . result = code ;
2089
+ serverTracingChannels . asyncEnd . publish ( context ) ;
2090
+ }
2023
2091
}
2024
2092
}
2025
2093
@@ -2415,6 +2483,41 @@ class Http2Stream extends Duplex {
2415
2483
}
2416
2484
const hasHandle = handle !== undefined ;
2417
2485
2486
+ // RST code 8 not emitted as an error as its used by clients to signify
2487
+ // abort and is already covered by aborted event, also allows more
2488
+ // seamless compatibility with http1
2489
+ if ( err == null && code !== NGHTTP2_NO_ERROR && code !== NGHTTP2_CANCEL )
2490
+ err = new ERR_HTTP2_STREAM_ERROR ( nameForErrorCode [ code ] || code ) ;
2491
+
2492
+ if ( err ) {
2493
+ const context = this [ kTracingContext ] ;
2494
+ if ( session [ kType ] === NGHTTP2_SESSION_CLIENT ) {
2495
+ if ( onClientStreamErrorChannel . hasSubscribers ) {
2496
+ onClientStreamErrorChannel . publish ( {
2497
+ stream : this ,
2498
+ error : err ,
2499
+ } ) ;
2500
+ }
2501
+
2502
+ if ( context ) {
2503
+ context . error = err ;
2504
+ clientTracingChannels . error . publish ( context ) ;
2505
+ }
2506
+ } else {
2507
+ if ( onServerStreamErrorChannel . hasSubscribers ) {
2508
+ onServerStreamErrorChannel . publish ( {
2509
+ stream : this ,
2510
+ error : err ,
2511
+ } ) ;
2512
+ }
2513
+
2514
+ if ( context ) {
2515
+ context . error = err ;
2516
+ serverTracingChannels . error . publish ( context ) ;
2517
+ }
2518
+ }
2519
+ }
2520
+
2418
2521
if ( ! this . closed )
2419
2522
closeStream ( this , code , hasHandle ? kForceRstStream : kNoRstStream ) ;
2420
2523
this . push ( null ) ;
@@ -2430,12 +2533,6 @@ class Http2Stream extends Duplex {
2430
2533
sessionState . writeQueueSize -= state . writeQueueSize ;
2431
2534
state . writeQueueSize = 0 ;
2432
2535
2433
- // RST code 8 not emitted as an error as its used by clients to signify
2434
- // abort and is already covered by aborted event, also allows more
2435
- // seamless compatibility with http1
2436
- if ( err == null && code !== NGHTTP2_NO_ERROR && code !== NGHTTP2_CANCEL )
2437
- err = new ERR_HTTP2_STREAM_ERROR ( nameForErrorCode [ code ] || code ) ;
2438
-
2439
2536
this [ kSession ] = undefined ;
2440
2537
this [ kHandle ] = undefined ;
2441
2538
@@ -2447,21 +2544,6 @@ class Http2Stream extends Duplex {
2447
2544
setImmediate ( ( ) => {
2448
2545
session [ kMaybeDestroy ] ( ) ;
2449
2546
} ) ;
2450
- if ( err ) {
2451
- if ( session [ kType ] === NGHTTP2_SESSION_CLIENT ) {
2452
- if ( onClientStreamErrorChannel . hasSubscribers ) {
2453
- onClientStreamErrorChannel . publish ( {
2454
- stream : this ,
2455
- error : err ,
2456
- } ) ;
2457
- }
2458
- } else if ( onServerStreamErrorChannel . hasSubscribers ) {
2459
- onServerStreamErrorChannel . publish ( {
2460
- stream : this ,
2461
- error : err ,
2462
- } ) ;
2463
- }
2464
- }
2465
2547
callback ( err ) ;
2466
2548
}
2467
2549
// The Http2Stream can be destroyed if it has closed and if the readable
0 commit comments