Repository navigation
fix(event-handler): ignore body on GET/HEAD requests when converting to Web Request - #5683
Conversation
…to Web Request API Gateway v1/v2 events can carry a body on GET or HEAD requests. The V1/V2 converters passed it through unconditionally, so the Web Request constructor threw a TypeError (GET/HEAD requests cannot have a body), crashing the handler invocation and returning a 502. Apply the same guard already used by the ALB converter, moved into the shared createBody helper, and add regression tests for GET/HEAD with a body on both V1 and V2. Closes aws-powertools#5673
svozza
left a comment
There was a problem hiding this comment.
Thanks for picking this up, the shared guard in createBody is the right place for it.
One change I'd like before merging. The dispatcher validates the method on an uppercased copy and then throws it away, and each converter re-reads the raw method from the event:
const method = event.httpMethod.toUpperCase();
if (!isHttpMethod(method)) throw new InvalidHttpMethodError(method);
return proxyEventV1ToWebRequest(event); // reads event.httpMethod again, rawThat means a lowercase get passes validation but misses the new guard, and Request throws the same TypeError this PR is fixing. patch is worse: the Fetch spec only normalises six methods and PATCH isn't one of them, so it reaches the router as patch and the route lookup misses. Neither happens with real API Gateway or ALB events today, but since you're already changing createBody's signature this is the moment to close it.
Suggestion: normalise at the point the method is read, so the value that's validated is the value that's used.
/**
* Reads and normalises the HTTP method of an event, throwing when it is not one we route.
*
* @param rawMethod - The method as it appears on the event
*/
const toHttpMethod = (rawMethod: string): HttpMethod => {
const method = rawMethod.toUpperCase();
if (!isHttpMethod(method)) {
throw new InvalidHttpMethodError(method);
}
return method;
};Each converter derives its method once from its own event and uses it for both the Request constructor and createBody:
const proxyEventV1ToWebRequest = (event: APIGatewayProxyEvent): Request => {
const method = toHttpMethod(event.httpMethod);
// ...
return new Request(url.toString(), {
method,
headers,
body: createBody(event.body, event.isBase64Encoded, method),
});
};Same for V2 (event.requestContext.http.method) and ALB. createBody can then take method: HttpMethod instead of string, and the dispatcher loses its two validation blocks and just dispatches on event type. The InvalidHttpMethodError is still thrown before any Request is built, so the existing 405 handling in Router is unaffected and the CONNECT/TRACE tests should pass as they are.
There's still some repetition left across the three converters after this, but that's beyond the scope of this PR; we're planning a follow-up to tidy that up separately.
Two small test asks:
- A converter-level case with a lowercase method, asserting
getyields aGETrequest with a null body andpatchyieldsPATCH, since those are the two behaviours that change. - One
it.eachover V1 and V2 intests/unit/http/Router/basic-routing.test.tsthat resolves a GET with a body throughapp.resolve()and asserts a 200, so the fix is locked in end to end rather than only at the converter.
Move method validation and normalization into a shared toHttpMethod helper called once per converter, so the same normalized value feeds both the Request constructor and createBody. This closes a gap: a lowercase method (e.g. get) previously passed the dispatcher's uppercase-only validation but missed createBody's guard when the converter re-read the raw method, and a lowercase patch was not normalized by the Fetch spec, so route lookup would miss it. Adds regression tests for lowercase get and patch on both V1 and V2 converters. Addresses review feedback from svozza on PR aws-powertools#5683.
Adds an it.each over the V1 and V2 converters that resolves a GET request carrying a body through Router.resolve() end to end and asserts a 200, per svozza's second test ask on PR aws-powertools#5683.
|
Good catch, thanks! Moved the normalization into a shared Added both test cases:
|
|
Awesome work, congrats on your first merged pull request and thank you for helping improve everyone's experience! |
Summary
Changes
API Gateway v1/v2 events can include a body on GET or HEAD requests, even
though that's unusual. The V1 and V2 event converters
(
proxyEventV1ToWebRequestandproxyEventV2ToWebRequest) passed the bodystraight through to the Web
Requestconstructor. Since a WebRequestwith method GET/HEAD cannot carry a body, this throws an uncaught
TypeError, crashing the handler invocation and returning a 502 to theclient.
The ALB converter already guarded against this case. This PR moves that
guard into the shared
createBodyhelper (used by all three converters) soGET/HEAD requests always get a
nullbody, matching the ALB converter'sexisting behavior.
Added regression tests covering GET and HEAD requests with a body for both
the API Gateway v1 and v2 converters.
Issue number: closes #5673
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.