diff --git a/tests/test_binary_support_settings.py b/tests/test_binary_support_settings.py new file mode 100644 index 000000000..adb257d55 --- /dev/null +++ b/tests/test_binary_support_settings.py @@ -0,0 +1,12 @@ +API_STAGE = "dev" +APP_FUNCTION = "app" +APP_MODULE = "tests.test_wsgi_binary_support_app" +BINARY_SUPPORT = True +CONTEXT_HEADER_MAPPINGS = {} +DEBUG = "True" +DJANGO_SETTINGS = None +DOMAIN = "api.example.com" +ENVIRONMENT_VARIABLES = {} +LOG_LEVEL = "DEBUG" +PROJECT_NAME = "binary_support_settings" +COGNITO_TRIGGER_MAPPING = {} diff --git a/tests/test_handler.py b/tests/test_handler.py index eecb3dcab..ce38278b3 100644 --- a/tests/test_handler.py +++ b/tests/test_handler.py @@ -3,6 +3,7 @@ from mock import Mock +from tests.utils import is_base64 from zappa.handler import LambdaHandler from zappa.utilities import merge_headers @@ -225,6 +226,66 @@ def test_exception_handler_on_web_request(self): self.assertEqual(response["statusCode"], 500) mocked_exception_handler.assert_called() + def test_wsgi_script_binary_support_base64_behavior(self): + """ + With Binary Support enabled, response mimetypes that are not text/* or application/json will be base64 encoded + """ + lh = LambdaHandler("tests.test_binary_support_settings") + + text_plain_event = { + "body": "", + "resource": "/{proxy+}", + "requestContext": {}, + "queryStringParameters": {}, + "headers": { + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + }, + "pathParameters": {"proxy": "return/request/url"}, + "httpMethod": "GET", + "stageVariables": {}, + "path": "/textplain_mimetype_response1", + } + + response = lh.handler(text_plain_event, None) + + self.assertEqual(response["statusCode"], 200) + self.assertNotIn("isBase64Encoded", response) + self.assertFalse(is_base64(response["body"])) + + text_arbitrary_event = { + **text_plain_event, + **{"path": "/textarbitrary_mimetype_response1"}, + } + + response = lh.handler(text_arbitrary_event, None) + + self.assertEqual(response["statusCode"], 200) + self.assertNotIn("isBase64Encoded", response) + self.assertFalse(is_base64(response["body"])) + + application_json_event = { + **text_plain_event, + **{"path": "/json_mimetype_response1"}, + } + + response = lh.handler(application_json_event, None) + + self.assertEqual(response["statusCode"], 200) + self.assertNotIn("isBase64Encoded", response) + self.assertFalse(is_base64(response["body"])) + + arbitrary_binary_event = { + **text_plain_event, + **{"path": "/arbitrarybinary_mimetype_response1"}, + } + + response = lh.handler(arbitrary_binary_event, None) + + self.assertEqual(response["statusCode"], 200) + self.assertIn("isBase64Encoded", response) + self.assertTrue(response["isBase64Encoded"]) + self.assertTrue(is_base64(response["body"])) + def test_wsgi_script_on_cognito_event_request(self): """ Ensure that requests sent by cognito behave sensibly diff --git a/tests/test_wsgi_binary_support_app.py b/tests/test_wsgi_binary_support_app.py new file mode 100644 index 000000000..ef0f62287 --- /dev/null +++ b/tests/test_wsgi_binary_support_app.py @@ -0,0 +1,31 @@ +### +# This test application exists to confirm how Zappa handles WSGI application +# _responses_ when Binary Support is enabled. +### + +import io +import json + +from flask import Flask, Response, send_file + +app = Flask(__name__) + + +@app.route("/textplain_mimetype_response1", methods=["GET"]) +def text_mimetype_response_1(): + return Response(response="OK", mimetype="text/plain") + + +@app.route("/textarbitrary_mimetype_response1", methods=["GET"]) +def text_mimetype_response_2(): + return Response(response="OK", mimetype="text/arbitary") + + +@app.route("/json_mimetype_response1", methods=["GET"]) +def json_mimetype_response_1(): + return Response(response=json.dumps({"some": "data"}), mimetype="application/json") + + +@app.route("/arbitrarybinary_mimetype_response1", methods=["GET"]) +def arbitrary_mimetype_response_1(): + return Response(response=b"some binary data", mimetype="arbitrary/binary_mimetype") diff --git a/tests/utils.py b/tests/utils.py index 31453e0ac..9a0f74943 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,3 +1,4 @@ +import base64 import functools import os from contextlib import contextmanager @@ -74,3 +75,14 @@ def stub_open(*args, **kwargs): with patch("__builtin__.open", stub_open): yield mock_open, mock_file + + +def is_base64(test_string: str) -> bool: + # Taken from https://stackoverflow.com/a/45928164/3200002 + try: + return ( + base64.b64encode(base64.b64decode(test_string)).decode("utf-8") + == test_string + ) + except Exception: + return False