diff --git a/tests/tests.py b/tests/tests.py index 8cc632966..07a38c41d 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -777,7 +777,7 @@ def test_wsgi_event_handle_space_in_xforwardedfor(self): def test_wsgi_path_info_unquoted(self): event = { - "body": {}, + "body": None, "headers": {}, "pathParameters": {}, "path": "/path%3A1", # encoded /path:1 @@ -790,7 +790,7 @@ def test_wsgi_path_info_unquoted(self): def test_wsgi_latin1(self): event = { - "body": {}, + "body": None, "headers": {}, "pathParameters": {}, "path": "/path/%E4%BB%8A%E6%97%A5%E3%81%AF", @@ -806,7 +806,7 @@ def test_wsgi_latin1(self): def test_wsgi_logging(self): # event = { - # "body": {}, + # "body": None, # "headers": {}, # "params": { # "parameter_1": "asdf1", @@ -873,7 +873,7 @@ def test_wsgi_multipart(self): # event = {'body': 'LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS03Njk1MjI4NDg0Njc4MTc2NTgwNjMwOTYxDQpDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9Im15c3RyaW5nIg0KDQpkZGQNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tNzY5NTIyODQ4NDY3ODE3NjU4MDYzMDk2MS0tDQo=', 'headers': {'Content-Type': 'multipart/form-data; boundary=---------------------------7695228484678176580630961', 'Via': '1.1 38205a04d96d60185e88658d3185ccee.cloudfront.net (CloudFront)', 'Accept-Language': 'en-US,en;q=0.5', 'Accept-Encoding': 'gzip, deflate, br', 'CloudFront-Is-SmartTV-Viewer': 'false', 'CloudFront-Forwarded-Proto': 'https', 'X-Forwarded-For': '71.231.27.57, 104.246.180.51', 'CloudFront-Viewer-Country': 'US', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:45.0) Gecko/20100101 Firefox/45.0', 'Host': 'xo2z7zafjh.execute-api.us-east-1.amazonaws.com', 'X-Forwarded-Proto': 'https', 'Cookie': 'zappa=AQ4', 'CloudFront-Is-Tablet-Viewer': 'false', 'X-Forwarded-Port': '443', 'Referer': 'https://xo8z7zafjh.execute-api.us-east-1.amazonaws.com/former/post', 'CloudFront-Is-Mobile-Viewer': 'false', 'X-Amz-Cf-Id': '31zxcUcVyUxBOMk320yh5NOhihn5knqrlYQYpGGyOngKKwJb0J0BAQ==', 'CloudFront-Is-Desktop-Viewer': 'true'}, 'params': {'parameter_1': 'post'}, 'method': 'POST', 'query': {}} event = { - "body": "LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS03Njk1MjI4NDg0Njc4MTc2NTgwNjMwOTYxDQpDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9Im15c3RyaW5nIg0KDQpkZGQNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tNzY5NTIyODQ4NDY3ODE3NjU4MDYzMDk2MS0tDQo=", + "body": "LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS03Njk1MjI4NDg0Njc4MTc2NTgwNjMwOTYxDQpDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9Im15c3RyaW5nIg0KDQpkZGQNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tNzY5NTIyODQ4NDY3ODE3NjU4MDYzMDk2MS0tDQo=".encode(), "resource": "/", "requestContext": { "resourceId": "6cqjw9qu0b", @@ -2213,7 +2213,7 @@ def test_flask_logging_bug(self): https://github.com/Miserlou/Zappa/issues/283 """ event = { - "body": {}, + "body": None, "headers": {}, "pathParameters": {}, "path": "/", @@ -2653,7 +2653,7 @@ def test_no_runtimeerror_when_in_docker(self, *_): def test_wsgi_query_string_unquoted(self): event = { - "body": {}, + "body": None, "headers": {}, "pathParameters": {}, "path": "/path/path1", diff --git a/tests/tests_middleware.py b/tests/tests_middleware.py index 0ec39818d..d65a6534d 100644 --- a/tests/tests_middleware.py +++ b/tests/tests_middleware.py @@ -1,6 +1,7 @@ # -*- coding: utf8 -*- import sys import unittest +from io import BytesIO from zappa.middleware import ZappaWSGIMiddleware, all_casings from zappa.wsgi import create_wsgi_request @@ -78,7 +79,7 @@ def test_wsgi_authorizer_handling(self): "queryStringParameters": None, "path": "/v1/runs", "params": {}, - "body": {}, + "body": None, "headers": {"Content-Type": "application/json"}, "pathParameters": {"proxy": "v1/runs"}, "requestContext": {"authorizer": {"principalId": "user1"}}, @@ -94,7 +95,7 @@ def test_wsgi_authorizer_handling(self): "queryStringParameters": None, "path": "/v1/runs", "params": {}, - "body": {}, + "body": None, "headers": {"Content-Type": "application/json"}, "pathParameters": {"proxy": "v1/runs"}, "requestContext": {"authorizer": {"principalId": ""}}, @@ -111,7 +112,7 @@ def test_wsgi_authorizer_handling(self): "queryStringParameters": None, "path": "/v1/runs", "params": {}, - "body": {}, + "body": None, "headers": {"Content-Type": "application/json"}, "pathParameters": {"proxy": "v1/runs"}, "requestContext": {}, @@ -128,7 +129,7 @@ def test_wsgi_authorizer_handling(self): "queryStringParameters": None, "path": "/v1/runs", "params": {}, - "body": {}, + "body": None, "headers": {"Content-Type": "application/json"}, "pathParameters": {"proxy": "v1/runs"}, "requestContext": {"authorizer": {}}, @@ -146,7 +147,7 @@ def test_wsgi_map_context_headers_handling(self): "queryStringParameters": None, "path": "/v1/runs", "params": {}, - "body": {}, + "body": None, "headers": {"Content-Type": "application/json"}, "pathParameters": {"proxy": "v1/runs"}, "requestContext": { @@ -170,7 +171,7 @@ def test_wsgi_map_context_headers_handling(self): "queryStringParameters": None, "path": "/v1/runs", "params": {}, - "body": {}, + "body": None, "headers": {"Content-Type": "application/json"}, "pathParameters": {"proxy": "v1/runs"}, "requestContext": { @@ -207,6 +208,16 @@ def test_wsgi_map_context_headers_handling(self): self.assertNotIn("HTTP_INVALIDVALUE", environ) self.assertNotIn("HTTP_OTHERINVALID", environ) + def test_wsgi_input_as_file_like_object(self): + event = { + "httpMethod": "GET", + "path": "/v1/runs", + "body": None, + } + + environ = create_wsgi_request(event, script_name="http://zappa.com/", trailing_slash=False) + self.assertEqual(type(environ["wsgi.input"]), BytesIO) + def test_should_allow_empty_query_params(self): event = { "httpMethod": "GET", @@ -214,7 +225,7 @@ def test_should_allow_empty_query_params(self): "multiValueQueryStringParameters": {}, "path": "/v1/runs", "params": {}, - "body": {}, + "body": None, "headers": {"Content-Type": "application/json"}, "pathParameters": {"proxy": "v1/runs"}, "requestContext": { @@ -244,7 +255,7 @@ def test_should_handle_multi_value_query_string_params(self): "multiValueQueryStringParameters": {"foo": [1, 2]}, "path": "/v1/runs", "params": {}, - "body": {}, + "body": None, "headers": {"Content-Type": "application/json"}, "pathParameters": {"proxy": "v1/runs"}, "requestContext": { diff --git a/tests/tests_placebo.py b/tests/tests_placebo.py index ef714d020..d55cf9e76 100644 --- a/tests/tests_placebo.py +++ b/tests/tests_placebo.py @@ -3,6 +3,7 @@ import random import string import unittest +from io import BytesIO import mock @@ -219,7 +220,7 @@ def test_handler(self, session): self.assertEqual(os.environ["hello"], "world") event = { - "body": {}, + "body": None, "headers": {}, "params": { "parameter_1": "asdf1", @@ -416,7 +417,7 @@ def test_handler(self, session): { "messageId": "c80e8021-a70a-42c7-a470-796e1186f753", "receiptHandle": "AQEBJQ+/u6NsnT5t8Q/VbVxgdUl4TMKZ5FqhksRdIQvLBhwNvADoBxYSOVeCBXdnS9P+erlTtwEALHsnBXynkfPLH3BOUqmgzP25U8kl8eHzq6RAlzrSOfTO8ox9dcp6GLmW33YjO3zkq5VRYyQlJgLCiAZUpY2D4UQcE5D1Vm8RoKfbE+xtVaOctYeINjaQJ1u3mWx9T7tork3uAlOe1uyFjCWU5aPX/1OHhWCGi2EPPZj6vchNqDOJC/Y2k1gkivqCjz1CZl6FlZ7UVPOx3AMoszPuOYZ+Nuqpx2uCE2MHTtMHD8PVjlsWirt56oUr6JPp9aRGo6bitPIOmi4dX0FmuMKD6u/JnuZCp+AXtJVTmSHS8IXt/twsKU7A+fiMK01NtD5msNgVPoe9JbFtlGwvTQ==", - "body": '{"foo":"bar"}', + "body": BytesIO('{"foo":"bar"}'.encode()), "attributes": { "ApproximateReceiveCount": "3", "SentTimestamp": "1529104986221", diff --git a/zappa/wsgi.py b/zappa/wsgi.py index ecbcec251..70333e0ac 100644 --- a/zappa/wsgi.py +++ b/zappa/wsgi.py @@ -106,7 +106,12 @@ def create_wsgi_request( "SERVER_PROTOCOL": str("HTTP/1.1"), "wsgi.version": (1, 0), "wsgi.url_scheme": headers.get("X-Forwarded-Proto", "http"), - "wsgi.input": body, + # This must be Bytes or None + # - https://docs.djangoproject.com/en/4.2/releases/4.2/#miscellaneous + # - https://wsgi.readthedocs.io/en/latest/definitions.html#envvar-wsgi.input + # > Manually instantiated WSGIRequest objects must be provided + # > a file-like object for wsgi.input. + "wsgi.input": BytesIO(body), "wsgi.errors": sys.stderr, "wsgi.multiprocess": False, "wsgi.multithread": False, @@ -129,8 +134,6 @@ def create_wsgi_request( if "Content-Type" in headers: environ["CONTENT_TYPE"] = headers["Content-Type"] - # This must be Bytes or None - environ["wsgi.input"] = BytesIO(body) if body: environ["CONTENT_LENGTH"] = str(len(body)) else: