Base64 Encoding in Netlify Lambda Functions

Hey! I was making a Netlify function that will take input of a form that contains a couple of images and some JSON data. I am sending it as a Base64 string in JSON form. In the local environment in Netlify Dev. It is working as expected, but In production, the body of the form is getting converted into base64 string and the parameter isBase64Encoded is true. And If I decoded it, then I am getting only a part of the body, it’s not full-body what I sent.

Example,
What I am sending {"name": "John}
What I am recieving {"name: "j`

Thanks

Are you sure you’re encoding and returning a single string rather than several, and that there is no terminating character like ’ midstring? Sorry if that’s a dumb question but it seems good to establish that first since you didn’t share your source code.

Hey @fool
I’m facing the exact same problem as @s-r-aman, i’ll try to go a bit more in depth.

We have a json payload being sent to netlify without application/json header (we have no control over this, since its coming via webhook from our rabbitmq queue).

This is our netlify handler that we are using to test this:

export const handler = async (event, context) => {
  let body = event.body;

  console.log(event.body);

  if (event.isBase64Encoded) {
    body = Buffer.from(event.body, 'base64').toString();
    console.log("isBase64Encoded");
  }
  console.log("Body decoded", body);
}

The payload being sent in this test was:

{"name": "test"}

The payload header is as follows

content-length:"6980"
content-type:"application/octet-stream"
host:"[our-netlify-app-name].netlify.app"
user-agent:"cloudamqp-webhook"
via:"https/1.1 Netlify[d88178b9-2f6e-424e-87d2-12d3c9873377] (ApacheTraffic..."

The output from netlify is

Body decoded {"name": "test"

Wondering if this is an error with the way netlify is handling the encoding part of the request, or if it’s something we are doing wrong in our end.

Thanks

Hey @Gui,
I just sent a POST request via Postman to your function endpoint and this is what I saw in your function logs:

5:07:38 PM: 2020-09-19T00:07:38.207Z	...	INFO	{"name": "test"}
5:07:38 PM: 2020-09-19T00:07:38.208Z	...	INFO	Body decoded {"name": "test"}
5:07:38 PM: Duration: 6.44 ms	Memory Usage: 73 MB	

Maybe you’ve resolved this since writing in? Please let us know if that’s not the case :slight_smile:

Hi @jen,

Thanks for the prompt reply. But I guess the problem is still there, maybe you sent the POST request to my endpoint using a content-type equal to application/json?

I’ve just tested it again, this is the simplest POST that will make the function output this wrong result

Headers:

content-type: application/octet-stream

Body

{"name": "test"}

The output was

9:51:07 PM: 2020-09-19T00:51:07.895Z	701e2c8e-3255-4fd2-994b-97b626b31da3	INFO	eyJuYW1lIjogInRlc3Qi
9:51:07 PM: 2020-09-19T00:51:07.895Z	701e2c8e-3255-4fd2-994b-97b626b31da3	INFO	isBase64Encoded
9:51:07 PM: 2020-09-19T00:51:07.895Z	701e2c8e-3255-4fd2-994b-97b626b31da3	INFO	Body decoded {"name": "test"

Hi @jen,

I had to make do with the problem in our main function with some try catches. But to continue this thread i setup a function at https://zerezes-quatro-olhos.netlify.app/.netlify/functions/base64-parse-error that still answers with the bad parsed body after decoding from base64.

This is all the content from the function handler

export const handler = async (event, context) => {
  let body = event.body;

  console.log(event.body);

  if (event.isBase64Encoded) {
    body = Buffer.from(event.body, 'base64').toString();
    console.log("isBase64Encoded");
  }
  
  console.log("Body decoded", body);

  return {
    statusCode: 200,
    body
  }
}

POST to https://zerezes-quatro-olhos.netlify.app/.netlify/functions/base64-parse-error

Headers:

content-type: application/octet-stream

Body

{"name": "test"}

Output

{"name": "test"

Hey @gui,
Sorry for the slow reply- I was out of office, but back now and taking a look! I was indeed looking at a different function in my initial reply, so will do some testing with the one you shared.

Taking another look at this, I think what you’re running into is expected with the application/octet-stream header set in the POST request to your function. Because that header is set, we base64 encode the payload. If you were to send the POST request with a content-type header like text/plain or application/json, then we would not encode the payload.

If you don’t have control over the application/octet-stream content-type header being set for the request, then you will want to base64 encode the JSON string before POSTing to the function, so something like:

let bufferObj = Buffer.from('{"name": "test"}', "utf8");
let base64String = bufferObj.toString("base64");

Then, you can decode that within the function as you’re doing and pass it along as a string. Let us know if that helps!

Hi @jen

Thanks for getting back to me about this. I didn’t have time to do much digging into this today, but from what i could test so far, your suggestion would result in me having to decode the body twice, am I correct?

If i encode the json before sending it, from the tests i’ve done, netlify will still encode it again, so i would have something like this

The original body:

{"name": "test"}

is sent after being converted to a encoded string

let bufferObj = Buffer.from('{"name": "test"}', "utf8");
let base64String = bufferObj.toString("base64"); // eyJuYW1lIjogInRlc3QifQ==

this is queued as eyJuYW1lIjogInRlc3QifQ== and at some point in the future sent to another function to be processed.

...
  if (event.isBase64Encoded) {
    let body = event.body // ZXlKdVlXMWxJam9nSW5SbGMzUWlmUT09 (encoding inception due to netlify)
    let firstDecode = Buffer.from(body, 'base64').toString("utf-8"); // eyJuYW1lIjogInRlc3QifQ==
    let message = JSON.parse(Buffer.from(firstDecode, 'base64').toString()) // this is {test: "name"};
  }
... 

Although this works, i wonder if this is the correct approach, since having to decode it twice seems a bit odd to me. I’m no expert with encoding/decoding so I apologize if this is in any way obvious.

I agree, it is weird and not ideal to double decode! The best case would be to change the content-type header on the POST to tell the function that the payload should not be base64 encoded. But since that’s not an option, this is the best workaround I know of. If you find another more concise way and are able to report back here, we would definitely love to know.