Corrupt response when returning base64-decoded content

I’m currently working on this repo and I’m having a problem responding with image data (from a base64 string stored in KV).

What my script does is base64 encode a file, upload it to KV, and then a worker pulls that string from KV and is supposed to return the file to the browser. I’m having trouble with the worker though, as any time I try to access a non-text file (base64-encoded html, js, CSS work) I receive an invalid response and one that is significantly larger than the file.

Here is my worker code, you can disregard the “file splitting” code for now. The basics of what this does:

    let value = await STATIC_KV.get(reqpath)
    return new Response(atob(value), {
        headers: {
            'content-type': contenttype,
        },
    })

Here’s a live link of some content: https://worker.judge.sh/tesla.jpg

If I manually get the KV content via the API, and run it through an image decoder, it works:

However, if I get it via KV, OR I input it as a constant at the top of the file, I get what you see on the live link (https://worker.judge.sh/tesla.jpg).

If I use the testing tab, it seems like the decoding is working correctly (this is on a different image with metadata):

image

But still, the returned content refuses to render in the browser.

I feel like I’m doing something wrong in terms of returning image content, but I’m not sure. Would like to see if anyone could help me out with this one.

2 Likes

I seem to be able to reproduce that.

atob appears to work fine, but later on (either in Response or because it is passed as string) there is some form of double encoding taking place (hence the response is larger).

My guess would be using one of the other types supported by Response (which are probably more binary friendly) might just fix that.

3 Likes

Yep, I should have read more of the docs!

The fix was getting rid of Base64, then in the worker getting the key as an arrayBuffer type and directly passing that to the response.

https://worker.judge.sh/tesla.jpg

This was a consequence of atob() returning a string. The Response constructor UTF-8-encodes strings. Therefore, the image’s binary data was being interpreted as UTF-16, JavaScript’s normal native encoding.

2 Likes