From 5f41f1b19eed83d78b0d2a57bff0d3e5d84e86db Mon Sep 17 00:00:00 2001 From: David Halls Date: Mon, 23 Nov 2020 23:35:04 +0000 Subject: [PATCH] http2: check write not scheduled in scope destructor Fixes: https://github.com/nodejs/node/issues/33156 PR-URL: https://github.com/nodejs/node/pull/36241 Reviewed-By: Matteo Collina Reviewed-By: Rich Trott --- src/node_http2.cc | 3 +- .../test-http2-close-while-writing.js | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-http2-close-while-writing.js diff --git a/src/node_http2.cc b/src/node_http2.cc index 776393de8f800a..1e2da918bf5b69 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -88,7 +88,8 @@ Http2Scope::Http2Scope(Http2Session* session) : session_(session) { Http2Scope::~Http2Scope() { if (!session_) return; session_->set_in_scope(false); - session_->MaybeScheduleWrite(); + if (!session_->is_write_scheduled()) + session_->MaybeScheduleWrite(); } // The Http2Options object is used during the construction of Http2Session diff --git a/test/parallel/test-http2-close-while-writing.js b/test/parallel/test-http2-close-while-writing.js new file mode 100644 index 00000000000000..d8537c31b00eb6 --- /dev/null +++ b/test/parallel/test-http2-close-while-writing.js @@ -0,0 +1,46 @@ +'use strict'; +// https://github.com/nodejs/node/issues/33156 +const common = require('../common'); +const fixtures = require('../common/fixtures'); + +if (!common.hasCrypto) { + common.skip('missing crypto'); +} + +const http2 = require('http2'); + +const key = fixtures.readKey('agent8-key.pem', 'binary'); +const cert = fixtures.readKey('agent8-cert.pem', 'binary'); +const ca = fixtures.readKey('fake-startcom-root-cert.pem', 'binary'); + +const server = http2.createSecureServer({ + key, + cert, + maxSessionMemory: 1000 +}); + +let client_stream; + +server.on('session', common.mustCall(function(session) { + session.on('stream', common.mustCall(function(stream) { + stream.resume(); + stream.on('data', function() { + this.write(Buffer.alloc(1)); + process.nextTick(() => client_stream.destroy()); + }); + })); +})); + +server.listen(0, function() { + const client = http2.connect(`https://localhost:${server.address().port}`, { + ca, + maxSessionMemory: 1000 + }); + client_stream = client.request({ ':method': 'POST' }); + client_stream.on('close', common.mustCall(() => { + client.close(); + server.close(); + })); + client_stream.resume(); + client_stream.write(Buffer.alloc(64 * 1024)); +});