diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js index 3800399c82ad62..b5acb3e6c24c7e 100644 --- a/lib/internal/streams/readable.js +++ b/lib/internal/streams/readable.js @@ -102,6 +102,8 @@ const kErroredValue = Symbol('kErroredValue'); const kDefaultEncodingValue = Symbol('kDefaultEncodingValue'); const kDecoderValue = Symbol('kDecoderValue'); const kEncodingValue = Symbol('kEncodingValue'); +const kBuffer = Symbol('kBuffer'); +const kBufferIndex = Symbol('kBufferIndex'); const kEnded = 1 << 9; const kEndEmitted = 1 << 10; @@ -276,8 +278,8 @@ function ReadableState(options, stream, isDuplex) { getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex) : getDefaultHighWaterMark(false); - this.buffer = []; - this.bufferIndex = 0; + this[kBuffer] = []; + this[kBufferIndex] = 0; this.length = 0; this.pipes = []; @@ -561,13 +563,13 @@ function addChunk(stream, state, chunk, addToFront) { // Update the buffer info. state.length += (state[kState] & kObjectMode) !== 0 ? 1 : chunk.length; if (addToFront) { - if (state.bufferIndex > 0) { - state.buffer[--state.bufferIndex] = chunk; + if (state[kBufferIndex] > 0) { + state[kBuffer][--state[kBufferIndex]] = chunk; } else { - state.buffer.unshift(chunk); // Slow path + state[kBuffer].unshift(chunk); // Slow path } } else { - state.buffer.push(chunk); + state[kBuffer].push(chunk); } if ((state[kState] & kNeedReadable) !== 0) @@ -592,14 +594,14 @@ Readable.prototype.setEncoding = function(enc) { // Iterate over current buffer to convert already stored Buffers: let content = ''; - for (const data of state.buffer.slice(state.bufferIndex)) { + for (const data of state[kBuffer].slice(state[kBufferIndex])) { content += decoder.write(data); } - state.buffer.length = 0; - state.bufferIndex = 0; + state[kBuffer].length = 0; + state[kBufferIndex] = 0; if (content !== '') - state.buffer.push(content); + state[kBuffer].push(content); state.length = content.length; return this; }; @@ -633,7 +635,7 @@ function howMuchToRead(n, state) { if (NumberIsNaN(n)) { // Only flow one buffer at a time. if ((state[kState] & kFlowing) !== 0 && state.length) - return state.buffer[state.bufferIndex].length; + return state[kBuffer][state[kBufferIndex]].length; return state.length; } if (n <= state.length) @@ -790,7 +792,7 @@ function onEofChunk(stream, state) { if (decoder) { const chunk = decoder.end(); if (chunk && chunk.length) { - state.buffer.push(chunk); + state[kBuffer].push(chunk); state.length += (state[kState] & kObjectMode) !== 0 ? 1 : chunk.length; } } @@ -1459,7 +1461,7 @@ ObjectDefineProperties(Readable.prototype, { __proto__: null, enumerable: false, get: function() { - return this._readableState && this._readableState.buffer; + return this._readableState && this._readableState[kBuffer]; }, }, @@ -1541,9 +1543,15 @@ ObjectDefineProperties(Readable.prototype, { return this._readableState ? this._readableState.endEmitted : false; }, }, - }); +function normalizeBuffer(state) { + if (state[kBufferIndex] > 0) { + state.splice(state[kBufferIndex]); + state[kBufferIndex] = 0; + } +} + ObjectDefineProperties(ReadableState.prototype, { // Legacy getter for `pipesCount`. pipesCount: { @@ -1568,6 +1576,30 @@ ObjectDefineProperties(ReadableState.prototype, { } }, }, + + // Legacy compat + buffer: { + __proto__: null, + get() { + return new Proxy(this._readableState[kBuffer], { + get (target, name) { + if (name === 'length') { + return target[kBuffer].length - target[kBufferIndex]; + } + if (name === '0') { + return target[kBuffer][target[kBufferIndex]]; + } + normalizeBuffer(target); + return target[name]; + }, + set (target, name, value, receiver) { + normalizeBuffer(target); + target[name] = value; + return true; + } + }) + }, + }, }); // Exposed for testing purposes only. @@ -1582,10 +1614,10 @@ function fromList(n, state) { if (state.length === 0) return null; - let idx = state.bufferIndex; + let idx = state[kBufferIndex]; let ret; - const buf = state.buffer; + const buf = state[kBuffer]; const len = buf.length; if ((state[kState] & kObjectMode) !== 0) { @@ -1656,8 +1688,8 @@ function fromList(n, state) { TypedArrayPrototypeSet(ret, data, retLen - n); buf[idx++] = null; } else { - TypedArrayPrototypeSet(ret, new FastBuffer(data.buffer, data.byteOffset, n), retLen - n); - buf[idx] = new FastBuffer(data.buffer, data.byteOffset + n, data.length - n); + TypedArrayPrototypeSet(ret, new FastBuffer(data[kBuffer], data.byteOffset, n), retLen - n); + buf[idx] = new FastBuffer(data[kBuffer], data.byteOffset + n, data.length - n); } break; } @@ -1665,13 +1697,13 @@ function fromList(n, state) { } if (idx === len) { - state.buffer.length = 0; - state.bufferIndex = 0; + state[kBuffer].length = 0; + state[kBufferIndex] = 0; } else if (idx > 1024) { - state.buffer.splice(0, idx); - state.bufferIndex = 0; + state[kBuffer].splice(0, idx); + state[kBufferIndex] = 0; } else { - state.bufferIndex = idx; + state[kBufferIndex] = idx; } return ret;