@@ -198,6 +198,9 @@ const onServerStreamErrorChannel = dc.channel('http2.server.stream.error');
198
198
const onServerStreamFinishChannel = dc . channel ( 'http2.server.stream.finish' ) ;
199
199
const onServerStreamCloseChannel = dc . channel ( 'http2.server.stream.close' ) ;
200
200
201
+ const clientTracingChannels = dc . tracingChannel ( 'http2.client' ) ;
202
+ const serverTracingChannels = dc . tracingChannel ( 'http2.server' ) ;
203
+
201
204
let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'http2' , ( fn ) => {
202
205
debug = fn ;
203
206
} ) ;
@@ -259,6 +262,7 @@ const kSentHeaders = Symbol('sent-headers');
259
262
const kSentTrailers = Symbol ( 'sent-trailers' ) ;
260
263
const kServer = Symbol ( 'server' ) ;
261
264
const kState = Symbol ( 'state' ) ;
265
+ const kTracingContext = Symbol ( 'tracing-context' ) ;
262
266
const kType = Symbol ( 'type' ) ;
263
267
const kWriteGeneric = Symbol ( 'write-generic' ) ;
264
268
@@ -342,6 +346,31 @@ function emit(self, ...args) {
342
346
ReflectApply ( self . emit , self , args ) ;
343
347
}
344
348
349
+ function createServerStream ( session , handle , id , options , headers , endOfStream ) {
350
+ // eslint-disable-next-line no-use-before-define
351
+ const stream = new ServerHttp2Stream ( session , handle , id , options , headers ) ;
352
+ if ( endOfStream ) {
353
+ stream . push ( null ) ;
354
+ stream [ kState ] . endAfterHeaders = true ;
355
+ }
356
+
357
+ if ( headers [ HTTP2_HEADER_METHOD ] === HTTP2_METHOD_HEAD ) {
358
+ // For head requests, there must not be a body...
359
+ // end the writable side immediately.
360
+ stream . end ( ) ;
361
+ stream [ kState ] . flags |= STREAM_FLAGS_HEAD_REQUEST ;
362
+ }
363
+
364
+ if ( onServerStreamStartChannel . hasSubscribers ) {
365
+ onServerStreamStartChannel . publish ( {
366
+ stream,
367
+ headers,
368
+ } ) ;
369
+ }
370
+
371
+ return stream ;
372
+ }
373
+
345
374
// Called when a new block of headers has been received for a given
346
375
// stream. The stream may or may not be new. If the stream is new,
347
376
// create the associated Http2Stream instance and emit the 'stream'
@@ -374,23 +403,24 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
374
403
}
375
404
// session[kType] can be only one of two possible values
376
405
if ( type === NGHTTP2_SESSION_SERVER ) {
377
- // eslint-disable-next-line no-use-before-define
378
- stream = new ServerHttp2Stream ( session , handle , id , { } , obj ) ;
379
- if ( endOfStream ) {
380
- stream . push ( null ) ;
381
- }
382
- if ( obj [ HTTP2_HEADER_METHOD ] === HTTP2_METHOD_HEAD ) {
383
- // For head requests, there must not be a body...
384
- // end the writable side immediately.
385
- stream . end ( ) ;
386
- stream [ kState ] . flags |= STREAM_FLAGS_HEAD_REQUEST ;
387
- }
388
-
389
- if ( onServerStreamStartChannel . hasSubscribers ) {
390
- onServerStreamStartChannel . publish ( {
391
- stream,
392
- headers : obj ,
406
+ if ( serverTracingChannels . start . hasSubscribers ) {
407
+ const context = { headers : obj , flags } ;
408
+ serverTracingChannels . start . runStores ( context , ( ) => {
409
+ try {
410
+ stream = createServerStream ( session , handle , id , { } , obj ) ;
411
+ stream [ kTracingContext ] = context ;
412
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
413
+ } catch ( e ) {
414
+ context . error = e ;
415
+ serverTracingChannels . error . publish ( context ) ;
416
+ throw e ;
417
+ } finally {
418
+ serverTracingChannels . end . publish ( context ) ;
419
+ }
393
420
} ) ;
421
+ } else {
422
+ stream = createServerStream ( session , handle , id , { } , obj , endOfStream ) ;
423
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
394
424
}
395
425
} else {
396
426
// eslint-disable-next-line no-use-before-define
@@ -406,10 +436,10 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
406
436
stream . push ( null ) ;
407
437
}
408
438
stream . end ( ) ;
439
+ if ( endOfStream )
440
+ stream [ kState ] . endAfterHeaders = true ;
441
+ process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
409
442
}
410
- if ( endOfStream )
411
- stream [ kState ] . endAfterHeaders = true ;
412
- process . nextTick ( emit , session , 'stream' , stream , obj , flags , headers ) ;
413
443
} else {
414
444
let event ;
415
445
const status = obj [ HTTP2_HEADER_STATUS ] ;
@@ -445,9 +475,10 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
445
475
} ) ;
446
476
}
447
477
}
448
- }
449
- if ( endOfStream ) {
450
- stream . push ( null ) ;
478
+
479
+ if ( endOfStream ) {
480
+ stream . push ( null ) ;
481
+ }
451
482
}
452
483
}
453
484
@@ -1779,7 +1810,31 @@ class ClientHttp2Session extends Http2Session {
1779
1810
// associated Http2Stream instance.
1780
1811
request ( headers , options ) {
1781
1812
debugSessionObj ( this , 'initiating request' ) ;
1813
+ headers = ObjectAssign ( { __proto__ : null } , headers ) ;
1814
+ options = { ...options } ;
1815
+ if ( ! clientTracingChannels . start . hasSubscribers ) {
1816
+ this . _requestPrepare ( headers , options ) ;
1817
+ return this . _requestFinalize ( headers , options ) ;
1818
+ }
1819
+
1820
+ this . _requestPrepare ( headers , options ) ;
1821
+ const context = { headers, options } ;
1822
+ return clientTracingChannels . start . runStores ( context , ( ) => {
1823
+ try {
1824
+ const stream = this . _requestFinalize ( context . headers , context . options ) ;
1825
+ stream [ kTracingContext ] = context ;
1826
+ return stream ;
1827
+ } catch ( e ) {
1828
+ context . error = e ;
1829
+ clientTracingChannels . error . publish ( context ) ;
1830
+ throw e ;
1831
+ } finally {
1832
+ clientTracingChannels . end . publish ( context ) ;
1833
+ }
1834
+ } ) ;
1835
+ }
1782
1836
1837
+ _requestPrepare ( headers , options ) {
1783
1838
if ( this . destroyed )
1784
1839
throw new ERR_HTTP2_INVALID_SESSION ( ) ;
1785
1840
@@ -1802,9 +1857,6 @@ class ClientHttp2Session extends Http2Session {
1802
1857
assertIsObject ( headers , 'headers' ) ;
1803
1858
assertIsObject ( options , 'options' ) ;
1804
1859
1805
- headers = ObjectAssign ( ObjectCreate ( null ) , headers ) ;
1806
- options = { ...options } ;
1807
-
1808
1860
if ( headers [ HTTP2_HEADER_METHOD ] === undefined )
1809
1861
headers [ HTTP2_HEADER_METHOD ] = HTTP2_METHOD_GET ;
1810
1862
@@ -1837,7 +1889,9 @@ class ClientHttp2Session extends Http2Session {
1837
1889
} else if ( typeof options . endStream !== 'boolean' ) {
1838
1890
throw new ERR_INVALID_ARG_VALUE ( 'options.endStream' , options . endStream ) ;
1839
1891
}
1892
+ }
1840
1893
1894
+ _requestFinalize ( headers , options ) {
1841
1895
const headersList = mapToHeaders ( headers ) ;
1842
1896
1843
1897
// eslint-disable-next-line no-use-before-define
@@ -1853,6 +1907,13 @@ class ClientHttp2Session extends Http2Session {
1853
1907
if ( options . waitForTrailers )
1854
1908
stream [ kState ] . flags |= STREAM_FLAGS_HAS_TRAILERS ;
1855
1909
1910
+ if ( onClientStreamCreatedChannel . hasSubscribers ) {
1911
+ onClientStreamCreatedChannel . publish ( {
1912
+ stream,
1913
+ headers,
1914
+ } ) ;
1915
+ }
1916
+
1856
1917
const { signal } = options ;
1857
1918
if ( signal ) {
1858
1919
validateAbortSignal ( signal , 'options.signal' ) ;
@@ -1883,17 +1944,11 @@ class ClientHttp2Session extends Http2Session {
1883
1944
onConnect ( ) ;
1884
1945
}
1885
1946
1886
- if ( onClientStreamCreatedChannel . hasSubscribers ) {
1887
- onClientStreamCreatedChannel . publish ( {
1888
- stream,
1889
- headers,
1890
- } ) ;
1891
- }
1892
-
1893
1947
return stream ;
1894
1948
}
1895
1949
}
1896
1950
1951
+
1897
1952
function trackWriteState ( stream , bytes ) {
1898
1953
const session = stream [ kSession ] ;
1899
1954
stream [ kState ] . writeQueueSize += bytes ;
@@ -1996,18 +2051,31 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
1996
2051
stream . once ( 'finish' , finishFn ) ;
1997
2052
}
1998
2053
2054
+ const context = stream [ kTracingContext ] ;
1999
2055
if ( type === NGHTTP2_SESSION_CLIENT ) {
2000
2056
if ( onClientStreamCloseChannel . hasSubscribers ) {
2001
2057
onClientStreamCloseChannel . publish ( {
2002
2058
stream,
2003
2059
code,
2004
2060
} ) ;
2005
2061
}
2006
- } else if ( onServerStreamCloseChannel . hasSubscribers ) {
2007
- onServerStreamCloseChannel . publish ( {
2008
- stream,
2009
- code,
2010
- } ) ;
2062
+
2063
+ if ( context ) {
2064
+ context . result = code ;
2065
+ clientTracingChannels . asyncEnd . publish ( context ) ;
2066
+ }
2067
+ } else {
2068
+ if ( onServerStreamCloseChannel . hasSubscribers ) {
2069
+ onServerStreamCloseChannel . publish ( {
2070
+ stream,
2071
+ code,
2072
+ } ) ;
2073
+ }
2074
+
2075
+ if ( context ) {
2076
+ context . result = code ;
2077
+ serverTracingChannels . asyncEnd . publish ( context ) ;
2078
+ }
2011
2079
}
2012
2080
}
2013
2081
@@ -2404,6 +2472,41 @@ class Http2Stream extends Duplex {
2404
2472
}
2405
2473
const hasHandle = handle !== undefined ;
2406
2474
2475
+ // RST code 8 not emitted as an error as its used by clients to signify
2476
+ // abort and is already covered by aborted event, also allows more
2477
+ // seamless compatibility with http1
2478
+ if ( err == null && code !== NGHTTP2_NO_ERROR && code !== NGHTTP2_CANCEL )
2479
+ err = new ERR_HTTP2_STREAM_ERROR ( nameForErrorCode [ code ] || code ) ;
2480
+
2481
+ if ( err ) {
2482
+ const context = this [ kTracingContext ] ;
2483
+ if ( session [ kType ] === NGHTTP2_SESSION_CLIENT ) {
2484
+ if ( onClientStreamErrorChannel . hasSubscribers ) {
2485
+ onClientStreamErrorChannel . publish ( {
2486
+ stream : this ,
2487
+ error : err ,
2488
+ } ) ;
2489
+ }
2490
+
2491
+ if ( context ) {
2492
+ context . error = err ;
2493
+ clientTracingChannels . error . publish ( context ) ;
2494
+ }
2495
+ } else {
2496
+ if ( onServerStreamErrorChannel . hasSubscribers ) {
2497
+ onServerStreamErrorChannel . publish ( {
2498
+ stream : this ,
2499
+ error : err ,
2500
+ } ) ;
2501
+ }
2502
+
2503
+ if ( context ) {
2504
+ context . error = err ;
2505
+ serverTracingChannels . error . publish ( context ) ;
2506
+ }
2507
+ }
2508
+ }
2509
+
2407
2510
if ( ! this . closed )
2408
2511
closeStream ( this , code , hasHandle ? kForceRstStream : kNoRstStream ) ;
2409
2512
this . push ( null ) ;
@@ -2419,12 +2522,6 @@ class Http2Stream extends Duplex {
2419
2522
sessionState . writeQueueSize -= state . writeQueueSize ;
2420
2523
state . writeQueueSize = 0 ;
2421
2524
2422
- // RST code 8 not emitted as an error as its used by clients to signify
2423
- // abort and is already covered by aborted event, also allows more
2424
- // seamless compatibility with http1
2425
- if ( err == null && code !== NGHTTP2_NO_ERROR && code !== NGHTTP2_CANCEL )
2426
- err = new ERR_HTTP2_STREAM_ERROR ( nameForErrorCode [ code ] || code ) ;
2427
-
2428
2525
this [ kSession ] = undefined ;
2429
2526
this [ kHandle ] = undefined ;
2430
2527
@@ -2433,21 +2530,6 @@ class Http2Stream extends Duplex {
2433
2530
// will destroy if it has been closed and there are no other open or
2434
2531
// pending streams.
2435
2532
session [ kMaybeDestroy ] ( ) ;
2436
- if ( err ) {
2437
- if ( session [ kType ] === NGHTTP2_SESSION_CLIENT ) {
2438
- if ( onClientStreamErrorChannel . hasSubscribers ) {
2439
- onClientStreamErrorChannel . publish ( {
2440
- stream : this ,
2441
- error : err ,
2442
- } ) ;
2443
- }
2444
- } else if ( onServerStreamErrorChannel . hasSubscribers ) {
2445
- onServerStreamErrorChannel . publish ( {
2446
- stream : this ,
2447
- error : err ,
2448
- } ) ;
2449
- }
2450
- }
2451
2533
callback ( err ) ;
2452
2534
}
2453
2535
// The Http2Stream can be destroyed if it has closed and if the readable
0 commit comments