Description
[REQUIRED] Environment info
firebase-tools: 14.9.0
Platform: macOS
[REQUIRED] Test case
The emulator doesn't decode strings with non-ascii utf8 characters correctly, for example, emoji.
Enqueue a task using firebase-admin in one (http) function:
const taskData = {"key":"some value with a utf-8 character, such as emoji"}
const queue = getFunctions().taskQueue("someTask")
await queue.enqueue(taskData)
Receive it:
export default async function someTask(req: TaskRequest) {
// does not print the original character
console.log(req.data.key)
}
[REQUIRED] Steps to reproduce
Run the emulator, invoke the http function that enqueues task, watch the task print the unexpected value.
[REQUIRED] Expected behavior
It should print exactly the utf-8 string that was enqueued.
[REQUIRED] Actual behavior
It prints a "junk" decoding.
The problem is that the emulator uses the JavaScript atob()
function to decode the base64 payload created by the Admin SDK. Here is what the Admin SDK does (correctly):
body: Buffer.from(JSON.stringify({ data })).toString('base64'),
Here is what the emulator does (incorrectly):
https://github.com/firebase/firebase-tools/blob/master/src/emulator/tasksEmulator.ts#L271
req.body.task.httpRequest.body = JSON.parse(atob(req.body.task.httpRequest.body));
atob()
uses the JavaScript native utf-16 internal encoding for strings, however, this incorrectly decodes anything with a codepoint above 256. What the emulator should do instead is use Buffer.from(data, "base64").toString("utf-8")
.
Here is a bit of node repl that illustrates the expected translation, including JSON parsing:
> b64 = Buffer.from(JSON.stringify({"A":"👍"})).toString('base64')
'eyJBIjoi8J+RjSJ9'
> JSON.parse(Buffer.from(b64, "base64").toString("utf-8"))
{ A: '👍' }
Note that the production Cloud Functions works fine - it's just the emulator that doesn't decode task payloads correctly.