http2: add diagnostics channel 'http2.server.stream.close'
Signed-off-by: Darshan Sen <raisinten@gmail.com> PR-URL: https://github.com/nodejs/node/pull/58602 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
This commit is contained in:
parent
e027da9289
commit
85e8cc6ff3
@ -1268,6 +1268,13 @@ Emitted when an error occurs during the processing of a stream on the server.
|
|||||||
|
|
||||||
Emitted when a stream is sent on the server.
|
Emitted when a stream is sent on the server.
|
||||||
|
|
||||||
|
`http2.server.stream.close`
|
||||||
|
|
||||||
|
* `stream` {ServerHttp2Stream}
|
||||||
|
|
||||||
|
Emitted when a stream is closed on the server. The HTTP/2 error code used when
|
||||||
|
closing the stream can be retrieved using the `stream.rstCode` property.
|
||||||
|
|
||||||
#### Modules
|
#### Modules
|
||||||
|
|
||||||
> Stability: 1 - Experimental
|
> Stability: 1 - Experimental
|
||||||
|
@ -196,6 +196,7 @@ const onServerStreamCreatedChannel = dc.channel('http2.server.stream.created');
|
|||||||
const onServerStreamStartChannel = dc.channel('http2.server.stream.start');
|
const onServerStreamStartChannel = dc.channel('http2.server.stream.start');
|
||||||
const onServerStreamErrorChannel = dc.channel('http2.server.stream.error');
|
const onServerStreamErrorChannel = dc.channel('http2.server.stream.error');
|
||||||
const onServerStreamFinishChannel = dc.channel('http2.server.stream.finish');
|
const onServerStreamFinishChannel = dc.channel('http2.server.stream.finish');
|
||||||
|
const onServerStreamCloseChannel = dc.channel('http2.server.stream.close');
|
||||||
|
|
||||||
let debug = require('internal/util/debuglog').debuglog('http2', (fn) => {
|
let debug = require('internal/util/debuglog').debuglog('http2', (fn) => {
|
||||||
debug = fn;
|
debug = fn;
|
||||||
@ -2011,9 +2012,12 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
|
|||||||
stream.once('finish', finishFn);
|
stream.once('finish', finishFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === NGHTTP2_SESSION_CLIENT &&
|
if (type === NGHTTP2_SESSION_CLIENT) {
|
||||||
onClientStreamCloseChannel.hasSubscribers) {
|
if (onClientStreamCloseChannel.hasSubscribers) {
|
||||||
onClientStreamCloseChannel.publish({ stream });
|
onClientStreamCloseChannel.publish({ stream });
|
||||||
|
}
|
||||||
|
} else if (onServerStreamCloseChannel.hasSubscribers) {
|
||||||
|
onServerStreamCloseChannel.publish({ stream });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
if (!common.hasCrypto)
|
||||||
|
common.skip('missing crypto');
|
||||||
|
|
||||||
|
// This test ensures that the built-in HTTP/2 diagnostics channels are reporting
|
||||||
|
// the diagnostics messages for the 'http2.server.stream.close' channel when
|
||||||
|
// a ServerHttp2Stream is destroyed because of an error.
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
const http2 = require('http2');
|
||||||
|
const { Duplex } = require('stream');
|
||||||
|
|
||||||
|
dc.subscribe('http2.server.stream.close', common.mustCall(({ stream }) => {
|
||||||
|
// Since ServerHttp2Stream is not exported from any module, this just checks
|
||||||
|
// if the stream is an instance of Duplex and the constructor name is
|
||||||
|
// 'ServerHttp2Stream'.
|
||||||
|
assert.ok(stream instanceof Duplex);
|
||||||
|
assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream');
|
||||||
|
assert.strictEqual(stream.closed, true);
|
||||||
|
assert.strictEqual(stream.destroyed, true);
|
||||||
|
|
||||||
|
assert.strictEqual(stream.rstCode, http2.constants.NGHTTP2_INTERNAL_ERROR);
|
||||||
|
}));
|
||||||
|
|
||||||
|
const server = http2.createServer();
|
||||||
|
|
||||||
|
server.on('stream', common.mustCall((stream) => {
|
||||||
|
let expectedError;
|
||||||
|
|
||||||
|
stream.on('error', common.mustCall((err) => {
|
||||||
|
assert.strictEqual(err, expectedError);
|
||||||
|
}));
|
||||||
|
|
||||||
|
expectedError = new Error('HTTP/2 server stream error');
|
||||||
|
stream.destroy(expectedError);
|
||||||
|
}));
|
||||||
|
|
||||||
|
server.listen(0, common.mustCall(() => {
|
||||||
|
const port = server.address().port;
|
||||||
|
const client = http2.connect(`http://localhost:${port}`);
|
||||||
|
|
||||||
|
const stream = client.request({});
|
||||||
|
stream.on('error', common.mustCall((err) => {
|
||||||
|
assert.strictEqual(err.code, 'ERR_HTTP2_STREAM_ERROR');
|
||||||
|
|
||||||
|
client.close();
|
||||||
|
server.close();
|
||||||
|
}));
|
||||||
|
}));
|
@ -0,0 +1,63 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
if (!common.hasCrypto)
|
||||||
|
common.skip('missing crypto');
|
||||||
|
|
||||||
|
// This test ensures that the built-in HTTP/2 diagnostics channels are reporting
|
||||||
|
// the diagnostics messages for the 'http2.server.stream.close' channel when
|
||||||
|
// ServerHttp2Streams created by these actions are closed:
|
||||||
|
// - in response to an incoming 'stream' event from the client
|
||||||
|
// - the server calling ServerHttp2Stream#pushStream()
|
||||||
|
|
||||||
|
const Countdown = require('../common/countdown');
|
||||||
|
const assert = require('assert');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
const http2 = require('http2');
|
||||||
|
const { Duplex } = require('stream');
|
||||||
|
|
||||||
|
const serverHttp2StreamCloseCount = 2;
|
||||||
|
|
||||||
|
dc.subscribe('http2.server.stream.close', common.mustCall(({ stream }) => {
|
||||||
|
// Since ServerHttp2Stream is not exported from any module, this just checks
|
||||||
|
// if the stream is an instance of Duplex and the constructor name is
|
||||||
|
// 'ServerHttp2Stream'.
|
||||||
|
assert.ok(stream instanceof Duplex);
|
||||||
|
assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream');
|
||||||
|
assert.strictEqual(stream.closed, true);
|
||||||
|
assert.strictEqual(stream.destroyed, false);
|
||||||
|
|
||||||
|
assert.strictEqual(stream.rstCode, http2.constants.NGHTTP2_NO_ERROR);
|
||||||
|
}, serverHttp2StreamCloseCount));
|
||||||
|
|
||||||
|
const server = http2.createServer();
|
||||||
|
server.on('stream', common.mustCall((stream) => {
|
||||||
|
stream.respond();
|
||||||
|
stream.end();
|
||||||
|
|
||||||
|
stream.pushStream({}, common.mustSucceed((pushStream) => {
|
||||||
|
pushStream.respond();
|
||||||
|
pushStream.end();
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
|
||||||
|
server.listen(0, common.mustCall(() => {
|
||||||
|
const port = server.address().port;
|
||||||
|
const client = http2.connect(`http://localhost:${port}`);
|
||||||
|
|
||||||
|
const countdown = new Countdown(serverHttp2StreamCloseCount, () => {
|
||||||
|
client.close();
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
const stream = client.request({});
|
||||||
|
stream.on('response', common.mustCall(() => {
|
||||||
|
countdown.dec();
|
||||||
|
}));
|
||||||
|
|
||||||
|
client.on('stream', common.mustCall((pushStream) => {
|
||||||
|
pushStream.on('push', common.mustCall(() => {
|
||||||
|
countdown.dec();
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
}));
|
Loading…
x
Reference in New Issue
Block a user