aws / aws-sam-cli

CLI tool to build, test, debug, and deploy Serverless applications using AWS SAM
https://aws.amazon.com/serverless/sam/
Apache License 2.0
6.5k stars 1.17k forks source link

Bug: 'isBase64Encoded: true' not working in local sam. #6452

Closed dyingsunlight closed 7 months ago

dyingsunlight commented 9 months ago

Description:

I wan to draw image in lambda as response, but it seems broken when i using isBase64Encoded: true as response option.

The debug output shows generated events are isBase64Encoded: false and output the original body as ouput.

Steps to reproduce:

My project files:

lambda/hello-world.mjs

export const handler = async (event, context) => {
    return {
        statusCode: 200,
        headers: { "content-type": `image/png` },
        isBase64Encoded: true,
        body: "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYcAAB2HAY/l8WUAAADbSURBVHhe7dAxEQAgDAAxhHTEvzM8YKG/5y4Kct5clmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZa3M/KCjwdMHWsEkAAAAASUVORK5CYII="
    };
}

lambda/package.json

{
  "name": "sam-test",
  "version": "1.0.0",
  "type": "module",
  "private": true
}

template.json

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Transform": "AWS::Serverless-2016-10-31",
  "Description": "",
  "Resources": {
    "HelloWorld": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "CodeUri": "./lambda",
        "Handler": "hello-word.handler",
        "Runtime": "nodejs18.x",
        "Events": {
          "HelloWorldEvent0": {
            "Type": "Api",
            "Properties": {
              "Path": "/hello-world",
              "Method": "get"
            }
          }
        },
        "Timeout": 60,
        "MemorySize": 1024
      }
    }
  }
}

The example project can be found in https://github.com/dyingsunlight/aws-sam-bug-isBase64Encoded

Observed result:

The image is broken image When edit the content as text that the text is extracly set to body before.

Response body

iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYcAAB2HAY/l8WUAAADbSURBVHhe7dAxEQAgDAAxhHTEvzM8YKG/5y4Kct5clmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZgaxAViArkBXICmQFsgJZa3M/KCjwdMHWsEkAAAAASUVORK5CYII=

Expected result:

I also deploy the same code to aws lambda in production...

The response should be this image

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

{                                     
  "version": "1.104.0",               
  "system": {                         
    "python": "3.11.4",               
    "os": "Windows-10-10.0.19044-SP0" 
  },                                  
  "additional_dependencies": {        
    "docker_engine": "24.0.6",        
    "aws_cdk": "Not available",       
    "terraform": "1.6.4"              
  },                                  
  "available_beta_feature_env_vars": [
    "SAM_CLI_BETA_FEATURES",          
    "SAM_CLI_BETA_BUILD_PERFORMANCE", 
    "SAM_CLI_BETA_TERRAFORM_SUPPORT",
    "SAM_CLI_BETA_RUST_CARGO_LAMBDA"
  ]
}

Add --debug flag to command you are running

DEBUG outputs

