Skip to content

Commit 0234a8e

Browse files
RaisinTentargos
authored andcommitted
http2: add diagnostics channel 'http2.server.stream.finish'
Signed-off-by: Darshan Sen <[email protected]> PR-URL: #58560 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent 29f34a7 commit 0234a8e

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

doc/api/diagnostics_channel.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,6 +1260,14 @@ Emitted when a stream is started on the server.
12601260

12611261
Emitted when an error occurs during the processing of a stream on the server.
12621262

1263+
`http2.server.stream.finish`
1264+
1265+
* `stream` {ServerHttp2Stream}
1266+
* `headers` {HTTP/2 Headers Object}
1267+
* `flags` {number}
1268+
1269+
Emitted when a stream is sent on the server.
1270+
12631271
#### Modules
12641272

12651273
> Stability: 1 - Experimental

lib/internal/http2/core.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ const onClientStreamCloseChannel = dc.channel('http2.client.stream.close');
193193
const onServerStreamCreatedChannel = dc.channel('http2.server.stream.created');
194194
const onServerStreamStartChannel = dc.channel('http2.server.stream.start');
195195
const onServerStreamErrorChannel = dc.channel('http2.server.stream.error');
196+
const onServerStreamFinishChannel = dc.channel('http2.server.stream.finish');
196197

197198
let debug = require('internal/util/debuglog').debuglog('http2', (fn) => {
198199
debug = fn;
@@ -2917,8 +2918,17 @@ class ServerHttp2Stream extends Http2Stream {
29172918
}
29182919

29192920
const ret = this[kHandle].respond(headersList, streamOptions);
2920-
if (ret < 0)
2921+
if (ret < 0) {
29212922
this.destroy(new NghttpError(ret));
2923+
} else if (onServerStreamFinishChannel.hasSubscribers) {
2924+
// No point in running this if the respond() call above fails because
2925+
// that would mean that it is an invalid call.
2926+
onServerStreamFinishChannel.publish({
2927+
stream: this,
2928+
headers,
2929+
flags: state.flags,
2930+
});
2931+
}
29222932
}
29232933

29242934
// Initiate a response using an open FD. Note that there are fewer
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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.finish' channel when
9+
// ServerHttp2Streams#respond() sends a regular stream as well as a push stream.
10+
11+
const Countdown = require('../common/countdown');
12+
const assert = require('assert');
13+
const dc = require('diagnostics_channel');
14+
const http2 = require('http2');
15+
const { Duplex } = require('stream');
16+
17+
const serverHttp2StreamFinishCount = 2;
18+
19+
dc.subscribe('http2.server.stream.finish', common.mustCall(({ stream, headers, flags }) => {
20+
// Since ServerHttp2Stream is not exported from any module, this just checks
21+
// if the stream is an instance of Duplex and the constructor name is
22+
// 'ServerHttp2Stream'.
23+
assert.ok(stream instanceof Duplex);
24+
assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream');
25+
26+
assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object');
27+
28+
assert.strictEqual(typeof flags, 'number');
29+
}, serverHttp2StreamFinishCount));
30+
31+
const server = http2.createServer();
32+
server.on('stream', common.mustCall((stream) => {
33+
stream.respond();
34+
stream.end();
35+
36+
stream.pushStream({}, common.mustSucceed((pushStream) => {
37+
pushStream.respond();
38+
pushStream.end();
39+
}));
40+
}));
41+
42+
server.listen(0, common.mustCall(() => {
43+
const port = server.address().port;
44+
const client = http2.connect(`http://localhost:${port}`);
45+
46+
const countdown = new Countdown(serverHttp2StreamFinishCount, () => {
47+
client.close();
48+
server.close();
49+
});
50+
51+
const stream = client.request({});
52+
stream.on('response', common.mustCall(() => {
53+
countdown.dec();
54+
}));
55+
56+
client.on('stream', common.mustCall((pushStream) => {
57+
pushStream.on('push', common.mustCall(() => {
58+
countdown.dec();
59+
}));
60+
}));
61+
}));

0 commit comments

Comments
 (0)