stream: use more accurate end-of-stream writable and readable detection

The value of stream.readable and stream.writable should not
be used to detect whether a stream is Writable or Readable.

Refs: https://github.com/nodejs/node/issues/29395
PR-URL: https://github.com/nodejs/node/pull/29409
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Robert Nagy 2019-09-02 17:30:56 +02:00 committed by Rich Trott
parent 872d803faf
commit 8709a408d2
2 changed files with 64 additions and 2 deletions

View File

@ -13,6 +13,18 @@ function isRequest(stream) {
return stream.setHeader && typeof stream.abort === 'function'; return stream.setHeader && typeof stream.abort === 'function';
} }
function isReadable(stream) {
return typeof stream.readable === 'boolean' ||
typeof stream.readableEnded === 'boolean' ||
!!stream._readableState;
}
function isWritable(stream) {
return typeof stream.writable === 'boolean' ||
typeof stream.writableEnded === 'boolean' ||
!!stream._writableState;
}
function eos(stream, opts, callback) { function eos(stream, opts, callback) {
if (arguments.length === 2) { if (arguments.length === 2) {
callback = opts; callback = opts;
@ -47,8 +59,10 @@ function eos(stream, opts, callback) {
}; };
} }
let readable = opts.readable || (opts.readable !== false && stream.readable); let readable = opts.readable ||
let writable = opts.writable || (opts.writable !== false && stream.writable); (opts.readable !== false && isReadable(stream));
let writable = opts.writable ||
(opts.writable !== false && isWritable(stream));
const onlegacyfinish = () => { const onlegacyfinish = () => {
if (!stream.writable) onfinish(); if (!stream.writable) onfinish();

View File

@ -318,3 +318,51 @@ const { promisify } = require('util');
})); }));
r.destroy(); r.destroy();
} }
{
// Test is readable check through readable
const streamLike = new EE();
streamLike.readable = false;
finished(streamLike, common.mustCall());
streamLike.emit('end');
}
{
// Test is readable check through readableEnded
const streamLike = new EE();
streamLike.readableEnded = true;
finished(streamLike, common.mustCall());
streamLike.emit('end');
}
{
// Test is readable check through _readableState
const streamLike = new EE();
streamLike._readableState = {};
finished(streamLike, common.mustCall());
streamLike.emit('end');
}
{
// Test is writable check through writable
const streamLike = new EE();
streamLike.writable = false;
finished(streamLike, common.mustCall());
streamLike.emit('finish');
}
{
// Test is writable check through writableEnded
const streamLike = new EE();
streamLike.writableEnded = true;
finished(streamLike, common.mustCall());
streamLike.emit('finish');
}
{
// Test is writable check through _writableState
const streamLike = new EE();
streamLike._writableState = {};
finished(streamLike, common.mustCall());
streamLike.emit('finish');
}