summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-09-02 01:32:15 +0200
committerAnna Henningsen <anna@addaleax.net>2019-09-04 17:15:24 +0200
commit18cb4372d1fccb58580f82a58649454032774832 (patch)
treee117fdbb638e03d30c375ff4f208691ca49f0e10
parenta3307eac0e6fb276274e4e9bbaab1aa4433e795f (diff)
downloadandroid-node-v8-18cb4372d1fccb58580f82a58649454032774832.tar.gz
android-node-v8-18cb4372d1fccb58580f82a58649454032774832.tar.bz2
android-node-v8-18cb4372d1fccb58580f82a58649454032774832.zip
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 8a4a1931b8b98. Fixes: https://github.com/nodejs/node/issues/29353 Fixes: https://github.com/nodejs/node/issues/29393 PR-URL: https://github.com/nodejs/node/pull/29399 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>
-rw-r--r--src/node_http2.cc6
-rw-r--r--test/parallel/test-http2-multistream-destroy-on-read-tls.js47
2 files changed, 52 insertions, 1 deletions
diff --git a/src/node_http2.cc b/src/node_http2.cc
index 1065a940f5..a5b834dc2c 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -742,8 +742,10 @@ void Http2Session::Close(uint32_t code, bool socket_closed) {
flags_ |= SESSION_STATE_CLOSING;
// Stop reading on the i/o stream
- if (stream_ != nullptr)
+ if (stream_ != nullptr) {
+ flags_ |= SESSION_STATE_READING_STOPPED;
stream_->ReadStop();
+ }
// If the socket is not closed, then attempt to send a closing GOAWAY
// frame. There is no guarantee that this GOAWAY will be received by
@@ -1192,6 +1194,7 @@ int Http2Session::OnDataChunkReceived(nghttp2_session* handle,
// If we are currently waiting for a write operation to finish, we should
// tell nghttp2 that we want to wait before we process more input data.
if (session->flags_ & SESSION_STATE_WRITE_IN_PROGRESS) {
+ CHECK_NE(session->flags_ & SESSION_STATE_READING_STOPPED, 0);
session->flags_ |= SESSION_STATE_NGHTTP2_RECV_PAUSED;
return NGHTTP2_ERR_PAUSE;
}
@@ -1546,6 +1549,7 @@ void Http2Session::OnStreamAfterWrite(WriteWrap* w, int status) {
ClearOutgoing(status);
if ((flags_ & SESSION_STATE_READING_STOPPED) &&
+ !(flags_ & SESSION_STATE_WRITE_IN_PROGRESS) &&
nghttp2_session_want_read(session_)) {
flags_ &= ~SESSION_STATE_READING_STOPPED;
stream_->ReadStart();
diff --git a/test/parallel/test-http2-multistream-destroy-on-read-tls.js b/test/parallel/test-http2-multistream-destroy-on-read-tls.js
new file mode 100644
index 0000000000..91cbec6b2d
--- /dev/null
+++ b/test/parallel/test-http2-multistream-destroy-on-read-tls.js
@@ -0,0 +1,47 @@
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+const fixtures = require('../common/fixtures');
+const http2 = require('http2');
+
+// Regression test for https://github.com/nodejs/node/issues/29353.
+// Test that it’s okay for an HTTP2 + TLS server to destroy a stream instance
+// while reading it.
+
+const server = http2.createSecureServer({
+ key: fixtures.readKey('agent2-key.pem'),
+ cert: fixtures.readKey('agent2-cert.pem')
+});
+
+const filenames = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
+
+server.on('stream', common.mustCall((stream) => {
+ function write() {
+ stream.write('a'.repeat(10240));
+ stream.once('drain', write);
+ }
+ write();
+}, filenames.length));
+
+server.listen(0, common.mustCall(() => {
+ const client = http2.connect(`https://localhost:${server.address().port}`, {
+ ca: fixtures.readKey('agent2-cert.pem'),
+ servername: 'agent2'
+ });
+
+ let destroyed = 0;
+ for (const entry of filenames) {
+ const stream = client.request({
+ ':path': `/${entry}`
+ });
+ stream.once('data', common.mustCall(() => {
+ stream.destroy();
+
+ if (++destroyed === filenames.length) {
+ client.destroy();
+ server.close();
+ }
+ }));
+ }
+}));