Skip to content

Commit

Permalink
stream: use Buffer.byteLength() to get the string length
Browse files Browse the repository at this point in the history
Use the byte length of the string when the `decodeStrings` option is set
to `false`.

Fixes: nodejs#52818
  • Loading branch information
lpinca committed May 4, 2024
1 parent 2c55652 commit 213539e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
22 changes: 14 additions & 8 deletions lib/internal/streams/writable.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ function _write(stream, chunk, encoding, cb) {
throw new ERR_STREAM_NULL_VALUES();
}

let length = 0;
if ((state[kState] & kObjectMode) === 0) {
if (!encoding) {
encoding = (state[kState] & kDefaultUTF8Encoding) !== 0 ? 'utf8' : state.defaultEncoding;
Expand All @@ -463,12 +464,17 @@ function _write(stream, chunk, encoding, cb) {
if (typeof chunk === 'string') {
if ((state[kState] & kDecodeStrings) !== 0) {
chunk = Buffer.from(chunk, encoding);
length = chunk.length;
encoding = 'buffer';
} else {
length = Buffer.byteLength(chunk, encoding);
}
} else if (chunk instanceof Buffer) {
length = chunk.length;
encoding = 'buffer';
} else if (Stream._isArrayBufferView(chunk)) {
chunk = Stream._uint8ArrayToBuffer(chunk);
length = chunk.length;
encoding = 'buffer';
} else {
throw new ERR_INVALID_ARG_TYPE(
Expand All @@ -490,7 +496,7 @@ function _write(stream, chunk, encoding, cb) {
}

state.pendingcb++;
return writeOrBuffer(stream, state, chunk, encoding, cb);
return writeOrBuffer(stream, state, chunk, length, encoding, cb);
}

Writable.prototype.write = function(chunk, encoding, cb) {
Expand Down Expand Up @@ -537,8 +543,8 @@ Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
// If we're already writing something, then just put this
// in the queue, and wait our turn. Otherwise, call _write
// If we return false, then we need a drain event, so set that flag.
function writeOrBuffer(stream, state, chunk, encoding, callback) {
const len = (state[kState] & kObjectMode) !== 0 ? 1 : chunk.length;
function writeOrBuffer(stream, state, chunk, length, encoding, callback) {
const len = (state[kState] & kObjectMode) !== 0 ? 1 : length;

state.length += len;

Expand All @@ -548,7 +554,7 @@ function writeOrBuffer(stream, state, chunk, encoding, callback) {
state[kBufferedValue] = [];
}

state[kBufferedValue].push({ chunk, encoding, callback });
state[kBufferedValue].push({ chunk, length, encoding, callback });
if ((state[kState] & kAllBuffers) !== 0 && encoding !== 'buffer') {
state[kState] &= ~kAllBuffers;
}
Expand Down Expand Up @@ -718,8 +724,8 @@ function errorBuffer(state) {

if ((state[kState] & kBuffered) !== 0) {
for (let n = state.bufferedIndex; n < state.buffered.length; ++n) {
const { chunk, callback } = state[kBufferedValue][n];
const len = (state[kState] & kObjectMode) !== 0 ? 1 : chunk.length;
const { length, callback } = state[kBufferedValue][n];
const len = (state[kState] & kObjectMode) !== 0 ? 1 : length;
state.length -= len;
callback(state.errored ?? new ERR_STREAM_DESTROYED('write'));
}
Expand Down Expand Up @@ -768,9 +774,9 @@ function clearBuffer(stream, state) {
resetBuffer(state);
} else {
do {
const { chunk, encoding, callback } = buffered[i];
const { chunk, length, encoding, callback } = buffered[i];
buffered[i++] = null;
const len = objectMode ? 1 : chunk.length;
const len = objectMode ? 1 : length;
doWrite(stream, state, false, len, chunk, encoding, callback);
} while (i < buffered.length && (state[kState] & kWriting) === 0);

Expand Down
22 changes: 22 additions & 0 deletions test/parallel/test-stream-writable-decoded-encoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,25 @@ class MyWritable extends stream.Writable {
m.write({ foo: 'bar' }, 'utf8');
m.end();
}

{
const w = new stream.Writable({
decodeStrings: false,
write() {}
});

w.write('€');

assert.strictEqual(w.writableLength, 3);
}

{
const w = new stream.Writable({
decodeStrings: false,
write() {}
});

w.write('aGVsbG8=', 'base64');

assert.strictEqual(w.writableLength, 5);
}

0 comments on commit 213539e

Please sign in to comment.