diff options
-rw-r--r-- | doc/api/http2.md | 11 | ||||
-rw-r--r-- | lib/internal/http2/core.js | 9 | ||||
-rw-r--r-- | test/parallel/test-http2-endafterheaders.js | 50 |
3 files changed, 69 insertions, 1 deletions
diff --git a/doc/api/http2.md b/doc/api/http2.md index 7aec57e111..feeb66aa88 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -958,6 +958,17 @@ added: v8.4.0 Set to `true` if the `Http2Stream` instance has been destroyed and is no longer usable. +#### http2stream.endAfterHeaders +<!-- YAML +added: REPLACEME +--> + +* {boolean} + +Set the `true` if the `END_STREAM` flag was set in the request or response +HEADERS frame received, indicating that no additional data should be received +and the readable side of the `Http2Stream` will be closed. + #### http2stream.pending <!-- YAML added: v9.4.0 diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index f2a298b6e5..0b9be932af 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -276,6 +276,8 @@ function onSessionHeaders(handle, id, cat, flags, headers) { } else { stream = new ClientHttp2Stream(session, handle, id, opts); } + if (endOfStream) + stream[kState].endAfterHeaders = true; process.nextTick(emit, session, 'stream', stream, obj, flags, headers); } else { let event; @@ -1548,7 +1550,8 @@ class Http2Stream extends Duplex { flags: STREAM_FLAGS_PENDING, rstCode: NGHTTP2_NO_ERROR, writeQueueSize: 0, - trailersReady: false + trailersReady: false, + endAfterHeaders: false }; this.on('pause', streamOnPause); @@ -1594,6 +1597,10 @@ class Http2Stream extends Duplex { return `Http2Stream ${util.format(obj)}`; } + get endAfterHeaders() { + return this[kState].endAfterHeaders; + } + get sentHeaders() { return this[kSentHeaders]; } diff --git a/test/parallel/test-http2-endafterheaders.js b/test/parallel/test-http2-endafterheaders.js new file mode 100644 index 0000000000..429ffc3188 --- /dev/null +++ b/test/parallel/test-http2-endafterheaders.js @@ -0,0 +1,50 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const http2 = require('http2'); +const Countdown = require('../common/countdown'); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream, headers) => { + const check = headers[':method'] === 'GET' ? true : false; + assert.strictEqual(stream.endAfterHeaders, check); + stream.on('data', common.mustNotCall()); + stream.on('end', common.mustCall()); + stream.respond(); + stream.end('ok'); +}, 2)); + +const countdown = new Countdown(2, () => server.close()); + +server.listen(0, common.mustCall(() => { + { + const client = http2.connect(`http://localhost:${server.address().port}`); + const req = client.request(); + + req.resume(); + req.on('response', common.mustCall(() => { + assert.strictEqual(req.endAfterHeaders, false); + })); + req.on('end', common.mustCall(() => { + client.close(); + countdown.dec(); + })); + } + { + const client = http2.connect(`http://localhost:${server.address().port}`); + const req = client.request({ ':method': 'POST' }); + + req.resume(); + req.end(); + req.on('response', common.mustCall(() => { + assert.strictEqual(req.endAfterHeaders, false); + })); + req.on('end', common.mustCall(() => { + client.close(); + countdown.dec(); + })); + } +})); |