From c30a153d1f47e6b1e48294fc4516ca58aec4b0c3 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Mon, 30 Mar 2020 12:50:43 -0700 Subject: [PATCH] Use new text encoder for stream frames This pattern was introduced with Exec and fixes the multibyte encoding issue that the native window.atob has. --- ui/app/utils/stream-frames.js | 14 ++++++++------ ui/tests/unit/utils/stream-frames-test.js | 13 +++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ui/app/utils/stream-frames.js b/ui/app/utils/stream-frames.js index 71ceadb4142..a4a4f54dfc7 100644 --- a/ui/app/utils/stream-frames.js +++ b/ui/app/utils/stream-frames.js @@ -1,3 +1,8 @@ +import { TextDecoderLite } from 'text-encoder-lite'; +import base64js from 'base64-js'; + +const decoder = new TextDecoderLite('utf-8'); + /** * * @param {string} chunk @@ -15,7 +20,7 @@ export function decode(chunk) { const frames = lines.map(line => JSON.parse(line)).filter(frame => frame.Data); if (frames.length) { - frames.forEach(frame => (frame.Data = b64DecodeUnicode(frame.Data))); + frames.forEach(frame => (frame.Data = b64decode(frame.Data))); return { offset: frames[frames.length - 1].Offset, message: frames.mapBy('Data').join(''), @@ -25,9 +30,6 @@ export function decode(chunk) { return {}; } -function b64DecodeUnicode(str) { - // from bytestream, to percent-encoding, to original string. - return decodeURIComponent(window.atob(str).split('').map(function(c) { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }).join('')); +function b64decode(str) { + return decoder.decode(base64js.toByteArray(str)); } diff --git a/ui/tests/unit/utils/stream-frames-test.js b/ui/tests/unit/utils/stream-frames-test.js index 0a185eb5bbc..90bab68c804 100644 --- a/ui/tests/unit/utils/stream-frames-test.js +++ b/ui/tests/unit/utils/stream-frames-test.js @@ -1,5 +1,10 @@ import { module, test } from 'qunit'; import { decode } from 'nomad-ui/utils/stream-frames'; +import { TextEncoderLite } from 'text-encoder-lite'; +import base64js from 'base64-js'; + +const Encoder = new TextEncoderLite('utf-8'); +const encode = str => base64js.fromByteArray(Encoder.encode(str)); module('Unit | Util | stream-frames', function() { const { btoa } = window; @@ -31,6 +36,14 @@ module('Unit | Util | stream-frames', function() { in: '', out: {}, }, + { + name: 'Multi-byte unicode', + in: `{"Offset":1,"Data":"${encode('ワンワン 🐶')}"}`, + out: { + offset: 1, + message: 'ワンワン 🐶', + }, + }, ]; decodeTestCases.forEach(testCase => {