Skip to content

Commit e4ea031

Browse files
committed
http: added closed property
1 parent c1f0cbe commit e4ea031

10 files changed

+72
-14
lines changed

doc/api/http.md

+18
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,15 @@ changes:
553553
The `request.aborted` property will be `true` if the request has
554554
been aborted.
555555

556+
### request.closed
557+
<!-- YAML
558+
added: CHANGEME
559+
-->
560+
561+
* {boolean}
562+
563+
The `request.closed` property indicates whether the request has been closed.
564+
556565
### request.connection
557566
<!-- YAML
558567
added: v0.3.0
@@ -1130,6 +1139,15 @@ response.end();
11301139
Attempting to set a header field name or value that contains invalid characters
11311140
will result in a [`TypeError`][] being thrown.
11321141

1142+
### response.closed
1143+
<!-- YAML
1144+
added: CHANGEME
1145+
-->
1146+
1147+
* {boolean}
1148+
1149+
The `response.closed` property indicates whether the response has been closed.
1150+
11331151
### response.connection
11341152
<!-- YAML
11351153
added: v0.3.0

lib/_http_client.js

+11-6
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ function ClientRequest(input, options, cb) {
191191
this._ended = false;
192192
this.res = null;
193193
this.aborted = false;
194+
this.closed = false;
194195
this.timeoutCb = null;
195196
this.upgradeOrConnect = false;
196197
this.parser = null;
@@ -358,14 +359,12 @@ function socketCloseListener() {
358359
res.aborted = true;
359360
res.emit('aborted');
360361
}
361-
req.emit('close');
362+
emitClose.call(req);
362363
if (res.readable) {
363-
res.on('end', function() {
364-
this.emit('close');
365-
});
364+
res.on('end', emitClose);
366365
res.push(null);
367366
} else {
368-
res.emit('close');
367+
emitClose.call(res);
369368
}
370369
} else {
371370
if (!req.socket._hadError) {
@@ -375,7 +374,7 @@ function socketCloseListener() {
375374
req.socket._hadError = true;
376375
req.emit('error', connResetException('socket hang up'));
377376
}
378-
req.emit('close');
377+
emitClose.call(req);
379378
}
380379

381380
// Too bad. That output wasn't getting written.
@@ -417,6 +416,11 @@ function socketErrorListener(err) {
417416
socket.destroy();
418417
}
419418

419+
function emitClose() {
420+
this.closed = true;
421+
this.emit('close');
422+
}
423+
420424
function freeSocketErrorListener(err) {
421425
const socket = this;
422426
debug('SOCKET ERROR on FREE socket:', err.message, err.stack);
@@ -487,6 +491,7 @@ function socketOnData(d) {
487491
socket.readableFlowing = null;
488492

489493
req.emit(eventName, res, socket, bodyHead);
494+
req.closed = true;
490495
req.emit('close');
491496
} else {
492497
// Requested Upgrade or used CONNECT method, but have no handler.

lib/_http_incoming.js

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ function IncomingMessage(socket) {
5656
this.readable = true;
5757

5858
this.aborted = false;
59+
this.closed = false;
5960

6061
this.upgrade = null;
6162

lib/_http_outgoing.js

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ function OutgoingMessage() {
9696
this._trailer = '';
9797

9898
this.finished = false;
99+
this.closed = false;
99100
this._headerSent = false;
100101
this[kIsCorked] = false;
101102

lib/_http_server.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,9 @@ function onServerResponseClose() {
178178
// Ergo, we need to deal with stale 'close' events and handle the case
179179
// where the ServerResponse object has already been deconstructed.
180180
// Fortunately, that requires only a single if check. :-)
181-
if (this._httpMessage) this._httpMessage.emit('close');
181+
if (this._httpMessage) {
182+
emitClose.call(this._httpMessage);
183+
}
182184
}
183185

184186
ServerResponse.prototype.assignSocket = function assignSocket(socket) {
@@ -469,7 +471,7 @@ function abortIncoming(incoming) {
469471
var req = incoming.shift();
470472
req.aborted = true;
471473
req.emit('aborted');
472-
req.emit('close');
474+
emitClose.call(req);
473475
}
474476
// Abort socket._httpMessage ?
475477
}
@@ -594,6 +596,11 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) {
594596
}
595597
}
596598

599+
function emitClose() {
600+
this.closed = true;
601+
this.emit('close');
602+
}
603+
597604
function resOnFinish(req, res, socket, state, server) {
598605
// Usually the first incoming element should be our request. it may
599606
// be that in the case abortIncoming() was called that the incoming
@@ -609,7 +616,8 @@ function resOnFinish(req, res, socket, state, server) {
609616
req._dump();
610617

611618
res.detachSocket(socket);
612-
req.emit('close');
619+
res.closed = true;
620+
emitClose.call(req);
613621
process.nextTick(emitCloseNT, res);
614622

615623
if (res._last) {

lib/internal/http2/compat.js

+8
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ class Http2ServerRequest extends Readable {
297297
this.on('resume', onRequestResume);
298298
}
299299

300+
get closed() {
301+
return this[kState].closed;
302+
}
303+
300304
get aborted() {
301305
return this[kAborted];
302306
}
@@ -446,6 +450,10 @@ class Http2ServerResponse extends Stream {
446450
stream.on('timeout', onStreamTimeout(kResponse));
447451
}
448452

453+
get closed() {
454+
return this[kState].closed;
455+
}
456+
449457
// User land modules such as finalhandler just check truthiness of this
450458
// but if someone is actually trying to use this for more than that
451459
// then we simply can't support such use cases

test/parallel/test-http-client-close-event.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ server.listen(0, common.mustCall(() => {
2323

2424
req.on('close', common.mustCall(() => {
2525
assert.strictEqual(errorEmitted, true);
26+
assert.strictEqual(req.closed, true);
2627
server.close();
2728
}));
2829

test/parallel/test-http-connect-req-res.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,14 @@ server.listen(0, common.mustCall(function() {
3333
path: 'example.com:443'
3434
}, common.mustNotCall());
3535

36-
req.on('close', common.mustCall());
36+
assert.strictEqual(req.closed, false);
37+
req.on('close', common.mustCall(() => {
38+
assert.strictEqual(req.closed, true);
39+
}));
3740

3841
req.on('connect', common.mustCall(function(res, socket, firstBodyChunk) {
42+
assert.strictEqual(req.closed, false);
43+
3944
console.error('Client got CONNECT request');
4045

4146
// Make sure this request got removed from the pool.
@@ -54,10 +59,20 @@ server.listen(0, common.mustCall(function() {
5459
// Test that the firstBodyChunk was not parsed as HTTP
5560
assert.strictEqual(data, 'Head');
5661

62+
let closeEmitted = false;
63+
64+
req.on('close', common.mustCall(() => {
65+
closeEmitted = true;
66+
}));
67+
5768
socket.on('data', function(buf) {
69+
assert.strictEqual(req.closed, true); // TODO: This should be false
70+
assert.strictEqual(closeEmitted, true); // TODO: This should be false
5871
data += buf.toString();
5972
});
6073
socket.on('end', function() {
74+
assert.strictEqual(req.closed, true); // TODO: This should be false
75+
assert.strictEqual(closeEmitted, true); // TODO: This should be false
6176
assert.strictEqual(data, 'HeadRequestEnd');
6277
server.close();
6378
});

test/parallel/test-http-req-res-close.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@ const http = require('http');
55
const assert = require('assert');
66

77
const server = http.Server(common.mustCall((req, res) => {
8-
let resClosed = false;
9-
108
res.end();
119
res.on('finish', common.mustCall(() => {
12-
assert.strictEqual(resClosed, false);
10+
assert.strictEqual(res.closed, false);
1311
}));
1412
res.on('close', common.mustCall(() => {
15-
resClosed = true;
13+
assert.strictEqual(res.closed, true);
1614
}));
1715
req.on('close', common.mustCall(() => {
16+
assert.strictEqual(req.closed, true);
1817
assert.strictEqual(req._readableState.ended, true);
1918
}));
2019
res.socket.on('close', () => server.close());

test/parallel/test-http-response-close.js

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
'use strict';
2323
const common = require('../common');
2424
const http = require('http');
25+
const assert = require('assert');
2526

2627
{
2728
const server = http.createServer(
@@ -40,6 +41,7 @@ const http = require('http');
4041
res.destroy();
4142
}));
4243
res.on('close', common.mustCall(() => {
44+
assert.strictEqual(res.closed, true);
4345
server.close();
4446
}));
4547
})

0 commit comments

Comments
 (0)