Skip to content

Commit a906ada

Browse files
committed
http-client: fix base64 decoding of journal content
The grpc gateway returns journal content as a base64-encoded string. Previously, we had been using `atob` to decode this, but that function does not work if the decoded content contains any byte values larger than 0x7f, because of course we can't have nice things in JS. So this adds one of those looks-insane-but-actually-works workarounds to make base64 decoding work properly with arbitrary utf-8 data.
1 parent fa319e4 commit a906ada

File tree

4 files changed

+44
-4
lines changed

4 files changed

+44
-4
lines changed

Diff for: client/dist/esm/streams.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,17 @@ export function decodeContent() {
5050
transform(value, controller) {
5151
// Base64 decode the `content` field and send it as a chunk.
5252
if (value.content?.length) {
53-
controller.enqueue(atob(value.content));
53+
// The `atob` function does not work properly if the decoded content contains any byte
54+
// values over 0x7f, because "binary" in JS means that each byte gets represented as a
55+
// UTF-16 code unit, which happens to be <= 0xff. I wish I was making this up:
56+
// https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
57+
const binary = atob(value.content);
58+
const bytes = new Uint8Array(binary.length);
59+
for (let i = 0; i < bytes.length; i++) {
60+
bytes[i] = binary.charCodeAt(i);
61+
}
62+
const text = new TextDecoder().decode(bytes);
63+
controller.enqueue(text);
5464
}
5565
},
5666
});

Diff for: client/dist/script/streams.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,17 @@ function decodeContent() {
5656
transform(value, controller) {
5757
// Base64 decode the `content` field and send it as a chunk.
5858
if (value.content?.length) {
59-
controller.enqueue(atob(value.content));
59+
// The `atob` function does not work properly if the decoded content contains any byte
60+
// values over 0x7f, because "binary" in JS means that each byte gets represented as a
61+
// UTF-16 code unit, which happens to be <= 0xff. I wish I was making this up:
62+
// https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
63+
const binary = atob(value.content);
64+
const bytes = new Uint8Array(binary.length);
65+
for (let i = 0; i < bytes.length; i++) {
66+
bytes[i] = binary.charCodeAt(i);
67+
}
68+
const text = new TextDecoder().decode(bytes);
69+
controller.enqueue(text);
6070
}
6171
},
6272
});

Diff for: client/dist/src/streams.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,17 @@ export function decodeContent() {
5454
transform(value, controller) {
5555
// Base64 decode the `content` field and send it as a chunk.
5656
if (value.content?.length) {
57-
controller.enqueue(atob(value.content));
57+
// The `atob` function does not work properly if the decoded content contains any byte
58+
// values over 0x7f, because "binary" in JS means that each byte gets represented as a
59+
// UTF-16 code unit, which happens to be <= 0xff. I wish I was making this up:
60+
// https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
61+
const binary = atob(value.content);
62+
const bytes = new Uint8Array(binary.length);
63+
for (let i = 0; i < bytes.length; i++) {
64+
bytes[i] = binary.charCodeAt(i);
65+
}
66+
const text = new TextDecoder().decode(bytes);
67+
controller.enqueue(text);
5868
}
5969
},
6070
});

Diff for: client/src/streams.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,17 @@ export function decodeContent() {
5454
transform(value, controller) {
5555
// Base64 decode the `content` field and send it as a chunk.
5656
if (value.content?.length) {
57-
controller.enqueue(atob(value.content));
57+
// The `atob` function does not work properly if the decoded content contains any byte
58+
// values over 0x7f, because "binary" in JS means that each byte gets represented as a
59+
// UTF-16 code unit, which happens to be <= 0xff. I wish I was making this up:
60+
// https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
61+
const binary = atob(value.content);
62+
const bytes = new Uint8Array(binary.length);
63+
for (let i = 0; i < bytes.length; i++) {
64+
bytes[i] = binary.charCodeAt(i);
65+
}
66+
const text = new TextDecoder().decode(bytes);
67+
controller.enqueue(text);
5868
}
5969
},
6070
});

0 commit comments

Comments
 (0)