diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 2b63284b825ee8..7d090897b2a4c0 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -136,26 +136,33 @@ function readableAddChunk(stream, state, chunk, encoding, addToFront) { const e = new Error('stream.unshift() after end event'); stream.emit('error', e); } else { - if (state.decoder && !addToFront && !encoding) + var skipAdd; + if (state.decoder && !addToFront && !encoding) { chunk = state.decoder.write(chunk); + skipAdd = (!state.objectMode && chunk.length === 0); + } if (!addToFront) state.reading = false; - // if we want the data now, just emit it. - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); - } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) - state.buffer.unshift(chunk); - else - state.buffer.push(chunk); - - if (state.needReadable) - emitReadable(stream); + // Don't add to the buffer if we've decoded to an empty string chunk and + // we're not in object mode + if (!skipAdd) { + // if we want the data now, just emit it. + if (state.flowing && state.length === 0 && !state.sync) { + stream.emit('data', chunk); + stream.read(0); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) + state.buffer.unshift(chunk); + else + state.buffer.push(chunk); + + if (state.needReadable) + emitReadable(stream); + } } maybeReadMore(stream, state); diff --git a/test/parallel/test-stream2-decode-partial.js b/test/parallel/test-stream2-decode-partial.js new file mode 100644 index 00000000000000..b58e192b9c33bb --- /dev/null +++ b/test/parallel/test-stream2-decode-partial.js @@ -0,0 +1,23 @@ +'use strict'; +require('../common'); +const Readable = require('_stream_readable'); +const assert = require('assert'); + +var buf = ''; +const euro = new Buffer([0xE2, 0x82, 0xAC]); +const cent = new Buffer([0xC2, 0xA2]); +const source = Buffer.concat([euro, cent]); + +const readable = Readable({ encoding: 'utf8' }); +readable.push(source.slice(0, 2)); +readable.push(source.slice(2, 4)); +readable.push(source.slice(4, 6)); +readable.push(null); + +readable.on('data', function(data) { + buf += data; +}); + +process.on('exit', function() { + assert.strictEqual(buf, '€¢'); +});