aws / aws-lambda-dotnet

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

Exceeded maximum allowed payload size #1815

Open schmallaria opened 2 months ago

schmallaria commented 2 months ago

Describe the bug

Hi,

We have an ASP.NET Core Web API running, hosted in a Lambda function. The API uses Top Level Statements and the package Amazon.Lambda.AspNetCoreServer.Hosting.

The function acts as a Proxy Server which enables our API clients to access a lot of legacy SOAP services. In front of the Lambda function there is an API Gateway.

Some of the responses from the SOAP Services exceeds the Lambda response limit of 6MB. When this occurs the underlying Lambda runtime client receives an HTTP 413 error and throws an exception which crashes the whole application, because this happens during startup of the .net application.

I'm not sure if it is a bug or not. How can we handle those errors. In such cases the calling client application should also receive HTTP 413 and not 500.

Regression Issue

Expected Behavior

Application doesn't crash, exception can be handled and send back to the client.

Current Behavior

When response size is greater than 6 MB, Lambda function receives an HTTP 413 error and crashes. The calling client receives a HTTP 500 error, probably because of the crashed application. The exception occurs during startup of the application:

{"errorMessage":"Exceeded maximum allowed payload size (6291556 bytes).","errorType":"RequestEntityTooLarge"}

at Amazon.Lambda.RuntimeSupport.InternalRuntimeApiClient.ResponseAsync(String awsRequestId, Stream outputStream, CancellationToken cancellationToken)
at Amazon.Lambda.RuntimeSupport.RuntimeApiClient.SendResponseAsync(String awsRequestId, Stream outputStream, CancellationToken cancellationToken)
at Amazon.Lambda.RuntimeSupport.LambdaBootstrap.InvokeOnceAsync(CancellationToken cancellationToken)
at Amazon.Lambda.RuntimeSupport.LambdaBootstrap.RunAsync(CancellationToken cancellationToken)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>b__15_1(IHostedService service, CancellationToken token)
at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
at Program.<Main>$(String[] args) in Program.cs:line 56

Reproduction Steps

n/a

Possible Solution

No response

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

Amazon.Lambda.AspNetCoreServer.Hosting 1.7.0

Targeted .NET Platform

.NET Core 8.0

Operating System and version

Docker container

ashishdhingra commented 2 months ago

Issue reproducible using below code:

...
    [Route("api/[controller]")]
    public class ValuesController : ControllerBase
    {
        private IHttpContextAccessor _httpContextAccessor;

        public ValuesController(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            string val1 = new string('*', 7 * 1024 * 1024); // 7MB string
            return new string[] { val1, "value2" };
        }
...

In CloudWatch logs, error with 413 status code would be logged:

{
    "errorMessage": "Exceeded maximum allowed payload size (6291556 bytes).",
    "errorType": "RequestEntityTooLarge"
}

The front-end will get a 502 Bad Gateway HTTP response status code.

@schmallaria I'm unsure if you could intercept the exception thrown by Lambda runtime. May be you could check the payload size returned by your downstream SOAP services and throw custom model object containing error property and status code to the calling client?

Thanks, Ashish

schmallaria commented 2 months ago

@ashishdhingra, checking downstream of SOAP Service is not possible. I've tried to use a Global Exception Handler using IExceptionHandler interface, but that's also not working, because the error occurs during startup of the application and at this time the application pipeline is not available, no chance to respond with a specific error to the calling client.

normj commented 2 weeks ago

I agree it would be for our library when converting the ASP.NET Core response to the API Gateway response check the size and if it larger then API Gateway can handle return an API Gateway response with the status code set to 413.