Skip to content

Commit e45b6a3

Browse files
addaleaxBethGriggs
authored andcommittedSep 25, 2019
http2: do not start reading after write if new write is on wire
Don’t start reading more input data if we’re still busy writing output. This was overlooked in 8a4a193. Fixes: #29353 Fixes: #29393 PR-URL: #29399 Backport-PR-URL: #29618 Reviewed-By: David Carlier <devnexen@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 559a8e3 commit e45b6a3

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed
 

‎src/node_http2.cc

+5-1
Original file line numberDiff line numberDiff line change
@@ -791,8 +791,10 @@ void Http2Session::Close(uint32_t code, bool socket_closed) {
791791
flags_ |= SESSION_STATE_CLOSING;
792792

793793
// Stop reading on the i/o stream
794-
if (stream_ != nullptr)
794+
if (stream_ != nullptr) {
795+
flags_ |= SESSION_STATE_READING_STOPPED;
795796
stream_->ReadStop();
797+
}
796798

797799
// If the socket is not closed, then attempt to send a closing GOAWAY
798800
// frame. There is no guarantee that this GOAWAY will be received by
@@ -1280,6 +1282,7 @@ inline int Http2Session::OnDataChunkReceived(nghttp2_session* handle,
12801282
// If we are currently waiting for a write operation to finish, we should
12811283
// tell nghttp2 that we want to wait before we process more input data.
12821284
if (session->flags_ & SESSION_STATE_WRITE_IN_PROGRESS) {
1285+
CHECK_NE(session->flags_ & SESSION_STATE_READING_STOPPED, 0);
12831286
session->flags_ |= SESSION_STATE_NGHTTP2_RECV_PAUSED;
12841287
return NGHTTP2_ERR_PAUSE;
12851288
}
@@ -1626,6 +1629,7 @@ void Http2Session::OnStreamAfterWriteImpl(WriteWrap* w, int status, void* ctx) {
16261629
session->ClearOutgoing(status);
16271630

16281631
if ((session->flags_ & SESSION_STATE_READING_STOPPED) &&
1632+
!(session->flags_ & SESSION_STATE_WRITE_IN_PROGRESS) &&
16291633
nghttp2_session_want_read(session->session_)) {
16301634
session->flags_ &= ~SESSION_STATE_READING_STOPPED;
16311635
session->stream_->ReadStart();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
const fixtures = require('../common/fixtures');
6+
const http2 = require('http2');
7+
8+
// Regression test for https://github.com/nodejs/node/issues/29353.
9+
// Test that it’s okay for an HTTP2 + TLS server to destroy a stream instance
10+
// while reading it.
11+
12+
const server = http2.createSecureServer({
13+
key: fixtures.readKey('agent2-key.pem'),
14+
cert: fixtures.readKey('agent2-cert.pem')
15+
});
16+
17+
const filenames = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
18+
19+
server.on('stream', common.mustCall((stream) => {
20+
function write() {
21+
stream.write('a'.repeat(10240));
22+
stream.once('drain', write);
23+
}
24+
write();
25+
}, filenames.length));
26+
27+
server.listen(0, common.mustCall(() => {
28+
const client = http2.connect(`https://localhost:${server.address().port}`, {
29+
ca: fixtures.readKey('agent2-cert.pem'),
30+
servername: 'agent2'
31+
});
32+
33+
let destroyed = 0;
34+
for (const entry of filenames) {
35+
const stream = client.request({
36+
':path': `/${entry}`
37+
});
38+
stream.once('data', common.mustCall(() => {
39+
stream.destroy();
40+
41+
if (++destroyed === filenames.length) {
42+
client.destroy();
43+
server.close();
44+
}
45+
}));
46+
}
47+
}));

0 commit comments

Comments
 (0)
Please sign in to comment.