-
Notifications
You must be signed in to change notification settings - Fork 485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add 6MB request and response size check #1990
Changes from all commits
8c9f9f7
3737f07
c179779
c8af00f
a7c413d
573a0bb
82cedef
cbf3b2a
f44b5ef
de827ad
d94320d
9570368
1357f86
1c19955
084b64c
57bbd2c
9e4e6a0
cf39cc7
8954a44
ad8d0a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"Projects": [ | ||
{ | ||
"Name": "Amazon.Lambda.TestTool", | ||
"Type": "Patch", | ||
"ChangelogMessages": [ | ||
"Add 6MB request and response size validation." | ||
] | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
using Amazon.Lambda.Model; | ||
using Microsoft.AspNetCore.Components; | ||
using Amazon.Lambda.TestTool.Services; | ||
using Amazon.Lambda.TestTool.Models; | ||
|
@@ -9,6 +10,7 @@ | |
using BlazorMonaco.Editor; | ||
using Microsoft.JSInterop; | ||
using Microsoft.AspNetCore.WebUtilities; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Amazon.Lambda.TestTool.Components.Pages; | ||
|
||
|
@@ -21,6 +23,8 @@ public partial class Home : ComponentBase, IDisposable | |
[Inject] public required IDirectoryManager DirectoryManager { get; set; } | ||
[Inject] public required IThemeService ThemeService { get; set; } | ||
[Inject] public required IJSRuntime JsRuntime { get; set; } | ||
[Inject] public required ILambdaClient LambdaClient { get; set; } | ||
[Inject] public IOptions<LambdaOptions> LambdaOptions { get; set; } | ||
|
||
private StandaloneCodeEditor? _editor; | ||
private StandaloneCodeEditor? _activeEditor; | ||
|
@@ -33,6 +37,8 @@ public partial class Home : ComponentBase, IDisposable | |
|
||
private const string NoSampleSelectedId = "void-select-request"; | ||
|
||
private string _errorMessage = string.Empty; | ||
|
||
private IDictionary<string, IList<LambdaRequest>> SampleRequests { get; set; } = new Dictionary<string, IList<LambdaRequest>>(); | ||
|
||
private IRuntimeApiDataStore? DataStore { get; set; } | ||
|
@@ -184,9 +190,12 @@ async Task OnAddEventClick() | |
DataStore is null) | ||
return; | ||
var editorValue = await _editor.GetValue(); | ||
DataStore.QueueEvent(editorValue, false); | ||
await _editor.SetValue(string.Empty); | ||
SelectedSampleRequestName = NoSampleSelectedId; | ||
var success = await InvokeLambdaFunction(editorValue); | ||
if (success) | ||
{ | ||
await _editor.SetValue(string.Empty); | ||
SelectedSampleRequestName = NoSampleSelectedId; | ||
} | ||
StateHasChanged(); | ||
} | ||
|
||
|
@@ -202,7 +211,7 @@ void OnClearExecuted() | |
StateHasChanged(); | ||
} | ||
|
||
void OnRequeue(string awsRequestId) | ||
async Task OnRequeue(string awsRequestId) | ||
{ | ||
if (DataStore is null) | ||
return; | ||
|
@@ -218,8 +227,7 @@ void OnRequeue(string awsRequestId) | |
|
||
if (evnt == null) | ||
return; | ||
|
||
DataStore.QueueEvent(evnt.EventJson, false); | ||
await InvokeLambdaFunction(evnt.EventJson); | ||
StateHasChanged(); | ||
} | ||
|
||
|
@@ -326,4 +334,32 @@ private StandaloneEditorConstructionOptions ActiveErrorEditorConstructionOptions | |
} | ||
}; | ||
} | ||
|
||
private async Task<bool> InvokeLambdaFunction(string payload) | ||
{ | ||
var invokeRequest = new InvokeRequest | ||
{ | ||
FunctionName = SelectedFunctionName, | ||
Payload = payload, | ||
InvocationType = InvocationType.Event | ||
}; | ||
|
||
try | ||
{ | ||
await LambdaClient.InvokeAsync(invokeRequest, LambdaOptions.Value.Endpoint); | ||
_errorMessage = string.Empty; | ||
return true; | ||
} | ||
catch (AmazonLambdaException e) | ||
{ | ||
Logger.LogInformation(e.Message); | ||
|
||
// lambda client automatically adds some extra verbiage: "The service returned an error with Error Code xxxx and HTTP Body: <bodyhere>". | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: log the entire error using the logger |
||
// removing the extra verbiage to make the error message smaller and look better on the ui. | ||
_errorMessage = e.Message.Contains("HTTP Body: ") | ||
? e.Message.Split("HTTP Body: ")[1] | ||
: e.Message; | ||
} | ||
return false; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
namespace Amazon.Lambda.TestTool; | ||
|
||
/// <summary> | ||
/// Contains constant string values for AWS Lambda exception types. | ||
/// </summary> | ||
public class Exceptions | ||
{ | ||
/// <summary> | ||
/// Exception thrown when the request payload size exceeds AWS Lambda's limits. | ||
/// This occurs when the request payload is larger than 6 MB for synchronous invocations. | ||
/// </summary> | ||
public const string RequestEntityTooLargeException = "RequestEntityTooLargeException"; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,8 @@ | |
using Amazon.Lambda.Model; | ||
using Amazon.Lambda.TestTool.Models; | ||
|
||
namespace Amazon.Lambda.TestTool.Extensions; | ||
|
||
/// <summary> | ||
/// Provides extension methods for converting Lambda InvokeResponse to API Gateway response types. | ||
/// </summary> | ||
|
@@ -83,6 +85,52 @@ public static APIGatewayProxyResponse ToApiGatewayErrorResponse(ApiGatewayEmulat | |
} | ||
} | ||
|
||
/// <summary> | ||
/// Creates a standard API Gateway response for a "Request Entity Too Large" (413) error. | ||
/// Not compatible with HTTP V2 API Gateway mode. | ||
/// </summary> | ||
/// <param name="emulatorMode">The API Gateway emulator mode (Rest or HttpV1 only).</param> | ||
/// <returns>An APIGatewayProxyResponse configured with: | ||
/// - Status code 413 | ||
/// - JSON error message ("Request Too Long" for REST, "Request Entity Too Large" for HTTP V1) | ||
/// - Content-Type header set to application/json | ||
/// </returns> | ||
/// <exception cref="InvalidOperationException">Thrown when emulatorMode is HttpV2 or invalid value</exception> | ||
/// <remarks> | ||
/// This method only supports REST and HTTP V1 API Gateway modes. For HTTP V2, | ||
/// use <seealso cref="ToHttpApiV2RequestTooLargeResponse"/>. | ||
/// </remarks> | ||
public static APIGatewayProxyResponse ToHttpApiRequestTooLargeResponse(ApiGatewayEmulatorMode emulatorMode) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, does this not apply to HttpV2? If not, maybe add a note to the method docs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. theres a separate function for httpv2, ill update the docs |
||
{ | ||
if (emulatorMode == ApiGatewayEmulatorMode.Rest) | ||
{ | ||
return new APIGatewayProxyResponse | ||
{ | ||
StatusCode = 413, | ||
Body = "{\"message\":\"Request Too Long\"}", | ||
Headers = new Dictionary<string, string> | ||
{ | ||
{ "Content-Type", "application/json" } | ||
}, | ||
IsBase64Encoded = false | ||
}; | ||
} | ||
if (emulatorMode == ApiGatewayEmulatorMode.HttpV1) | ||
{ | ||
return new APIGatewayProxyResponse | ||
{ | ||
StatusCode = 413, | ||
Body = "{\"message\":\"Request Entity Too Large\"}", | ||
Headers = new Dictionary<string, string> | ||
{ | ||
{ "Content-Type", "application/json" } | ||
}, | ||
IsBase64Encoded = false | ||
}; | ||
} | ||
throw new ArgumentException($"Unsupported API Gateway emulator mode: {emulatorMode}. Only Rest and HttpV1 modes are supported."); | ||
} | ||
|
||
/// <summary> | ||
/// Converts an Amazon Lambda InvokeResponse to an APIGatewayHttpApiV2ProxyResponse. | ||
/// </summary> | ||
|
@@ -209,4 +257,25 @@ public static APIGatewayHttpApiV2ProxyResponse ToHttpApiV2ErrorResponse() | |
}; | ||
} | ||
|
||
/// <summary> | ||
/// Creates a standard HTTP API v2 response for a "Request Entity Too Large" (413) error. | ||
/// </summary> | ||
/// <returns>An APIGatewayHttpApiV2ProxyResponse configured with: | ||
/// - Status code 413 | ||
/// - JSON error message | ||
/// - Content-Type header set to application/json | ||
/// </returns> | ||
public static APIGatewayHttpApiV2ProxyResponse ToHttpApiV2RequestTooLargeResponse() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: same comment about naming |
||
{ | ||
return new APIGatewayHttpApiV2ProxyResponse | ||
{ | ||
StatusCode = 413, | ||
Body = "{\"message\":\"Request Entity Too Large\"}", | ||
Headers = new Dictionary<string, string> | ||
{ | ||
{ "Content-Type", "application/json" } | ||
}, | ||
IsBase64Encoded = false | ||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
namespace Amazon.Lambda.TestTool.Models; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wasnt sure where to put this in models folder or in LambdaClient file/folder |
||
|
||
/// <summary> | ||
/// Configuration options for invoking lambda functions. | ||
/// </summary> | ||
public class LambdaOptions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add docs for class and members |
||
{ | ||
/// <summary> | ||
/// Gets or sets the endpoint URL for Lambda function invocations. | ||
/// </summary> | ||
/// <value> | ||
/// A string containing the endpoint URL. Defaults to an empty string. | ||
/// </value> | ||
public string Endpoint { get; set; } = string.Empty; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is the invocation type "Event" and not "RequestResponse"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the original implementation was also set to Event type (When invocated as
DataStore.QueueEvent(editorValue, false);
, thefalse
was for theisRequestResponse
boolean, so kept it the sameThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Event is what we want here because we just want to queue the event. We don't want to block the UI waiting for the response.