GeezerVison is showing github.com — http2: add diagnostics channel 'http2.server.stream.start' · nodejs/node@b4df8d3
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/diagnostics_channel.md +7Lines changed: 7 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1246,6 +1246,13 @@ closing the stream can be retrieved using the `stream.rstCode` property. | 1246 | 1246 |
| 1247 | 1247 | Emitted when a stream is created on the server. | 1248 | 1248 |
| | 1249 | +`http2.server.stream.start` | | 1250 | + | | 1251 | +* `stream` {ServerHttp2Stream} | | 1252 | +* `headers` {HTTP/2 Headers Object} | | 1253 | + | | 1254 | +Emitted when a stream is started on the server. | | 1255 | + | 1249 | 1256 | #### Modules | 1250 | 1257 |
| 1251 | 1258 | > Stability: 1 - Experimental | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/http2/core.js +17-1Lines changed: 17 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -191,6 +191,7 @@ const onClientStreamErrorChannel = dc.channel('http2.client.stream.error'); | 191 | 191 | const onClientStreamFinishChannel = dc.channel('http2.client.stream.finish'); | 192 | 192 | const onClientStreamCloseChannel = dc.channel('http2.client.stream.close'); | 193 | 193 | const onServerStreamCreatedChannel = dc.channel('http2.server.stream.created'); | | 194 | +const onServerStreamStartChannel = dc.channel('http2.server.stream.start'); | 194 | 195 |
| 195 | 196 | let debug = require('internal/util/debuglog').debuglog('http2', (fn) => { | 196 | 197 | debug = fn; | @@ -373,6 +374,12 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) { | 373 | 374 | headers: obj, | 374 | 375 | }); | 375 | 376 | } | | 377 | + if (onServerStreamStartChannel.hasSubscribers) { | | 378 | + onServerStreamStartChannel.publish({ | | 379 | + stream, | | 380 | + headers: obj, | | 381 | + }); | | 382 | + } | 376 | 383 | if (endOfStream) { | 377 | 384 | stream.push(null); | 378 | 385 | } | @@ -2838,7 +2845,16 @@ class ServerHttp2Stream extends Http2Stream { | 2838 | 2845 | if (headRequest) | 2839 | 2846 | stream[kState].flags |= STREAM_FLAGS_HEAD_REQUEST; | 2840 | 2847 |
| 2841 | | - process.nextTick(callback, null, stream, headers, 0); | | 2848 | + process.nextTick(() => { | | 2849 | + if (onServerStreamStartChannel.hasSubscribers) { | | 2850 | + onServerStreamStartChannel.publish({ | | 2851 | + stream, | | 2852 | + headers, | | 2853 | + }); | | 2854 | + } | | 2855 | + | | 2856 | + callback(null, stream, headers, 0); | | 2857 | + }); | 2842 | 2858 |
| 2843 | 2859 | if (onServerStreamCreatedChannel.hasSubscribers) { | 2844 | 2860 | onServerStreamCreatedChannel.publish({ | |
Collapse file Copy file name to clipboard +65Lines changed: 65 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | + | | 3 | +const common = require('../common'); | | 4 | +if (!common.hasCrypto) | | 5 | + common.skip('missing crypto'); | | 6 | + | | 7 | +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting | | 8 | +// the diagnostics messages for the 'http2.server.stream.start' channel only | | 9 | +// after the 'http2.server.stream.created' channel. | | 10 | + | | 11 | +const Countdown = require('../common/countdown'); | | 12 | +const assert = require('assert'); | | 13 | +const dc = require('diagnostics_channel'); | | 14 | +const http2 = require('http2'); | | 15 | + | | 16 | +const serverHttp2StreamCreationCount = 2; | | 17 | + | | 18 | +const map = {}; | | 19 | + | | 20 | +dc.subscribe('http2.server.stream.created', common.mustCall(({ stream, headers }) => { | | 21 | + map[stream.id] = { ...map[stream.id], 'createdTime': process.hrtime.bigint() }; | | 22 | +}, serverHttp2StreamCreationCount)); | | 23 | + | | 24 | +dc.subscribe('http2.server.stream.start', common.mustCall(({ stream, headers }) => { | | 25 | + map[stream.id] = { ...map[stream.id], 'startTime': process.hrtime.bigint() }; | | 26 | +}, serverHttp2StreamCreationCount)); | | 27 | + | | 28 | +const server = http2.createServer(); | | 29 | +server.on('stream', common.mustCall((stream) => { | | 30 | + stream.respond(); | | 31 | + stream.end(); | | 32 | + | | 33 | + stream.pushStream({}, common.mustSucceed((pushStream) => { | | 34 | + pushStream.respond(); | | 35 | + pushStream.end(); | | 36 | + })); | | 37 | +})); | | 38 | + | | 39 | +server.listen(0, common.mustCall(() => { | | 40 | + const port = server.address().port; | | 41 | + const client = http2.connect(`http://localhost:${port}`); | | 42 | + | | 43 | + const countdown = new Countdown(serverHttp2StreamCreationCount, () => { | | 44 | + client.close(); | | 45 | + server.close(); | | 46 | + | | 47 | + const timings = Object.values(map); | | 48 | + assert.strictEqual(timings.length, serverHttp2StreamCreationCount); | | 49 | + | | 50 | + for (const { createdTime, startTime } of timings) { | | 51 | + assert.ok(createdTime < startTime); | | 52 | + } | | 53 | + }); | | 54 | + | | 55 | + const stream = client.request({}); | | 56 | + stream.on('response', common.mustCall(() => { | | 57 | + countdown.dec(); | | 58 | + })); | | 59 | + | | 60 | + client.on('stream', common.mustCall((pushStream) => { | | 61 | + pushStream.on('push', common.mustCall(() => { | | 62 | + countdown.dec(); | | 63 | + })); | | 64 | + })); | | 65 | +})); |
Collapse file Copy file name to clipboard +60Lines changed: 60 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | + | | 3 | +const common = require('../common'); | | 4 | +if (!common.hasCrypto) | | 5 | + common.skip('missing crypto'); | | 6 | + | | 7 | +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting | | 8 | +// the diagnostics messages for the 'http2.server.stream.start' channel when | | 9 | +// ServerHttp2Streams are started by both: | | 10 | +// - in response to an incoming 'stream' event from the client | | 11 | +// - the server calling ServerHttp2Stream#pushStream() | | 12 | + | | 13 | +const Countdown = require('../common/countdown'); | | 14 | +const assert = require('assert'); | | 15 | +const dc = require('diagnostics_channel'); | | 16 | +const http2 = require('http2'); | | 17 | +const { Duplex } = require('stream'); | | 18 | + | | 19 | +const serverHttp2StreamCreationCount = 2; | | 20 | + | | 21 | +dc.subscribe('http2.server.stream.start', common.mustCall(({ stream, headers }) => { | | 22 | + // Since ServerHttp2Stream is not exported from any module, this just checks | | 23 | + // if the stream is an instance of Duplex and the constructor name is | | 24 | + // 'ServerHttp2Stream'. | | 25 | + assert.ok(stream instanceof Duplex); | | 26 | + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); | | 27 | + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); | | 28 | +}, serverHttp2StreamCreationCount)); | | 29 | + | | 30 | +const server = http2.createServer(); | | 31 | +server.on('stream', common.mustCall((stream) => { | | 32 | + stream.respond(); | | 33 | + stream.end(); | | 34 | + | | 35 | + stream.pushStream({}, common.mustSucceed((pushStream) => { | | 36 | + pushStream.respond(); | | 37 | + pushStream.end(); | | 38 | + })); | | 39 | +})); | | 40 | + | | 41 | +server.listen(0, common.mustCall(() => { | | 42 | + const port = server.address().port; | | 43 | + const client = http2.connect(`http://localhost:${port}`); | | 44 | + | | 45 | + const countdown = new Countdown(serverHttp2StreamCreationCount, () => { | | 46 | + client.close(); | | 47 | + server.close(); | | 48 | + }); | | 49 | + | | 50 | + const stream = client.request({}); | | 51 | + stream.on('response', common.mustCall(() => { | | 52 | + countdown.dec(); | | 53 | + })); | | 54 | + | | 55 | + client.on('stream', common.mustCall((pushStream) => { | | 56 | + pushStream.on('push', common.mustCall(() => { | | 57 | + countdown.dec(); | | 58 | + })); | | 59 | + })); | | 60 | +})); |
|