diff --git a/CHANGELOG.md b/CHANGELOG.md index 32af8abca95..49744f1b7d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ This project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) fo ## [Unreleased] +## [1.18.1] - 2021-07-23 + +### Bug Fixes + +* **api-gateway:** route regression for non-word and unsafe URI chars ([#556](https://github.com/awslabs/aws-lambda-powertools-python/issues/556)) + ## [1.18.0] - 2021-07-20 ### Bug Fixes diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 6948646a360..44d3f2b07de 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -21,7 +21,11 @@ logger = logging.getLogger(__name__) _DYNAMIC_ROUTE_PATTERN = r"(<\w+>)" -_NAMED_GROUP_BOUNDARY_PATTERN = r"(?P\1\\w+\\b)" +_SAFE_URI = "-._~()'!*:@,;" # https://www.ietf.org/rfc/rfc3986.txt +# API GW/ALB decode non-safe URI chars; we must support them too +_UNSAFE_URI = "%<>\[\]{}|^" # noqa: W605 + +_NAMED_GROUP_BOUNDARY_PATTERN = fr"(?P\1[{_SAFE_URI}{_UNSAFE_URI}\\w]+)" class ProxyEventType(Enum): diff --git a/pyproject.toml b/pyproject.toml index e1200887938..12d3c68376f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aws_lambda_powertools" -version = "1.18.0" +version = "1.18.1" description = "Python utilities for AWS Lambda functions including but not limited to tracing, logging and custom metric" authors = ["Amazon Web Services"] include = ["aws_lambda_powertools/py.typed"] diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index 1c7c53f7187..f16086ba634 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -701,3 +701,30 @@ def get_network_account(account_id: str, network_id: str): event["resource"] = "/accounts/{account_id}/source_networks/{network_id}" event["path"] = "/accounts/nested_account/source_networks/network" app.resolve(event, {}) + + +@pytest.mark.parametrize( + "req", + [ + pytest.param(123456789, id="num"), + pytest.param("user@example.com", id="email"), + pytest.param("-._~'!*:@,;()", id="safe-rfc3986"), + pytest.param("%<>[]{}|^", id="unsafe-rfc3986"), + ], +) +def test_non_word_chars_route(req): + # GIVEN + app = ApiGatewayResolver() + event = deepcopy(LOAD_GW_EVENT) + + # WHEN + @app.get("/accounts/") + def get_account(account_id: str): + assert account_id == f"{req}" + + # THEN + event["resource"] = "/accounts/{account_id}" + event["path"] = f"/accounts/{req}" + + ret = app.resolve(event, None) + assert ret["statusCode"] == 200