Skip to content

Commit

Permalink
http2: emit close event if request aborted
Browse files Browse the repository at this point in the history
Fix Http2ServerRequest and Http2ServerResponse to emit close event
if the request is aborted before response.end can be called.

Fixes: #15385
PR-URL: #15415
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
apapirovski authored and jasnell committed Sep 20, 2017
1 parent f0e411d commit 2ea2725
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 2 deletions.
12 changes: 10 additions & 2 deletions lib/internal/http2/compat.js
Expand Up @@ -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');
}
}

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
41 changes: 41 additions & 0 deletions 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();
}));
});

0 comments on commit 2ea2725

Please sign in to comment.