From a6762135ddfc5ad39f48866798fdc20454652064 Mon Sep 17 00:00:00 2001 From: Khafra Date: Wed, 27 Mar 2024 12:23:18 -0400 Subject: [PATCH] fallback to Buffer.isUtf8 on platforms without icu --- lib/web/websocket/receiver.js | 5 ++--- lib/web/websocket/util.js | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/lib/web/websocket/receiver.js b/lib/web/websocket/receiver.js index 108d8b08f75..4b35ceb54a4 100644 --- a/lib/web/websocket/receiver.js +++ b/lib/web/websocket/receiver.js @@ -4,7 +4,7 @@ const { Writable } = require('node:stream') const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants') const { kReadyState, kSentClose, kResponse, kReceivedClose } = require('./symbols') const { channels } = require('../../core/diagnostics') -const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived } = require('./util') +const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived, utf8Decode } = require('./util') const { WebsocketFrameSend } = require('./frame') // This code was influenced by ws released under the MIT license. @@ -314,8 +314,7 @@ class ByteParser extends Writable { } try { - // TODO: optimize this - reason = new TextDecoder('utf-8', { fatal: true }).decode(reason) + reason = utf8Decode(reason) } catch { return null } diff --git a/lib/web/websocket/util.js b/lib/web/websocket/util.js index 6352b998ebd..05f879e6e14 100644 --- a/lib/web/websocket/util.js +++ b/lib/web/websocket/util.js @@ -3,6 +3,7 @@ const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = require('./symbols') const { states, opcodes } = require('./constants') const { MessageEvent, ErrorEvent } = require('./events') +const { isUtf8 } = require('node:buffer') /* globals Blob */ @@ -87,7 +88,7 @@ function websocketMessageReceived (ws, type, data) { // -> type indicates that the data is Text // a new DOMString containing data try { - dataForEvent = new TextDecoder('utf-8', { fatal: true }).decode(data) + dataForEvent = utf8Decode(data) } catch { failWebsocketConnection(ws, 'Received invalid UTF-8 in text frame.') return @@ -200,6 +201,33 @@ function failWebsocketConnection (ws, reason) { } } +// https://nodejs.org/api/intl.html#detecting-internationalization-support +const hasIntl = typeof process.versions.icu === 'string' +const fatalDecoder = hasIntl ? new TextDecoder('utf-8', { fatal: true }) : undefined + +/** + * Converts a Buffer to utf-8, even on platforms without icu. + * @param {Buffer} buffer + */ +function utf8Decode (buffer) { + if (hasIntl) { + return fatalDecoder.decode(buffer) + } else { + if (!isUtf8?.(buffer)) { + // TODO: remove once node 18 or < node v18.14.0 is dropped + if (!isUtf8) { + process.emitWarning('ICU is not supported and no fallback exists. Please upgrade to at least Node v18.14.0.', { + code: 'UNDICI-WS-NO-ICU' + }) + } + + throw new TypeError('Invalid utf-8 received.') + } + + return buffer.toString('utf-8') + } +} + module.exports = { isConnecting, isEstablished, @@ -209,5 +237,6 @@ module.exports = { isValidSubprotocol, isValidStatusCode, failWebsocketConnection, - websocketMessageReceived + websocketMessageReceived, + utf8Decode }