Skip to content

Commit ef93aff

Browse files
nathangloverkhamaileon
authored andcommitted
Kludex#178 alb url double encoding (Kludex#184)
1 parent 62e9d60 commit ef93aff

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

mangum/handlers/aws_alb.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,42 @@ class AwsAlb(AbstractHandler):
3535

3636
TYPE = "AWS_ALB"
3737

38+
def encode_query_string(self) -> bytes:
39+
"""
40+
Encodes the queryStringParameters.
41+
The parameters must be decoded, and then encoded again to prevent double
42+
encoding.
43+
44+
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html # noqa: E501
45+
"If the query parameters are URL-encoded, the load balancer does not decode
46+
them. You must decode them in your Lambda function."
47+
48+
Issue: https://github.com/jordaneremieff/mangum/issues/178
49+
"""
50+
51+
params = self.trigger_event.get("multiValueQueryStringParameters")
52+
if not params:
53+
params = self.trigger_event.get("queryStringParameters")
54+
if not params:
55+
return b"" # No query parameters, exit early with an empty byte string.
56+
57+
# Loop through the query parameters, unquote each key and value and append the
58+
# pair as a tuple to the query list. If value is a list or a tuple, loop
59+
# through the nested struture and unqote.
60+
query = []
61+
for key, value in params.items():
62+
if isinstance(value, (tuple, list)):
63+
for v in value:
64+
query.append(
65+
(urllib.parse.unquote_plus(key), urllib.parse.unquote_plus(v))
66+
)
67+
else:
68+
query.append(
69+
(urllib.parse.unquote_plus(key), urllib.parse.unquote_plus(value))
70+
)
71+
72+
return urllib.parse.urlencode(query).encode()
73+
3874
@property
3975
def request(self) -> Request:
4076
event = self.trigger_event
@@ -46,9 +82,7 @@ def request(self) -> Request:
4682
source_ip = headers.get("x-forwarded-for", "")
4783
path = event["path"]
4884
http_method = event["httpMethod"]
49-
query_string = urllib.parse.urlencode(
50-
event.get("queryStringParameters", {}), doseq=True
51-
).encode()
85+
query_string = self.encode_query_string()
5286

5387
server_name = headers.get("host", "mangum")
5488
if ":" not in server_name:

tests/handlers/test_aws_alb.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def get_mock_aws_alb_event(
2020
},
2121
"httpMethod": method,
2222
"path": path,
23-
"queryStringParameters": multi_value_query_parameters
23+
"multiValueQueryStringParameters": multi_value_query_parameters
2424
if multi_value_query_parameters
2525
else {},
2626
"headers": {
@@ -61,7 +61,13 @@ def test_aws_alb_basic():
6161
},
6262
"httpMethod": "GET",
6363
"path": "/lambda",
64-
"queryStringParameters": {"query": "1234ABCD"},
64+
"queryStringParameters": {
65+
"q1": "1234ABCD",
66+
"q2": "b c", # not encoded
67+
"q3": "b%20c", # encoded
68+
"q4": "/some/path/", # not encoded
69+
"q5": "%2Fsome%2Fpath%2F", # encoded
70+
},
6571
"headers": {
6672
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
6773
"image/webp,image/apng,*/*;q=0.8",
@@ -116,7 +122,7 @@ def test_aws_alb_basic():
116122
"http_version": "1.1",
117123
"method": "GET",
118124
"path": "/lambda",
119-
"query_string": b"query=1234ABCD",
125+
"query_string": b"q1=1234ABCD&q2=b+c&q3=b+c&q4=%2Fsome%2Fpath%2F&q5=%2Fsome%2Fpath%2F", # noqa: E501
120126
"raw_path": None,
121127
"root_path": "",
122128
"scheme": "http",

0 commit comments

Comments
 (0)