Skip to content

Commit 5eccd64

Browse files
addaleaxtargos
authored andcommitted
stream: convert existing buffer when calling .setEncoding
Convert already-stored chunks when `.setEncoding()` is called so that subsequent `data` events will receive decoded strings, as they expect. Fixes: #27932 PR-URL: #27936 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Rich Trott <[email protected]>
1 parent 6548b91 commit 5eccd64

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

‎lib/_stream_readable.js‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,22 @@ Readable.prototype.isPaused = function(){
321321
Readable.prototype.setEncoding=function(enc){
322322
if(!StringDecoder)
323323
StringDecoder=require('string_decoder').StringDecoder;
324-
this._readableState.decoder=newStringDecoder(enc);
324+
constdecoder=newStringDecoder(enc);
325+
this._readableState.decoder=decoder;
325326
// If setEncoding(null), decoder.encoding equals utf8
326327
this._readableState.encoding=this._readableState.decoder.encoding;
328+
329+
// Iterate over current buffer to convert already stored Buffers:
330+
letp=this._readableState.buffer.head;
331+
letcontent='';
332+
while(p!==null){
333+
content+=decoder.write(p.data);
334+
p=p.next;
335+
}
336+
this._readableState.buffer.clear();
337+
if(content!=='')
338+
this._readableState.buffer.push(content);
339+
this._readableState.length=content.length;
327340
returnthis;
328341
};
329342

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
'use strict';
2+
require('../common');
3+
const{ Readable }=require('stream');
4+
constassert=require('assert');
5+
6+
{
7+
// Call .setEncoding() while there are bytes already in the buffer.
8+
constr=newReadable({read(){}});
9+
10+
r.push(Buffer.from('a'));
11+
r.push(Buffer.from('b'));
12+
13+
r.setEncoding('utf8');
14+
constchunks=[];
15+
r.on('data',(chunk)=>chunks.push(chunk));
16+
17+
process.nextTick(()=>{
18+
assert.deepStrictEqual(chunks,['ab']);
19+
});
20+
}
21+
22+
{
23+
// Call .setEncoding() while the buffer contains a complete,
24+
// but chunked character.
25+
constr=newReadable({read(){}});
26+
27+
r.push(Buffer.from([0xf0]));
28+
r.push(Buffer.from([0x9f]));
29+
r.push(Buffer.from([0x8e]));
30+
r.push(Buffer.from([0x89]));
31+
32+
r.setEncoding('utf8');
33+
constchunks=[];
34+
r.on('data',(chunk)=>chunks.push(chunk));
35+
36+
process.nextTick(()=>{
37+
assert.deepStrictEqual(chunks,['🎉']);
38+
});
39+
}
40+
41+
{
42+
// Call .setEncoding() while the buffer contains an incomplete character,
43+
// and finish the character later.
44+
constr=newReadable({read(){}});
45+
46+
r.push(Buffer.from([0xf0]));
47+
r.push(Buffer.from([0x9f]));
48+
49+
r.setEncoding('utf8');
50+
51+
r.push(Buffer.from([0x8e]));
52+
r.push(Buffer.from([0x89]));
53+
54+
constchunks=[];
55+
r.on('data',(chunk)=>chunks.push(chunk));
56+
57+
process.nextTick(()=>{
58+
assert.deepStrictEqual(chunks,['🎉']);
59+
});
60+
}

0 commit comments

Comments
(0)