Skip to content

[BUG] API Gateway V2 (HTTP API): trailing slash stripped from rawPath (rawPath /thing/ -> /thing) #2136

Description

@ravi-arnan

Service

API Gateway V2 (HTTP API)

AWS API Action

Lambda proxy integration invoke (payload format 2.0), and REQUEST authorizer invoke on payload format 1.0.

Expected behavior

A request to /thing/ on an HTTP API delivers the trailing slash to the Lambda, because rawPath is by contract the raw, unmodified path:

{ "rawPath": "/thing/" }

Routers commonly treat /thing and /thing/ as distinct routes, so a v2 Lambda needs to be able to tell them apart.

Actual behavior

The slash is stripped and the Lambda receives rawPath: "/thing". A v2 Lambda cannot distinguish /thing from /thing/ at all.

Cause is the same JAX-RS {proxy} path-param binding that #1557 covered for REST APIs. dispatchV2 rebuilds the path from the stripped binding at ApiGatewayExecuteController.java:1219:

String path = "/" + (proxy == null ? "" : proxy);

and that value becomes the event's rawPath at lines 1728 and 1840. buildRequestAuthorizerEventV1 (line 1680, used for v2 authorizers on payload format 1.0) has the same problem in its methodArn, resource, path and requestContext.path.

Impact

#1863 fixed this for REST (v1) APIs, so as of that PR a REST API preserves the trailing slash and an HTTP API silently does not. That inconsistency between the two API types is the confusing part, and it is worth closing so v1 and v2 do not drift.

Suggested fix

preserveTrailingSlash landed in #1863 as a static package-private helper, so v2 can reuse it as-is:

String path = preserveTrailingSlash(
        "/" + (proxy == null ? "" : proxy),
        uriInfo.getRequestUri().getRawPath());

One caveat: apiGatewayV2Service.findMatchingRoute (called at line 1216 area) would then receive the slash-preserving path, so route matching should keep using the normalized value. That is the same split #1863 made explicit for v1, where the event fields get the slash-preserving path while resource matching and path-parameter extraction stay on the normalized one.

Reproduction

# Create an HTTP API with a Lambda proxy integration on $default, then:
curl -s http://localhost:4566/restapis/<apiId>/<stage>/_user_request_/thing/
# Lambda receives rawPath "/thing", expected "/thing/"

Environment

  • Floci version / image tag: main (1.5.34)
  • How you're running Floci: ./mvnw quarkus:dev

Filed as the follow-up @abanna suggested while reviewing #1863, which deliberately scoped itself to v1. Happy to pick this up.

Metadata

Metadata

Assignees

No one assigned

    Labels

    apigatewayv2Amazon API Gateway v2 (HTTP/WebSocket)bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions