http: make OutgoingMessage more streamlike

Implement missing getters error & closed. Add support for
proper "writable" check through `isWritable` helper.

We cannot fix the `OutgoingMessage.writable` property as that
would break the ecosystem.

PR-URL: https://github.com/nodejs/node/pull/45672
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
Robert Nagy 2022-12-02 10:40:44 +01:00 committed by GitHub
parent 8541b3a4c0
commit d385106302
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 21 deletions

View File

@ -88,6 +88,7 @@ const kCorked = Symbol('corked');
const kUniqueHeaders = Symbol('kUniqueHeaders'); const kUniqueHeaders = Symbol('kUniqueHeaders');
const kBytesWritten = Symbol('kBytesWritten'); const kBytesWritten = Symbol('kBytesWritten');
const kEndCalled = Symbol('kEndCalled'); const kEndCalled = Symbol('kEndCalled');
const kErrored = Symbol('errored');
const nop = () => {}; const nop = () => {};
@ -147,10 +148,26 @@ function OutgoingMessage() {
this._keepAliveTimeout = 0; this._keepAliveTimeout = 0;
this._onPendingData = nop; this._onPendingData = nop;
this[kErrored] = null;
} }
ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype); ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype);
ObjectSetPrototypeOf(OutgoingMessage, Stream); ObjectSetPrototypeOf(OutgoingMessage, Stream);
ObjectDefineProperty(OutgoingMessage.prototype, 'errored', {
__proto__: null,
get() {
return this[kErrored];
},
});
ObjectDefineProperty(OutgoingMessage.prototype, 'closed', {
__proto__: null,
get() {
return this._closed;
},
});
ObjectDefineProperty(OutgoingMessage.prototype, 'writableFinished', { ObjectDefineProperty(OutgoingMessage.prototype, 'writableFinished', {
__proto__: null, __proto__: null,
get() { get() {
@ -320,6 +337,8 @@ OutgoingMessage.prototype.destroy = function destroy(error) {
} }
this.destroyed = true; this.destroyed = true;
this[kErrored] = error;
if (this.socket) { if (this.socket) {
this.socket.destroy(error); this.socket.destroy(error);
} else { } else {

View File

@ -20,6 +20,13 @@ server.listen(0, () => {
get({ get({
port: server.address().port port: server.address().port
}, common.mustCall((res) => { }, common.mustCall((res) => {
res.destroy(new Error('Destroy test')); const err = new Error('Destroy test');
assert.strictEqual(res.errored, null);
res.destroy(err);
assert.strictEqual(res.closed, false);
assert.strictEqual(res.errored, err);
res.on('close', () => {
assert.strictEqual(res.closed, true);
});
})); }));
}); });

View File

@ -1,24 +1,55 @@
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
const http = require('http'); const http = require('http');
const assert = require('assert');
const server = http.createServer(common.mustCall((req, res) => { {
req.pipe(res); const server = http.createServer(common.mustCall((req, res) => {
res.on('error', common.mustNotCall()); assert.strictEqual(res.closed, false);
res.on('close', common.mustCall(() => { req.pipe(res);
res.end('asd'); res.on('error', common.mustNotCall());
process.nextTick(() => { res.on('close', common.mustCall(() => {
server.close(); assert.strictEqual(res.closed, true);
}); res.end('asd');
})); process.nextTick(() => {
})).listen(0, () => { server.close();
http });
.request({ }));
port: server.address().port, })).listen(0, () => {
method: 'PUT' http
}) .request({
.on('response', (res) => { port: server.address().port,
res.destroy(); method: 'PUT'
}) })
.write('asd'); .on('response', (res) => {
}); res.destroy();
})
.write('asd');
});
}
{
const server = http.createServer(common.mustCall((req, res) => {
assert.strictEqual(res.closed, false);
req.pipe(res);
res.on('error', common.mustNotCall());
res.on('close', common.mustCall(() => {
assert.strictEqual(res.closed, true);
process.nextTick(() => {
server.close();
});
}));
const err = new Error('Destroy test');
res.destroy(err);
assert.strictEqual(res.errored, err);
})).listen(0, () => {
http
.request({
port: server.address().port,
method: 'PUT'
})
.on('error', common.mustCall())
.write('asd');
});
}