Skip to content

Commit 3d23d5b

Browse files
committed
stream: improve Readable legacy compat
The popular stream-shift library accesses internal Readable state which has been modified. Refs: googleapis/nodejs-storage#2391 Refs: mafintosh/stream-shift#10 PR-URL: nodejs#51470
1 parent ee61c2c commit 3d23d5b

File tree

1 file changed

+56
-23
lines changed

1 file changed

+56
-23
lines changed

lib/internal/streams/readable.js

+56-23
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ const kErroredValue = Symbol('kErroredValue');
102102
const kDefaultEncodingValue = Symbol('kDefaultEncodingValue');
103103
const kDecoderValue = Symbol('kDecoderValue');
104104
const kEncodingValue = Symbol('kEncodingValue');
105+
const kBuffer = Symbol('kBuffer');
106+
const kBufferIndex = Symbol('kBufferIndex');
105107

106108
const kEnded = 1 << 9;
107109
const kEndEmitted = 1 << 10;
@@ -276,8 +278,8 @@ function ReadableState(options, stream, isDuplex) {
276278
getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex) :
277279
getDefaultHighWaterMark(false);
278280

279-
this.buffer = [];
280-
this.bufferIndex = 0;
281+
this[kBuffer] = [];
282+
this[kBufferIndex] = 0;
281283
this.length = 0;
282284
this.pipes = [];
283285

@@ -561,13 +563,13 @@ function addChunk(stream, state, chunk, addToFront) {
561563
// Update the buffer info.
562564
state.length += (state[kState] & kObjectMode) !== 0 ? 1 : chunk.length;
563565
if (addToFront) {
564-
if (state.bufferIndex > 0) {
565-
state.buffer[--state.bufferIndex] = chunk;
566+
if (state[kBufferIndex] > 0) {
567+
state[kBuffer][--state[kBufferIndex]] = chunk;
566568
} else {
567-
state.buffer.unshift(chunk); // Slow path
569+
state[kBuffer].unshift(chunk); // Slow path
568570
}
569571
} else {
570-
state.buffer.push(chunk);
572+
state[kBuffer].push(chunk);
571573
}
572574

573575
if ((state[kState] & kNeedReadable) !== 0)
@@ -592,14 +594,14 @@ Readable.prototype.setEncoding = function(enc) {
592594

593595
// Iterate over current buffer to convert already stored Buffers:
594596
let content = '';
595-
for (const data of state.buffer.slice(state.bufferIndex)) {
597+
for (const data of state[kBuffer].slice(state[kBufferIndex])) {
596598
content += decoder.write(data);
597599
}
598-
state.buffer.length = 0;
599-
state.bufferIndex = 0;
600+
state[kBuffer].length = 0;
601+
state[kBufferIndex] = 0;
600602

601603
if (content !== '')
602-
state.buffer.push(content);
604+
state[kBuffer].push(content);
603605
state.length = content.length;
604606
return this;
605607
};
@@ -633,7 +635,7 @@ function howMuchToRead(n, state) {
633635
if (NumberIsNaN(n)) {
634636
// Only flow one buffer at a time.
635637
if ((state[kState] & kFlowing) !== 0 && state.length)
636-
return state.buffer[state.bufferIndex].length;
638+
return state[kBuffer][state[kBufferIndex]].length;
637639
return state.length;
638640
}
639641
if (n <= state.length)
@@ -790,7 +792,7 @@ function onEofChunk(stream, state) {
790792
if (decoder) {
791793
const chunk = decoder.end();
792794
if (chunk && chunk.length) {
793-
state.buffer.push(chunk);
795+
state[kBuffer].push(chunk);
794796
state.length += (state[kState] & kObjectMode) !== 0 ? 1 : chunk.length;
795797
}
796798
}
@@ -1459,7 +1461,7 @@ ObjectDefineProperties(Readable.prototype, {
14591461
__proto__: null,
14601462
enumerable: false,
14611463
get: function() {
1462-
return this._readableState && this._readableState.buffer;
1464+
return this._readableState && this._readableState[kBuffer];
14631465
},
14641466
},
14651467

@@ -1541,9 +1543,15 @@ ObjectDefineProperties(Readable.prototype, {
15411543
return this._readableState ? this._readableState.endEmitted : false;
15421544
},
15431545
},
1544-
15451546
});
15461547

1548+
function normalizeBuffer(state) {
1549+
if (state[kBufferIndex] > 0) {
1550+
state.splice(state[kBufferIndex]);
1551+
state[kBufferIndex] = 0;
1552+
}
1553+
}
1554+
15471555
ObjectDefineProperties(ReadableState.prototype, {
15481556
// Legacy getter for `pipesCount`.
15491557
pipesCount: {
@@ -1568,6 +1576,31 @@ ObjectDefineProperties(ReadableState.prototype, {
15681576
}
15691577
},
15701578
},
1579+
1580+
// Legacy compat
1581+
buffer: {
1582+
__proto__: null,
1583+
get() {
1584+
const r = this._readableState;
1585+
return new Proxy(r[kBuffer], {
1586+
get (target, name) {
1587+
if (name === 'length') {
1588+
return target[kBuffer].length - target[kBufferIndex];
1589+
}
1590+
if (name === '0') {
1591+
return target[kBuffer][target[kBufferIndex]];
1592+
}
1593+
normalizeBuffer(target);
1594+
return target[name];
1595+
},
1596+
set (target, property, value, receiver) {
1597+
normalizeBuffer(target);
1598+
target[property] = value;
1599+
return true;
1600+
}
1601+
})
1602+
},
1603+
},
15711604
});
15721605

15731606
// Exposed for testing purposes only.
@@ -1582,10 +1615,10 @@ function fromList(n, state) {
15821615
if (state.length === 0)
15831616
return null;
15841617

1585-
let idx = state.bufferIndex;
1618+
let idx = state[kBufferIndex];
15861619
let ret;
15871620

1588-
const buf = state.buffer;
1621+
const buf = state[kBuffer];
15891622
const len = buf.length;
15901623

15911624
if ((state[kState] & kObjectMode) !== 0) {
@@ -1656,22 +1689,22 @@ function fromList(n, state) {
16561689
TypedArrayPrototypeSet(ret, data, retLen - n);
16571690
buf[idx++] = null;
16581691
} else {
1659-
TypedArrayPrototypeSet(ret, new FastBuffer(data.buffer, data.byteOffset, n), retLen - n);
1660-
buf[idx] = new FastBuffer(data.buffer, data.byteOffset + n, data.length - n);
1692+
TypedArrayPrototypeSet(ret, new FastBuffer(data[kBuffer], data.byteOffset, n), retLen - n);
1693+
buf[idx] = new FastBuffer(data[kBuffer], data.byteOffset + n, data.length - n);
16611694
}
16621695
break;
16631696
}
16641697
}
16651698
}
16661699

16671700
if (idx === len) {
1668-
state.buffer.length = 0;
1669-
state.bufferIndex = 0;
1701+
state[kBuffer].length = 0;
1702+
state[kBufferIndex] = 0;
16701703
} else if (idx > 1024) {
1671-
state.buffer.splice(0, idx);
1672-
state.bufferIndex = 0;
1704+
state[kBuffer].splice(0, idx);
1705+
state[kBufferIndex] = 0;
16731706
} else {
1674-
state.bufferIndex = idx;
1707+
state[kBufferIndex] = idx;
16751708
}
16761709

16771710
return ret;

0 commit comments

Comments
 (0)