From e9530c863fa0e6f933cffa5effa3ce5227abfc5a Mon Sep 17 00:00:00 2001 From: Stephan Huber Date: Fri, 8 Apr 2022 11:07:11 +0200 Subject: [PATCH 1/3] fix(parameters): allow whitespace in routes' path parmeter --- aws_lambda_powertools/event_handler/api_gateway.py | 2 +- tests/functional/event_handler/test_api_gateway.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 8e4ea866dd1..5d57c645b27 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -26,7 +26,7 @@ _DYNAMIC_ROUTE_PATTERN = r"(<\w+>)" _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 +_UNSAFE_URI = "%<> \[\]{}|^" # noqa: W605 _NAMED_GROUP_BOUNDARY_PATTERN = fr"(?P\1[{_SAFE_URI}{_UNSAFE_URI}\\w]+)" diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index c21cd352961..50e5cd6fcfd 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -688,12 +688,12 @@ def test_similar_dynamic_routes(): # r'^/accounts/(?P\\w+\\b)$' # noqa: E800 @app.get("/accounts/") def get_account(account_id: str): - assert account_id == "single_account" + assert account_id in ("single_account", "single account") # r'^/accounts/(?P\\w+\\b)/source_networks$' # noqa: E800 @app.get("/accounts//source_networks") def get_account_networks(account_id: str): - assert account_id == "nested_account" + assert account_id in ("nested_account", "nested account") # r'^/accounts/(?P\\w+\\b)/source_networks/(?P\\w+\\b)$' # noqa: E800 @app.get("/accounts//source_networks/") @@ -706,10 +706,18 @@ def get_network_account(account_id: str, network_id: str): event["path"] = "/accounts/single_account" app.resolve(event, None) + event["resource"] = "/accounts/{account_id}" + event["path"] = "/accounts/single account" + app.resolve(event, None) + event["resource"] = "/accounts/{account_id}/source_networks" event["path"] = "/accounts/nested_account/source_networks" app.resolve(event, None) + event["resource"] = "/accounts/{account_id}/source_networks" + event["path"] = "/accounts/nested account/source_networks" + app.resolve(event, None) + event["resource"] = "/accounts/{account_id}/source_networks/{network_id}" event["path"] = "/accounts/nested_account/source_networks/network" app.resolve(event, {}) From 45a75885442ee8344c1421116cdb92aaafb131c6 Mon Sep 17 00:00:00 2001 From: Stephan Huber Date: Fri, 8 Apr 2022 12:47:23 +0200 Subject: [PATCH 2/3] pull whitespace path param in own test --- .../event_handler/test_api_gateway.py | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index 50e5cd6fcfd..82401a81908 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -688,12 +688,12 @@ def test_similar_dynamic_routes(): # r'^/accounts/(?P\\w+\\b)$' # noqa: E800 @app.get("/accounts/") def get_account(account_id: str): - assert account_id in ("single_account", "single account") + assert account_id == "single_account" # r'^/accounts/(?P\\w+\\b)/source_networks$' # noqa: E800 @app.get("/accounts//source_networks") def get_account_networks(account_id: str): - assert account_id in ("nested_account", "nested account") + assert account_id == "nested_account" # r'^/accounts/(?P\\w+\\b)/source_networks/(?P\\w+\\b)$' # noqa: E800 @app.get("/accounts//source_networks/") @@ -706,20 +706,48 @@ def get_network_account(account_id: str, network_id: str): event["path"] = "/accounts/single_account" app.resolve(event, None) - event["resource"] = "/accounts/{account_id}" - event["path"] = "/accounts/single account" - app.resolve(event, None) - event["resource"] = "/accounts/{account_id}/source_networks" event["path"] = "/accounts/nested_account/source_networks" app.resolve(event, None) + event["resource"] = "/accounts/{account_id}/source_networks/{network_id}" + event["path"] = "/accounts/nested_account/source_networks/network" + app.resolve(event, {}) + + +def test_similar_dynamic_routes_with_whitespaces(): + # GIVEN + app = ApiGatewayResolver() + event = deepcopy(LOAD_GW_EVENT) + + # WHEN + # r'^/accounts/(?P\\w+\\b)$' # noqa: E800 + @app.get("/accounts/") + def get_account(account_id: str): + assert account_id == "single account" + + # r'^/accounts/(?P\\w+\\b)/source_networks$' # noqa: E800 + @app.get("/accounts//source_networks") + def get_account_networks(account_id: str): + assert account_id == "nested account" + + # r'^/accounts/(?P\\w+\\b)/source_networks/(?P\\w+\\b)$' # noqa: E800 + @app.get("/accounts//source_networks/") + def get_network_account(account_id: str, network_id: str): + assert account_id == "nested account" + assert network_id == "network 123" + + # THEN + event["resource"] = "/accounts/{account_id}" + event["path"] = "/accounts/single account" + app.resolve(event, None) + event["resource"] = "/accounts/{account_id}/source_networks" event["path"] = "/accounts/nested account/source_networks" app.resolve(event, None) event["resource"] = "/accounts/{account_id}/source_networks/{network_id}" - event["path"] = "/accounts/nested_account/source_networks/network" + event["path"] = "/accounts/nested account/source_networks/network 123" app.resolve(event, {}) From 92086676271c2577d0c471b8935da1e418cc8850 Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Fri, 8 Apr 2022 15:42:24 +0200 Subject: [PATCH 3/3] chore: ensure whitespace yields a successful ret --- tests/functional/event_handler/test_api_gateway.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index 82401a81908..9b5835c8b20 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -740,15 +740,15 @@ def get_network_account(account_id: str, network_id: str): # THEN event["resource"] = "/accounts/{account_id}" event["path"] = "/accounts/single account" - app.resolve(event, None) + assert app.resolve(event, {})["statusCode"] == 200 event["resource"] = "/accounts/{account_id}/source_networks" event["path"] = "/accounts/nested account/source_networks" - app.resolve(event, None) + assert app.resolve(event, {})["statusCode"] == 200 event["resource"] = "/accounts/{account_id}/source_networks/{network_id}" event["path"] = "/accounts/nested account/source_networks/network 123" - app.resolve(event, {}) + assert app.resolve(event, {})["statusCode"] == 200 @pytest.mark.parametrize(