http2: fix end without read · nodejs/node@b2fb1d7 · GitHub
Skip to content

Commit b2fb1d7

Browse files
apapirovskiMylesBorins
authored andcommitted
http2: fix end without read
Adjust http2 behaviour to allow ending a stream even after some data comes in (when the user has no intention of reading that data). Also correctly end a stream when trailers are present. PR-URL: #20621 Fixes: #20060 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
1 parent 9e432ca commit b2fb1d7

4 files changed

Lines changed: 66 additions & 15 deletions

File tree

lib/internal/http2/compat.js

Lines changed: 6 additions & 4 deletions

lib/internal/http2/core.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,11 @@ function onStreamClose(code) {
349349
// Push a null so the stream can end whenever the client consumes
350350
// it completely.
351351
stream.push(null);
352-
353-
// Same as net.
354-
if (stream.readableLength === 0) {
355-
stream.read(0);
356-
}
352+
// If the client hasn't tried to consume the stream and there is no
353+
// resume scheduled (which would indicate they would consume in the future),
354+
// then just dump the incoming data so that the stream can be destroyed.
355+
if (!stream[kState].didRead && !stream._readableState.resumeScheduled)
356+
stream.resume();
357357
}
358358
}
359359

@@ -1795,6 +1795,8 @@ class Http2Stream extends Duplex {
17951795
const ret = this[kHandle].trailers(headersList);
17961796
if (ret < 0)
17971797
this.destroy(new NghttpError(ret));
1798+
else
1799+
this[kMaybeDestroy]();
17981800
}
17991801

18001802
get closed() {

test/parallel/test-http2-client-upload-reject.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ fs.readFile(loc, common.mustCall((err, data) => {
2020
const server = http2.createServer();
2121

2222
server.on('stream', common.mustCall((stream) => {
23-
stream.on('close', common.mustCall(() => {
24-
assert.strictEqual(stream.rstCode, 0);
25-
}));
26-
27-
stream.respond({ ':status': 400 });
28-
stream.end();
23+
// Wait for some data to come through.
24+
setImmediate(() => {
25+
stream.on('close', common.mustCall(() => {
26+
assert.strictEqual(stream.rstCode, 0);
27+
}));
28+
29+
stream.respond({ ':status': 400 });
30+
stream.end();
31+
});
2932
}));
3033

3134
server.listen(0, common.mustCall(() => {
Lines changed: 44 additions & 0 deletions

0 commit comments

Comments
 (0)