Description
Version
v19.4.0
Platform
Microsoft Windows NT 10.0.22000.0 x64
Subsystem
node:stream
What steps will reproduce the bug?
Create a new stream.Writeable
and supply an invalid encoding for defaultEncoding
. It will accept the encoding just fine, which can lead to some strange side effects.
For a very quick test, just to show that it does not validate it:
new (require('node:stream').Writable)({defaultEncoding: 'some invalid encoding'});
For a more complete test that shows more of its effects:
const stream = require('node:stream');
console.log('stream 1');
const s1 = new stream.Writable({
defaultEncoding: 'my invalid encoding',
write(chunk, enc, cb) {
console.log('dat', chunk);
console.log('enc', enc);
cb();
}
});
// output:
//TypeError: Unknown encoding: my invalid encoding
//...
try {
s1.write('test data');
} catch (err) {
console.error(err);
}
/* ============================== */
console.log('\nstream 2');
const s2 = new stream.Writable({
defaultEncoding: 'my invalid encoding',
decodeStrings: false,
write(chunk, enc, cb) {
console.log('dat', chunk);
console.log('enc', enc);
cb();
}
});
// output:
//dat test data
//enc my invalid encoding
s2.write('test data');
/* ============================== */
console.log('\nstream 3');
const s3 = new stream.Writable({
defaultEncoding: {an: 'object'},
write(chunk, enc, cb) {
console.log('dat', chunk);
console.log('enc', enc);
cb();
}
});
// output:
//dat <Buffer 74 65 73 74 20 64 61 74 61>
//enc buffer
s3.write('test data');
/* ============================== */
console.log('\nstream 4');
const s4 = new stream.Transform({
defaultEncoding: 'my invalid encoding',
transform(chunk, enc, cb) {
console.log('dat', chunk);
console.log('enc', enc);
cb(chunk);
}
});
// output:
//TypeError: Unknown encoding: my invalid encoding
//...
try {
s4.write('test data');
} catch (err) {
console.error(err);
}
/* ============================== */
console.log('\nnode:crypto test');
console.log('crypto.createCipheriv');
const crypto = require('node:crypto');
const encrypt = crypto.createCipheriv('aes-128-gcm', crypto.randomBytes(16), crypto.randomBytes(16), {defaultEncoding: 'an invalid encoding'});
encrypt.on('data', (chunk) => {
console.log('data received', chunk);
});
encrypt.write('some more data');
encrypt.end();
How often does it reproduce? Is there a required condition?
As far as I can tell, it always reproduces.
What is the expected behavior?
I would expect the stream.Writeable
constructor to validate the defaultEncoding
option and throw an error if it is invalid.
It still can throw an error with a call to writeable.write
if objectMode
is false, decodeStrings
is true, the chunk
is a string, and no encoding is specified in the write call. Weirdly enough, it doesn't throw an error if the defaultEncoding
is something other than a string, like a number or object, and converts the string provided in the write call to a buffer anyway.
const stream = require('node:stream');
// would expect an error
new stream.Writable({defaultEncoding: 'some invalid encoding'});
// would very much expect an error
new stream.Writable({defaultEncoding: 42}).write('a string');
const s = new stream.Writeable();
// throws an error, which is exactly what I would expect
s.setDefaultEncoding('some invalid encoding');
// also throws an error (expected)
s.write('a string', 42);
What do you see instead?
It does not validate invalid default encodings in the constructor, and only throws an error if the invalid default encoding is used (such as if a string is provided in a write call with no other encoding specified).
Additional information
Trying a similar thing with stream.Readable
throws an error instead.
// throws an error (which is expected)
new (require('node:stream').Readable)({encoding: 'some invalid encoding'});