2023-12-14 21:39:00,776 | Mounting HelloWorld at http://127.0.0.1:8090/hello-world [GET]
2023-12-14 21:39:00,777 | You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. If you  
used sam build before running local commands, you will need to re-run sam build for the changes to be picked up. You only need to restart SAM CLI if you update your AWS SAM template
2023-12-14 21:39:00,779 | Localhost server is starting up. Multi-threading = True
2023-12-14 21:39:00 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:8090
2023-12-14 21:39:00 Press CTRL+C to quit
2023-12-14 21:39:23,306 | Constructed Event 1.0 to invoke Lambda. Event: {'version': '1.0', 'httpMethod': 'GET', 'body': None, 'resource': '/hello-world', 'requestContext': {'resourceId': '123456', 'apiId': '1234567890',        
'resourcePath': '/hello-world', 'httpMethod': 'GET', 'requestId': 'f84cc355-d1eb-460f-b1c9-7379451f2037', 'accountId': '123456789012', 'stage': 'Prod', 'identity': {'apiKey': None, 'userArn': None, 'cognitoAuthenticationType':  
None, 'caller': None, 'userAgent': 'Custom User Agent String', 'user': None, 'cognitoIdentityPoolId': None, 'cognitoAuthenticationProvider': None, 'sourceIp': '127.0.0.1', 'accountId': None}, 'extendedRequestId': None, 'path':  
'/hello-world', 'protocol': 'HTTP/1.1', 'domainName': '127.0.0.1:8090', 'requestTimeEpoch': 1702561140, 'requestTime': '14/Dec/2023:13:39:00 +0000'}, 'queryStringParameters': None, 'multiValueQueryStringParameters': None,       
'headers': {'Host': '127.0.0.1:8090', 'Connection': 'keep-alive', 'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', 'Sec-Ch-Ua-Mobile': '?0', 'Sec-Ch-Ua-Platform': '"Windows"',
'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Accept':
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'Sec-Fetch-Site': 'none', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-User': '?1',
'Sec-Fetch-Dest': 'document', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7,ja;q=0.6,ru;q=0.5', 'X-Forwarded-Proto': 'http', 'X-Forwarded-Port': '8090'}, 'multiValueHeaders':    
{'Host': ['127.0.0.1:8090'], 'Connection': ['keep-alive'], 'Sec-Ch-Ua': ['"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"'], 'Sec-Ch-Ua-Mobile': ['?0'], 'Sec-Ch-Ua-Platform': ['"Windows"'],
'Upgrade-Insecure-Requests': ['1'], 'User-Agent': ['Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'], 'Accept':
['text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'], 'Sec-Fetch-Site': ['none'], 'Sec-Fetch-Mode': ['navigate'], 'Sec-Fetch-User': ['?1'],  
'Sec-Fetch-Dest': ['document'], 'Accept-Encoding': ['gzip, deflate, br'], 'Accept-Language': ['zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7,ja;q=0.6,ru;q=0.5'], 'X-Forwarded-Proto': ['http'], 'X-Forwarded-Port': ['8090']},
'pathParameters': None, 'stageVariables': None, 'path': '/hello-world', 'isBase64Encoded': False}
2023-12-14 21:39:23,319 | Found one Lambda function with name 'HelloWorld'
2023-12-14 21:39:23,321 | Invoking hello-word.handler (nodejs18.x)
2023-12-14 21:39:23,322 | No environment variables found for function 'HelloWorld'
2023-12-14 21:39:23,323 | Loading AWS credentials from session with profile 'None'
2023-12-14 21:39:23,336 | Resolving code path. Cwd=D:\Projects\sam-test, CodeUri=D:\Projects\sam-test\lambda
2023-12-14 21:39:23,338 | Resolved absolute path to code is D:\Projects\sam-test\lambda
2023-12-14 21:39:23,339 | Code D:\Projects\sam-test\lambda is not a zip/jar file
2023-12-14 21:39:28,354 | Local image is up-to-date
2023-12-14 21:39:28,363 | Checking free port on 127.0.0.1:5333
2023-12-14 21:39:28,368 | Using local image: public.ecr.aws/lambda/nodejs:18-rapid-x86_64.

2023-12-14 21:39:28,370 | Mounting D:\Projects\sam-test\lambda as /var/task:ro,delegated, inside runtime container
2023-12-14 21:39:29,222 | Starting a timer for 60 seconds for function 'HelloWorld'
START RequestId: 4ddc257a-d96c-4e41-8eb7-f501a5157e21 Version: $LATEST
END RequestId: 1da142fa-d1e8-48b9-a68a-93830248d442
REPORT RequestId: 1da142fa-d1e8-48b9-a68a-93830248d442  Init Duration: 0.03 ms  Duration: 71.21 ms      Billed Duration: 72 ms  Memory Size: 1024 MB    Max Memory Used: 1024 MB

2023-12-14 21:39:31,576 | Cleaning all decompressed code dirs
2023-12-14 21:39:31,579 | Unable to find Click Context for getting session_id.
2023-12-14 21:39:31 127.0.0.1 - - [14/Dec/2023 21:39:31] "GET /hello-world HTTP/1.1" 200 -
hnnasit commented 9 months ago

Hi @dyingsunlight, thanks for reporting the issue. I tried to deploy the app and browse the URL but could not see the image. As for the isBase64Encoded: False in the debug logs, it seems this is for the input event sent to the lambda function. I think what you are looking for is the response to return True for isBase64Encoded and looking at this code, the boolean value is a string. Can you check if setting it to a string works?

dyingsunlight commented 9 months ago

It's not working... I tried setting isBase64Encoded to 'true' and 'True', but the debug message still outputs: 'isBase64Encoded': False.

The debug logs:

Constructed Event 1.0 to invoke Lambda. Event: {'version': '1.0', 'httpMethod': 'GET', 'body': None, 'resource': '/hello-world', 'requestContext': {'resourceId': '123456', 'apiId': '1234567890',        
'resourcePath': '/hello-world', 'httpMethod': 'GET', 'requestId': '35b543fb-3f9b-4ba4-80a0-c1983c882814', 'accountId': '123456789012', 'stage': 'Prod', 'identity': {'apiKey': None, 'userArn': None, 'cognitoAuthenticationType':  
None, 'caller': None, 'userAgent': 'Custom User Agent String', 'user': None, 'cognitoIdentityPoolId': None, 'cognitoAuthenticationProvider': None, 'sourceIp': '127.0.0.1', 'accountId': None}, 'extendedRequestId': None, 'path':  
'/hello-world', 'protocol': 'HTTP/1.1', 'domainName': '127.0.0.1:8090', 'requestTimeEpoch': 1702792298, 'requestTime': '17/Dec/2023:05:51:38 +0000'}, 'queryStringParameters': None, 'multiValueQueryStringParameters': None,       
'headers': {'Host': '127.0.0.1:8090', 'Connection': 'keep-alive', 'Cache-Control': 'max-age=0', 'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', 'Sec-Ch-Ua-Mobile': '?0', 'Sec-Ch-Ua-Platform':    
'"Windows"', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Accept':
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'Sec-Fetch-Site': 'none', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-User': '?1',
'Sec-Fetch-Dest': 'document', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7,ja;q=0.6,ru;q=0.5', 'X-Forwarded-Proto': 'http', 'X-Forwarded-Port': '8090'}, 'multiValueHeaders':    
{'Host': ['127.0.0.1:8090'], 'Connection': ['keep-alive'], 'Cache-Control': ['max-age=0'], 'Sec-Ch-Ua': ['"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"'], 'Sec-Ch-Ua-Mobile': ['?0'], 'Sec-Ch-Ua-Platform':     
['"Windows"'], 'Upgrade-Insecure-Requests': ['1'], 'User-Agent': ['Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'], 'Accept':
['text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'], 'Sec-Fetch-Site': ['none'], 'Sec-Fetch-Mode': ['navigate'], 'Sec-Fetch-User': ['?1'],  
'Sec-Fetch-Dest': ['document'], 'Accept-Encoding': ['gzip, deflate, br'], 'Accept-Language': ['zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7,ja;q=0.6,ru;q=0.5'], 'X-Forwarded-Proto': ['http'], 'X-Forwarded-Port': ['8090']},
'pathParameters': None, 'stageVariables': None, 'path': '/hello-world', 'isBase64Encoded': False}

I believe the issue is that, according to the documentation, the 'isBase64Encoded' value should be a boolean type, not a string type.

https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.response

hnnasit commented 9 months ago

Marking this as a bug for the team to investigate the right behavior here.

sidhujus commented 7 months ago

Hi, It looks like because in the template provided the api definition does not have anything declared for the BinaryMediaTypes property SAM CLI does not try to decode the image. Changing the template to the following fixed the issue for me

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Transform": "AWS::Serverless-2016-10-31",
  "Description": "",
  "Resources": {
    "HelloWorld": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "CodeUri": "./lambda",
        "Handler": "hello-word.handler",
        "Runtime": "nodejs18.x",
        "Events": {
          "HelloWorldEvent0": {
            "Type": "Api",
            "Properties": {
              "Path": "/hello-world",
              "Method": "get",
              "RestApiId": {
                "Ref": "HelloWorldApi"
              }
            }
          }
        },
        "Timeout": 60,
        "MemorySize": 1024
      }
    },
    "HelloWorldApi": {
    "Type": "AWS::Serverless::Api",
    "Properties": {
      "StageName": "prod",
      "BinaryMediaTypes": ["image/png"]
    }
  }
  }
}

Alternatively changing the event type to HttpApi will also cause the image to be decoded. It looks like the behaviour for decoding base64 images is defined here

dyingsunlight commented 7 months ago

Thanks, it's looks working now!

github-actions[bot] commented 7 months ago

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.