| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8f09a1f commit 0885546
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1232,6 +1232,13 @@ Emitted when an error occurs during the processing of a stream on the client. | |||
| 1232 | 1232 | ||
| 1233 | 1233 | Emitted when a stream is received on the client. | |
| 1234 | 1234 | ||
| 1235 | + `http2.client.stream.close` | ||
| 1236 | + | ||
| 1237 | + * `stream` {ClientHttp2Stream} | ||
| 1238 | + | ||
| 1239 | + Emitted when a stream is closed on the client. The HTTP/2 error code used when | ||
| 1240 | + closing the stream can be retrieved using the `stream.rstCode` property. | ||
| 1241 | + | ||
| 1235 | 1242 | #### Modules | |
| 1236 | 1243 | ||
| 1237 | 1244 | > Stability: 1 - Experimental | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -189,6 +189,7 @@ const onClientStreamCreatedChannel = dc.channel('http2.client.stream.created'); | |||
| 189 | 189 | const onClientStreamStartChannel = dc.channel('http2.client.stream.start'); | |
| 190 | 190 | const onClientStreamErrorChannel = dc.channel('http2.client.stream.error'); | |
| 191 | 191 | const onClientStreamFinishChannel = dc.channel('http2.client.stream.finish'); | |
| 192 | + const onClientStreamCloseChannel = dc.channel('http2.client.stream.close'); | ||
| 192 | 193 | ||
| 193 | 194 | let debug = require('internal/util/debuglog').debuglog('http2', (fn) => { | |
| 194 | 195 | debug = fn; | |
@@ -1979,6 +1980,7 @@ const kSubmitRstStream = 1; | |||
| 1979 | 1980 | const kForceRstStream = 2; | |
| 1980 | 1981 | ||
| 1981 | 1982 | function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) { | |
| 1983 | + const type = stream[kSession][kType]; | ||
| 1982 | 1984 | const state = stream[kState]; | |
| 1983 | 1985 | state.flags |= STREAM_FLAGS_CLOSED; | |
| 1984 | 1986 | state.rstCode = code; | |
@@ -2009,6 +2011,11 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) { | |||
| 2009 | 2011 | else | |
| 2010 | 2012 | stream.once('finish', finishFn); | |
| 2011 | 2013 | } | |
| 2014 | + | ||
| 2015 | + if (type === NGHTTP2_SESSION_CLIENT && | ||
| 2016 | + onClientStreamCloseChannel.hasSubscribers) { | ||
| 2017 | + onClientStreamCloseChannel.publish({ stream }); | ||
| 2018 | + } | ||
| 2012 | 2019 | } | |
| 2013 | 2020 | ||
| 2014 | 2021 | function finishCloseStream(code) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,44 @@ | |||
| 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.client.stream.close' channel when | ||
| 9 | + // a ClientHttp2Stream is destroyed because of an error. | ||
| 10 | + | ||
| 11 | + const assert = require('assert'); | ||
| 12 | + const dc = require('diagnostics_channel'); | ||
| 13 | + const http2 = require('http2'); | ||
| 14 | + const { Duplex } = require('stream'); | ||
| 15 | + | ||
| 16 | + dc.subscribe('http2.client.stream.close', common.mustCall(({ stream }) => { | ||
| 17 | + // Since ClientHttp2Stream is not exported from any module, this just checks | ||
| 18 | + // if the stream is an instance of Duplex and the constructor name is | ||
| 19 | + // 'ClientHttp2Stream'. | ||
| 20 | + assert.ok(stream instanceof Duplex); | ||
| 21 | + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); | ||
| 22 | + assert.strictEqual(stream.closed, true); | ||
| 23 | + assert.strictEqual(stream.destroyed, true); | ||
| 24 | + | ||
| 25 | + assert.strictEqual(stream.rstCode, http2.constants.NGHTTP2_CANCEL); | ||
| 26 | + })); | ||
| 27 | + | ||
| 28 | + const server = http2.createServer(); | ||
| 29 | + server.listen(0, common.mustCall(() => { | ||
| 30 | + const port = server.address().port; | ||
| 31 | + const client = http2.connect(`http://localhost:${port}`); | ||
| 32 | + | ||
| 33 | + const ac = new AbortController(); | ||
| 34 | + const stream = client.request({}, { signal: ac.signal }); | ||
| 35 | + ac.abort(); | ||
| 36 | + | ||
| 37 | + stream.on('error', common.mustCall((err) => { | ||
| 38 | + assert.strictEqual(err.code, 'ABORT_ERR'); | ||
| 39 | + assert.strictEqual(err.name, 'AbortError'); | ||
| 40 | + | ||
| 41 | + client.close(); | ||
| 42 | + server.close(); | ||
| 43 | + })); | ||
| 44 | + })); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,63 @@ | |||
| 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.client.stream.close' channel when | ||
| 9 | + // ClientHttp2Streams created by these actions are closed: | ||
| 10 | + // - the client calling ClientHttp2Session#request() | ||
| 11 | + // - in response to an incoming 'push' event from the server | ||
| 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 clientHttp2StreamCloseCount = 2; | ||
| 20 | + | ||
| 21 | + dc.subscribe('http2.client.stream.close', common.mustCall(({ stream }) => { | ||
| 22 | + // Since ClientHttp2Stream is not exported from any module, this just checks | ||
| 23 | + // if the stream is an instance of Duplex and the constructor name is | ||
| 24 | + // 'ClientHttp2Stream'. | ||
| 25 | + assert.ok(stream instanceof Duplex); | ||
| 26 | + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); | ||
| 27 | + assert.strictEqual(stream.closed, true); | ||
| 28 | + assert.strictEqual(stream.destroyed, false); | ||
| 29 | + | ||
| 30 | + assert.strictEqual(stream.rstCode, http2.constants.NGHTTP2_NO_ERROR); | ||
| 31 | + }, clientHttp2StreamCloseCount)); | ||
| 32 | + | ||
| 33 | + const server = http2.createServer(); | ||
| 34 | + server.on('stream', common.mustCall((stream) => { | ||
| 35 | + stream.respond(); | ||
| 36 | + stream.end(); | ||
| 37 | + | ||
| 38 | + stream.pushStream({}, common.mustSucceed((pushStream) => { | ||
| 39 | + pushStream.respond(); | ||
| 40 | + pushStream.end(); | ||
| 41 | + })); | ||
| 42 | + })); | ||
| 43 | + | ||
| 44 | + server.listen(0, common.mustCall(() => { | ||
| 45 | + const port = server.address().port; | ||
| 46 | + const client = http2.connect(`http://localhost:${port}`); | ||
| 47 | + | ||
| 48 | + const countdown = new Countdown(clientHttp2StreamCloseCount, () => { | ||
| 49 | + client.close(); | ||
| 50 | + server.close(); | ||
| 51 | + }); | ||
| 52 | + | ||
| 53 | + const stream = client.request({}); | ||
| 54 | + stream.on('response', common.mustCall(() => { | ||
| 55 | + countdown.dec(); | ||
| 56 | + })); | ||
| 57 | + | ||
| 58 | + client.on('stream', common.mustCall((pushStream) => { | ||
| 59 | + pushStream.on('push', common.mustCall(() => { | ||
| 60 | + countdown.dec(); | ||
| 61 | + })); | ||
| 62 | + })); | ||
| 63 | + })); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments