aws / aws-lambda-dotnet

Libraries, samples and tools to help .NET Core developers develop AWS Lambda functions.
Apache License 2.0
1.57k stars 479 forks source link

DotNet Lambda with wasm resources not being handled correctly #1781

Closed genifycom closed 2 months ago

genifycom commented 2 months ago

Describe the bug

If you include a .wasm file in a lambda function (either standalone or in the wwwroot/_framework directory) then the API Gateway does not deliver the .wasm file intact to the caller.

I have successfully created a Blazor SSR and Webassembly project into Lambda but in order to do this, I had to place all of the .wasm files into an S3 bucket and serve them using API Gateway S3 integration.

I could not find a way to get the Lambda function to deliver them correctly to the client (they appear to get base64 encoded).

Using the standard dotnet Lambda proxy route, the Integration Reponse cannot be altered.

Expected Behavior

If I deploy a Blazor Web App to Lambda with webassembly, I expect the application to be able to deliver the .wasm files from the lambda function correctly to the client.

Current Behavior

Using the standard dotnet proxy route, the Integration response cannot be altered and it appears that the default configuration does not handle application/wasm files correctly as binary.

Reproduction Steps

Create a dotnet lambda application with a webassembly client and deploy to Lambda. All of the .wasm files will fail SHA-256 integrity checks because they have not been correctly handled by the routing.

Possible Solution

Change the proxy to allow application/wasm files?

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

Standard DotNet lambda project for application

Targeted .NET Platform

.NET Framework 8.0

Operating System and version

Windows 11

normj commented 2 months ago

Any chance you could put together a repo that you can share that demonstrates the behavior you are seeing?

genifycom commented 2 months ago

Absolutely. I have researched the heck out of this.

There are two possible scenarios.

  1. A wasm file embedded in a Lambda dotnet application. Then try and pull this wasm resource using the standard dotnet /{proxy+} route. This will return the wasm file, but the SHA-256 will not match the original.
  2. Using the standard directory created by Microsoft wwwroot_framework which includes dozens of .wasm files none of which will correctly match the SHA-256 of the blazor.boot.json file in _framework.

Do you want the full #2 example?

I have verified this problem by manually redirecting every .wasm file to an S3 bucket and using API Gateway s# integration for each individual file. In the integration response I include the Content-Type, Content-Length and Timestamp for each object as per https://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-s3.html Using this redirect, the lambda web assembly app works.

I can't use an s3 proxy because again the SHA-256 are wrong.

Thanks, Dave

normj commented 2 months ago

The first scenario seems like the basic problem we need to solve first so if you have a repo of that that I can investigate with that will help me get started.

genifycom commented 2 months ago

AWSServerlessWASMSample.zip

In Visual Studio 2022 created an AWS Serverless Application with Select Blueprint ASP.NET Core Web App

Then I added one of Microsoft's wasm files Microsoft.Extensions.Logging.wasm to wwwroot.

If I call this with Postman

https://xxx.execute-api.us-east-1.amazonaws.com/Prod/Microsoft.Extensions.Logging.wasm

The headers I get back say

Content-Type application/wasm Content-Length 17977 x-amzn-Remapped-Content-Length 16149

The correct file length is 16149

From blazor.boot.json (Microsoft's file)

"Microsoft.Extensions.Logging.wasm": "sha256-8BH+kQfjYuZWxprOICXJ4+tU0OdJOYDKN7G0S3zYYHI=",

SHA-256 of https://xxx.execute-api.us-east-1.amazonaws.com/Prod/Microsoft.Extensions.Logging.wasm is LoFWSPAifjI8QJ1u07C0q1vuvKxs401ZPgwCc1xQS2Q=

genifycom commented 2 months ago

Really appreciate you responding. Been trying to get this going for months :)

normj commented 2 months ago

I know I have seen you trying to get this working. I keep trying to find time to investigate but failing in that. I appreciate giving me the repo case so I can repo it faster.

normj commented 2 months ago

In your LambdaEntryPoint can you register the application/wasm content type to use base64 encoding? Below is an example and when I did this I saw content-length and x-amzn-Remapped-Content-Length were both 16149.

    protected override void Init(IHostBuilder builder)
    {
        base.RegisterResponseContentEncodingForContentType("application/wasm", Amazon.Lambda.AspNetCoreServer.ResponseContentEncoding.Base64);
    }

We should probably add application/wasm as base64 in the know content types dictionary. If you felt like sending over a PR that would be great. https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.AspNetCoreServer/AbstractAspNetCoreFunction.cs#L59

genifycom commented 2 months ago

So that works perfectly for the .wasm files. Totally awesome!

Is there anything I can do with the Microsoft .dat files? For example they have _framework/icudt_CJK.dat

AWSServerlessWASMSample.zip

This is the same project with the icudt_CJK.dat file added to wwwroot.

If I call with postman

https://xxx.execute-api.us-east-1.amazonaws.com/Prod/icudt_CJK.dat

I get a 404. This should probably be application/octet-stream

Is there any other Init magic I can invoke?

Thanks so much, Dave

normj commented 2 months ago

The dat file is an ASP.NET Core thing where it doesn't download unknown file types from wwwroot by default. I was able to reproduce your issue when just running the ASP.NET Core project locally.

My quick searching found the following work around you can do when configuring the IApplicationBuilder.

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "application/octet-stream"
});

Again this is an ASP.NET Core design so please don't take my quick googling solution as fact and make sure this is the right choice for you. I'm not sure what are the implications with setting ServeUnknownFileTypes to true.

genifycom commented 2 months ago

That did it!

I didn't think about that being a problem.

Wow. Appreciate your wealth of experience.

Thank you so much. With respect, Dave

normj commented 2 months ago

Great! Glad you got a path forward. Are we good to close the issue?

genifycom commented 2 months ago

Great work Norm. Thank you

github-actions[bot] commented 2 months ago

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.