-
Notifications
You must be signed in to change notification settings - Fork 30k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
stream: support decoding buffers for Writables
Support decoding the input of writable streams to a specific decoding before passing it to `_write()`. By default, all data written to a writable stream is encoded into Buffers. This change enables the reverse situation, i.e. when it is desired by the stream implementer to process all input as strings, whether it was passed to `write()` as a string or not. This makes sense for multi-byte character encodings where the buffers that are written using `write()` may contain partial characters, so calling `chunk.toString()` is not universally applicable. Fixes: #7315
- Loading branch information
Showing
3 changed files
with
181 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
'use strict'; | ||
require('../common'); | ||
const assert = require('assert'); | ||
|
||
const stream = require('stream'); | ||
|
||
class ChunkStoringWritable extends stream.Writable { | ||
constructor(options) { | ||
super(options); | ||
|
||
this.chunks = []; | ||
} | ||
|
||
_write(data, encoding, callback) { | ||
this.chunks.push({ data, encoding }); | ||
callback(); | ||
} | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ decodeBuffers: true }); | ||
w.write(Buffer.from('e4bd', 'hex')); | ||
w.write(Buffer.from('a0e5', 'hex')); | ||
w.write(Buffer.from('a5bd', 'hex')); | ||
w.end(); | ||
|
||
assert.deepStrictEqual(w.chunks.map((c) => c.data), ['', '你', '好']); | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ decodeBuffers: true }); | ||
w.write(Buffer.from('你', 'utf8')); | ||
w.write(Buffer.from('好', 'utf8')); | ||
w.end(); | ||
|
||
assert.deepStrictEqual(w.chunks.map((c) => c.data), ['你', '好']); | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ decodeBuffers: true }); | ||
w.write(Buffer.from('80', 'hex')); | ||
w.end(); | ||
|
||
assert.deepStrictEqual(w.chunks.map((c) => c.data), ['\ufffd']); | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ decodeBuffers: true }); | ||
w.write(Buffer.from('c3', 'hex')); | ||
w.end(); | ||
|
||
assert.deepStrictEqual(w.chunks.map((c) => c.data), ['', '\ufffd']); | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ | ||
decodeBuffers: true, | ||
defaultEncoding: 'utf16le' | ||
}); | ||
|
||
w.write(Buffer.from('你好', 'utf16le')); | ||
w.end(); | ||
|
||
assert.deepStrictEqual(w.chunks.map((c) => c.data), ['你好']); | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ | ||
decodeBuffers: true, | ||
defaultEncoding: 'base64' | ||
}); | ||
|
||
w.write(Buffer.from('你好', 'utf16le')); | ||
w.end(); | ||
|
||
assert.deepStrictEqual(w.chunks.map((c) => c.data), ['YE99', 'WQ==']); | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ | ||
decodeBuffers: true, | ||
defaultEncoding: 'utf16le' | ||
}); | ||
|
||
w.write('你好', 'utf16le'); | ||
w.end(); | ||
|
||
assert.deepStrictEqual(w.chunks.map((c) => c.data), ['你好']); | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ decodeBuffers: true }); | ||
|
||
w.write(Buffer.from([0x44, 0xc3])); // Ends on incomplete UTF8. | ||
|
||
// This write should *not* be passed through directly as there's | ||
// input pending. | ||
w.write('a'); | ||
|
||
w.end(Buffer.from('bc7373656c', 'hex')); | ||
|
||
assert.deepStrictEqual(w.chunks.map((c) => c.data), ['D', '�a', '�ssel']); | ||
} | ||
|
||
{ | ||
const w = new ChunkStoringWritable({ decodeBuffers: true }); | ||
|
||
w.write('a'); | ||
w.setDefaultEncoding('ucs2'); | ||
w.end('换'); | ||
|
||
assert.deepStrictEqual(w.chunks, [ | ||
{ data: 'a', encoding: 'utf8' }, | ||
{ data: 'bc', encoding: 'utf8' } | ||
]); | ||
} | ||
|
||
assert.throws(() => new stream.Writable({ | ||
decodeBuffers: true, | ||
decodeStrings: true | ||
}), /decodeBuffers and decodeStrings cannot both be true/); |