Skip to content

Commit d1567ab

Browse files
watildeaduh95
authored andcommitted
buffer: normalize lone "\r" in Blob native line endings
`new Blob(parts, { endings: 'native' })` failed to normalize a standalone carriage return. The replacement regex only matched `\n` and `\r\n`, so a lone `\r` (and runs such as `\r\r`) were left untouched instead of being converted to the platform's native line ending. The WHATWG "convert line endings to native" algorithm requires `\r`, `\n`, and `\r\n` to all be normalized. Match `\r\n` before a lone `\r` so that CRLF collapses to a single native ending. Refs: https://w3c.github.io/FileAPI/#convert-line-endings-to-native Signed-off-by: Daijiro Wachi <daijiro.wachi@gmail.com> PR-URL: #64115 Refs: https://w3c.github.io/FileAPI/#convert-line-endings-to-native Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Jason Zhang <xzha4350@gmail.com>
1 parent bd1e1d0 commit d1567ab

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

lib/internal/blob.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function getSource(source, endings) {
122122
source = new Uint8Array(source);
123123
} else if (!isArrayBufferView(source)) {
124124
if (endings === 'native')
125-
source = RegExpPrototypeSymbolReplace(/\n|\r\n/g, source, EOL);
125+
source = RegExpPrototypeSymbolReplace(/\r\n|\r|\n/g, source, EOL);
126126
source = enc.encode(source);
127127
}
128128

test/parallel/test-blob.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,24 @@ assert.throws(() => new Blob({}), {
407407
const b = new Blob(['hello\n'], { endings: 'native' });
408408
assert.strictEqual(b.size, EOL.length + 5);
409409

410+
// The WHATWG "convert line endings to native" algorithm normalizes every
411+
// standalone "\r", "\n", and "\r\n" sequence to the native line ending.
412+
// Refs: https://w3c.github.io/FileAPI/#convert-line-endings-to-native
413+
(async () => {
414+
const cases = [
415+
['a\rb', `a${EOL}b`],
416+
['a\nb', `a${EOL}b`],
417+
['a\r\nb', `a${EOL}b`],
418+
['a\r\rb', `a${EOL}${EOL}b`],
419+
['a\n\rb', `a${EOL}${EOL}b`],
420+
['\r\n\r', `${EOL}${EOL}`],
421+
];
422+
for (const [input, expected] of cases) {
423+
const blob = new Blob([input], { endings: 'native' });
424+
assert.strictEqual(await blob.text(), expected);
425+
}
426+
})().then(common.mustCall());
427+
410428
[1, {}, 'foo'].forEach((endings) => {
411429
assert.throws(() => new Blob([], { endings }), {
412430
code: 'ERR_INVALID_ARG_VALUE',

0 commit comments

Comments
 (0)