Skip to content

Commit 2ea2725

Browse files
apapirovskijasnell
authored andcommitted
http2: emit close event if request aborted
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 <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent f0e411d commit 2ea2725

File tree

2 files changed

+51
-2
lines changed

2 files changed

+51
-2
lines changed

lib/internal/http2/compat.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,17 @@ function onStreamClosedResponse() {
116116
res.emit('finish');
117117
}
118118

119-
function onAborted(hadError, code) {
119+
function onStreamAbortedRequest(hadError, code) {
120120
if ((this.writable) ||
121121
(this._readableState && !this._readableState.ended)) {
122122
this.emit('aborted', hadError, code);
123+
this.emit('close');
124+
}
125+
}
126+
127+
function onStreamAbortedResponse() {
128+
if (this.writable) {
129+
this.emit('close');
123130
}
124131
}
125132

@@ -145,7 +152,7 @@ class Http2ServerRequest extends Readable {
145152
stream.on('end', onStreamEnd);
146153
stream.on('error', onStreamError);
147154
stream.on('close', onStreamClosedRequest);
148-
stream.on('aborted', onAborted.bind(this));
155+
stream.on('aborted', onStreamAbortedRequest.bind(this));
149156
const onfinish = this[kFinish].bind(this);
150157
stream.on('streamClosed', onfinish);
151158
stream.on('finish', onfinish);
@@ -294,6 +301,7 @@ class Http2ServerResponse extends Stream {
294301
this.writable = true;
295302
stream.on('drain', onStreamResponseDrain);
296303
stream.on('close', onStreamClosedResponse);
304+
stream.on('aborted', onStreamAbortedResponse.bind(this));
297305
const onfinish = this[kFinish].bind(this);
298306
stream.on('streamClosed', onfinish);
299307
stream.on('finish', onfinish);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Flags: --expose-http2 --expose-internals
2+
'use strict';
3+
4+
const common = require('../common');
5+
if (!common.hasCrypto)
6+
common.skip('missing crypto');
7+
const h2 = require('http2');
8+
9+
// Server request and response should receive close event
10+
// if the connection was terminated before response.end
11+
// could be called or flushed
12+
13+
const server = h2.createServer(common.mustCall((req, res) => {
14+
res.writeHead(200);
15+
res.write('a');
16+
17+
req.on('close', common.mustCall());
18+
res.on('close', common.mustCall());
19+
}));
20+
server.listen(0);
21+
22+
server.on('listening', function() {
23+
const port = server.address().port;
24+
25+
const url = `http://localhost:${port}`;
26+
const client = h2.connect(url, common.mustCall(function() {
27+
const headers = {
28+
':path': '/foobar',
29+
':method': 'GET',
30+
':scheme': 'http',
31+
':authority': `localhost:${port}`,
32+
};
33+
const request = client.request(headers);
34+
request.on('data', common.mustCall(function(chunk) {
35+
// cause an error on the server side
36+
client.destroy();
37+
server.close();
38+
}));
39+
request.end();
40+
}));
41+
});

0 commit comments

Comments
 (0)