diff --git a/lib/internal/http2/compat.js b/lib/internal/http2/compat.js index fa565e9bd67386..6a5fc40da18f95 100644 --- a/lib/internal/http2/compat.js +++ b/lib/internal/http2/compat.js @@ -116,10 +116,17 @@ function onStreamClosedResponse() { res.emit('finish'); } -function onAborted(hadError, code) { +function onStreamAbortedRequest(hadError, code) { if ((this.writable) || (this._readableState && !this._readableState.ended)) { this.emit('aborted', hadError, code); + this.emit('close'); + } +} + +function onStreamAbortedResponse() { + if (this.writable) { + this.emit('close'); } } @@ -145,7 +152,7 @@ class Http2ServerRequest extends Readable { stream.on('end', onStreamEnd); stream.on('error', onStreamError); stream.on('close', onStreamClosedRequest); - stream.on('aborted', onAborted.bind(this)); + stream.on('aborted', onStreamAbortedRequest.bind(this)); const onfinish = this[kFinish].bind(this); stream.on('streamClosed', onfinish); stream.on('finish', onfinish); @@ -294,6 +301,7 @@ class Http2ServerResponse extends Stream { this.writable = true; stream.on('drain', onStreamResponseDrain); stream.on('close', onStreamClosedResponse); + stream.on('aborted', onStreamAbortedResponse.bind(this)); const onfinish = this[kFinish].bind(this); stream.on('streamClosed', onfinish); stream.on('finish', onfinish); diff --git a/test/parallel/test-http2-compat-serverresponse-close.js b/test/parallel/test-http2-compat-serverresponse-close.js new file mode 100644 index 00000000000000..9b42ae05dc24b4 --- /dev/null +++ b/test/parallel/test-http2-compat-serverresponse-close.js @@ -0,0 +1,41 @@ +// Flags: --expose-http2 --expose-internals +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const h2 = require('http2'); + +// Server request and response should receive close event +// if the connection was terminated before response.end +// could be called or flushed + +const server = h2.createServer(common.mustCall((req, res) => { + res.writeHead(200); + res.write('a'); + + req.on('close', common.mustCall()); + res.on('close', common.mustCall()); +})); +server.listen(0); + +server.on('listening', function() { + const port = server.address().port; + + const url = `http://localhost:${port}`; + const client = h2.connect(url, common.mustCall(function() { + const headers = { + ':path': '/foobar', + ':method': 'GET', + ':scheme': 'http', + ':authority': `localhost:${port}`, + }; + const request = client.request(headers); + request.on('data', common.mustCall(function(chunk) { + // cause an error on the server side + client.destroy(); + server.close(); + })); + request.end(); + })); +});