Skip to content

Commit

Permalink
Fix query string parameter encoding (#187)
Browse files Browse the repository at this point in the history
Fixes #186.
  • Loading branch information
adamchainz authored Oct 12, 2020
1 parent afaf2e5 commit 41a8741
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 14 deletions.
6 changes: 5 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ History
=======

* Support Python 3.9.
* Fix query string parameter encoding so that symbols are correctly re-encoded
for WSGI, for API Gateway format version 1
(`Issue #186 <https://github.com/adamchainz/apig-wsgi/pull/186>`__).

2.9.0 (2020-10-12)
------------------
Expand All @@ -11,7 +14,8 @@ History
* Always send ``isBase64Encoded`` in responses, as per the AWS documentation.
* Support `format version
2 <https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html>`,
which was introduced by API Gateway for “HTTP API's”.
which was introduced by API Gateway for “HTTP API's”
(`Issue #124 <https://github.com/adamchainz/apig-wsgi/pull/124>`__)..
* ``binary_support`` now defaults to ``None``, which means that it will
automatically enable binary support for format version 2 events.

Expand Down
14 changes: 7 additions & 7 deletions src/apig_wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from base64 import b64decode, b64encode
from collections import defaultdict
from io import BytesIO
from urllib.parse import urlencode

__all__ = ("make_lambda_handler",)

Expand Down Expand Up @@ -87,14 +88,13 @@ def get_environ_v1(event, context, binary_support):

# Multi-value query strings need explicit activation on ALB
if "multiValueQueryStringParameters" in event:
# may be None when testing on console
multi_params = event["multiValueQueryStringParameters"] or {}
environ["QUERY_STRING"] = urlencode(
# may be None when testing on console
event["multiValueQueryStringParameters"] or (),
doseq=True,
)
else:
single_params = event.get("queryStringParameters") or {}
multi_params = {key: [value] for key, value in single_params.items()}
environ["QUERY_STRING"] = "&".join(
"{}={}".format(key, val) for (key, vals) in multi_params.items() for val in vals
)
environ["QUERY_STRING"] = urlencode(event.get("queryStringParameters") or ())

# Multi-value headers need explicit activation on ALB
if "multiValueHeaders" in event:
Expand Down
26 changes: 20 additions & 6 deletions tests/test_apig_wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,19 +328,19 @@ def test_querystring_one_single(self, simple_app):

assert simple_app.environ["QUERY_STRING"] == "foo=bar"

def test_querystring_encoding_value(self, simple_app):
event = make_v1_event(qs_params={"foo": ["a%20bar"]})
def test_querystring_encoding_plus_value(self, simple_app):
event = make_v1_event(qs_params={"a": ["b+c"]}, qs_params_multi=False)

simple_app.handler(event, None)

assert simple_app.environ["QUERY_STRING"] == "foo=a%20bar"
assert simple_app.environ["QUERY_STRING"] == "a=b%2Bc"

def test_querystring_encoding_key(self, simple_app):
event = make_v1_event(qs_params={"a%20foo": ["bar"]})
def test_querystring_encoding_plus_key(self, simple_app):
event = make_v1_event(qs_params={"a+b": ["c"]}, qs_params_multi=False)

simple_app.handler(event, None)

assert simple_app.environ["QUERY_STRING"] == "a%20foo=bar"
assert simple_app.environ["QUERY_STRING"] == "a%2Bb=c"

def test_querystring_multi(self, simple_app):
event = make_v1_event(qs_params={"foo": ["bar", "baz"]})
Expand All @@ -349,6 +349,20 @@ def test_querystring_multi(self, simple_app):

assert simple_app.environ["QUERY_STRING"] == "foo=bar&foo=baz"

def test_querystring_multi_encoding_plus_value(self, simple_app):
event = make_v1_event(qs_params={"a": ["b+c", "d"]})

simple_app.handler(event, None)

assert simple_app.environ["QUERY_STRING"] == "a=b%2Bc&a=d"

def test_querystring_multi_encoding_plus_key(self, simple_app):
event = make_v1_event(qs_params={"a+b": ["c"]})

simple_app.handler(event, None)

assert simple_app.environ["QUERY_STRING"] == "a%2Bb=c"

def test_plain_header(self, simple_app):
event = make_v1_event(headers={"Test-Header": ["foobar"]})

Expand Down

0 comments on commit 41a8741

Please sign in to comment.