Bug: HTTP API with router event handler fails on whitespace in path parameter
See original GitHub issueExpected Behaviour
Calling GET /pets/{name}
or GET /pets/{name}/vets
should return a successful response with status code 200 when called with “Chester Mall” or “Chester%20Mall” (without ") as name
. API Gateway will already decode encoded whitespaces as you can see in the example events.
GET /pets/Fiffi
{
"version": "2.0",
"routeKey": "GET /pets/{name}",
"rawPath": "/pets/Fiffi",
"rawQueryString": "",
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"cache-control": "no-cache",
"content-length": "0",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"requestContext": {
"http": {
"method": "GET",
"path": "/pets/Fiffi",
"protocol": "HTTP/1.1"
},
"requestId": "QQCtFipSIAMEPNQ=",
"routeKey": "GET /pets/{name}",
"stage": "$default",
"time": "08/Apr/2022:07:31:05 +0000",
"timeEpoch": 1649403065999
},
"pathParameters": {
"name": "Fiffi"
},
"isBase64Encoded": false
}
GET /pets/Fiffi/vets
{
"version": "2.0",
"routeKey": "GET /pets/{name}/vets",
"rawPath": "/pets/Fiffi/vets",
"rawQueryString": "",
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"cache-control": "no-cache",
"content-length": "0",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"requestContext": {
"http": {
"method": "GET",
"path": "/pets/Fiffi/vets",
"protocol": "HTTP/1.1"
},
"requestId": "QQGmWiEcoAMEPqA=",
"routeKey": "GET /pets/{name}/vets",
"stage": "$default",
"time": "08/Apr/2022:07:57:41 +0000",
"timeEpoch": 1649404661221
},
"pathParameters": {
"name": "Fiffi"
},
"isBase64Encoded": false
}
GET /pets/Chester Mall
{
"version": "2.0",
"routeKey": "GET /pets/{name}",
"rawPath": "/pets/Chester Mall",
"rawQueryString": "",
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"cache-control": "no-cache",
"content-length": "0",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"requestContext": {
"http": {
"method": "GET",
"path": "/pets/Chester Mall",
"protocol": "HTTP/1.1"
},
"requestId": "QQCu1ioiIAMEPlg=",
"routeKey": "GET /pets/{name}",
"stage": "$default",
"time": "08/Apr/2022:07:31:17 +0000",
"timeEpoch": 1649403077140
},
"pathParameters": {
"name": "Chester Mall"
},
"isBase64Encoded": false
}
GET /pets/Chester Mall/vets
{
"version": "2.0",
"routeKey": "GET /pets/{name}/vets",
"rawPath": "/pets/Chester Mall/vets",
"rawQueryString": "",
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"cache-control": "no-cache",
"content-length": "0"
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"requestContext": {
"http": {
"method": "GET",
"path": "/pets/Chester Mall/vets",
"protocol": "HTTP/1.1"
},
"requestId": "QQGlpij8oAMEPig=",
"routeKey": "GET /pets/{name}/vets",
"stage": "$default",
"time": "08/Apr/2022:07:57:36 +0000",
"timeEpoch": 1649404656715
},
"pathParameters": {
"name": "Chester Mall"
},
"isBase64Encoded": false
}
Current Behaviour
Instead of a successful response a 404 “Not Found” is returned, with response body
{
"statusCode": 404,
"message": "Not found"
}
Code snippet
import aws_lambda_powertools.event_handler.api_gateway
from aws_lambda_powertools import Logger
from aws_lambda_powertools.event_handler import APIGatewayHttpResolver
from aws_lambda_powertools.logging import correlation_paths
logger = Logger()
app = APIGatewayHttpResolver()
# Add to code to handle whitespaces in path parameters
# aws_lambda_powertools.event_handler.api_gateway._UNSAFE_URI = "%<> \[\]{}|^"
# aws_lambda_powertools.event_handler.api_gateway._NAMED_GROUP_BOUNDARY_PATTERN = rf"(?P\1[{aws_lambda_powertools.event_handler.api_gateway._SAFE_URI}{aws_lambda_powertools.event_handler.api_gateway._UNSAFE_URI}\\w]+)"
@app.get("/pets/<name>")
def get_petname(name):
return {"name": name}
@app.get("/pets/<name>/vets")
def get_petname(name):
return {"pet_name": name, "vets": []}
@logger.inject_lambda_context(
correlation_id_path=correlation_paths.API_GATEWAY_HTTP, log_event=True
)
def lambda_handler(event, context):
return app.resolve(event, context)
Possible Solution
Change the _UNSAFE_URI
constant in aws_lambda_powertools/event_handler/api_gateway from:
_UNSAFE_URI = "%<>\[\]{}|^"
to
# whitespace between <> and \[\]
_UNSAFE_URI = "%<> \[\]{}|^"
Steps to Reproduce
- Deploy reproducible example (https://github.com/sthuber90/aws-python-http-api-project)
- Call
/pets/{name}
and/pets/{name}/vets
endpoint with different names
AWS Lambda Powertools for Python version
latest (layer version 16)
AWS Lambda function runtime
{“label”=>“3.9”}
Packaging format used
{“label”=>“Lambda Layers”}
Debugging logs
timestamp,message
1649404657592,"START RequestId: 46aafc05-0539-4035-83cb-cbd4268db189 Version: $LATEST
"
1649404657592,"2022-04-08 07:57:37,592 aws_lambda_powertools.event_handler.api_gateway [DEBUG] Adding route using rule /pets/<name> and methods: GET
"
1649404657593,"2022-04-08 07:57:37,592 aws_lambda_powertools.event_handler.api_gateway [DEBUG] Adding route using rule /pets/<name>/vets and methods: GET
"
1649404657593,"2022-04-08 07:57:37,593 aws_lambda_powertools.logging.logger [DEBUG] Decorator called with parameters
"
1649404657596,"2022-04-08 07:57:37,595 aws_lambda_powertools.logging.logger [DEBUG] Event received
"
1649404657596,"{""level"":""INFO"",""location"":""decorate:352"",""message"":{""version"":""2.0"",""routeKey"":""GET /pets/{name}/vets"",""rawPath"":""/pets/Chester Mall/vets"",""rawQueryString"":"""",""headers"":{""accept"":""*/*"",""accept-encoding"":""gzip, deflate, br"",""cache-control"":""no-cache"",""content-length"":""0"",""host"":""938e36howc.execute-api.us-east-1.amazonaws.com"",""postman-token"":""d44c4268-96ea-4e76-a308-ac9f2b0eb952"",""user-agent"":""PostmanRuntime/7.29.0"",""x-amzn-trace-id"":""Root=1-624feaf0-4b992fda408853251e402d93"",""x-forwarded-for"":""95.208.248.101"",""x-forwarded-port"":""443"",""x-forwarded-proto"":""https""},""requestContext"":{""http"":{""method"":""GET"",""path"":""/pets/Chester Mall/vets"",""protocol"":""HTTP/1.1"",""userAgent"":""PostmanRuntime/7.29.0""},""requestId"":""QQGlpij8oAMEPig="",""routeKey"":""GET /pets/{name}/vets"",""stage"":""$default"",""time"":""08/Apr/2022:07:57:36 +0000"",""timeEpoch"":1649404656715},""pathParameters"":{""name"":""Chester Mall""},""isBase64Encoded"":false},""timestamp"":""2022-04-08 07:57:37,596+0000"",""service"":""service_undefined"",""cold_start"":true,""function_name"":""aws-python-http-api-project-dev-hello"",""function_memory_size"":""1024"",""function_arn"":""arn:aws:lambda:us-east-1:373270804851:function:aws-python-http-api-project-dev-hello"",""function_request_id"":""46aafc05-0539-4035-83cb-cbd4268db189"",""correlation_id"":""QQGlpij8oAMEPig="",""xray_trace_id"":""1-624feaf0-1f7281e9141a9e970179de6f""}
"
1649404657596,"2022-04-08 07:57:37,596 aws_lambda_powertools.event_handler.api_gateway [DEBUG] Converting event to API Gateway HTTP API contract
"
1649404657596,"2022-04-08 07:57:37,596 aws_lambda_powertools.event_handler.api_gateway [DEBUG] No match found for path /pets/Chester Mall/vets and method GET
"
1649404657597,"END RequestId: 46aafc05-0539-4035-83cb-cbd4268db189
"
1649404657597,"REPORT RequestId: 46aafc05-0539-4035-83cb-cbd4268db189 Duration: 2.12 ms Billed Duration: 3 ms Memory Size: 1024 MB Max Memory Used: 57 MB Init Duration: 531.20 ms
"
1649404661256,"START RequestId: 23baf67a-158c-4246-a950-4eea00efba7d Version: $LATEST
"
1649404661259,"2022-04-08 07:57:41,259 aws_lambda_powertools.logging.logger [DEBUG] Event received
"
1649404661259,"{""level"":""INFO"",""location"":""decorate:352"",""message"":{""version"":""2.0"",""routeKey"":""GET /pets/{name}/vets"",""rawPath"":""/pets/Fiffi/vets"",""rawQueryString"":"""",""headers"":{""accept"":""*/*"",""accept-encoding"":""gzip, deflate, br"",""cache-control"":""no-cache"",""content-length"":""0"",""host"":""938e36howc.execute-api.us-east-1.amazonaws.com"",""postman-token"":""7d1e6998-1851-44fc-b029-279c7cbce941"",""user-agent"":""PostmanRuntime/7.29.0"",""x-amzn-trace-id"":""Root=1-624feaf5-1cf0e266526a59a700b13d68"",""x-forwarded-for"":""95.208.248.101"",""x-forwarded-port"":""443"",""x-forwarded-proto"":""https""},""requestContext"":{""http"":{""method"":""GET"",""path"":""/pets/Fiffi/vets"",""protocol"":""HTTP/1.1"",""userAgent"":""PostmanRuntime/7.29.0""},""requestId"":""QQGmWiEcoAMEPqA="",""routeKey"":""GET /pets/{name}/vets"",""stage"":""$default"",""time"":""08/Apr/2022:07:57:41 +0000"",""timeEpoch"":1649404661221},""pathParameters"":{""name"":""Fiffi""},""isBase64Encoded"":false},""timestamp"":""2022-04-08 07:57:41,259+0000"",""service"":""service_undefined"",""cold_start"":false,""function_name"":""aws-python-http-api-project-dev-hello"",""function_memory_size"":""1024"",""function_arn"":""arn:aws:lambda:us-east-1:373270804851:function:aws-python-http-api-project-dev-hello"",""function_request_id"":""23baf67a-158c-4246-a950-4eea00efba7d"",""correlation_id"":""QQGmWiEcoAMEPqA="",""xray_trace_id"":""1-624feaf5-44c0297c56144d6e0eb23a2f""}
"
1649404661260,"2022-04-08 07:57:41,260 aws_lambda_powertools.event_handler.api_gateway [DEBUG] Converting event to API Gateway HTTP API contract
"
1649404661260,"2022-04-08 07:57:41,260 aws_lambda_powertools.event_handler.api_gateway [DEBUG] Found a registered route. Calling function
"
1649404661260,"2022-04-08 07:57:41,260 aws_lambda_powertools.event_handler.api_gateway [DEBUG] Simple response detected, serializing return before constructing final response
"
1649404661260,"END RequestId: 23baf67a-158c-4246-a950-4eea00efba7d
"
1649404661260,"REPORT RequestId: 23baf67a-158c-4246-a950-4eea00efba7d Duration: 1.85 ms Billed Duration: 2 ms Memory Size: 1024 MB Max Memory Used: 57 MB
"
Issue Analytics
- State:
- Created a year ago
- Reactions:1
- Comments:8 (6 by maintainers)
Top Results From Across the Web
HTTP API with router event handler fails on whitespace in path ...
Bug : HTTP API with router event handler fails on whitespace in path parameter · Expected Behaviour · Current Behaviour · Code snippet...
Read more >awslabs/aws-lambda-powertools-python - v1.25.7 - GitHub
This patch release addresses bugs on Logger, Event Handler REST API, Idempotency, and a static type annotation on middleware factory utility.
Read more >WebAPI route 404's when there is a trailing space in the URL
the route 404's. Now this example may seem silly since browsers trim trailing spaces, but. for a route like 'api/{controller}/{id}/{extrastuff}'.
Read more >Working with routes for HTTP APIs - Amazon API Gateway
Routes direct incoming API requests to backend resources. Routes consist of two parts: an HTTP method and a resource path—for example, GET /pets...
Read more >Bug listing with status RESOLVED with resolution OBSOLETE ...
Bug :1523 - "[IDEA] Offload work by distributing trivial ebuild maintenance to ... fails due to hardcoded library path" status:RESOLVED resolution:OBSOLETE ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
@sthuber90 thanks for the contribution.
@michaelbrewer thanks for trying to shepherd this, but the project maintainers have already validated it and merged it
No worries. Thank you for this great project and the awesome support ❤️