Skip to content

Commit

Permalink
Use Content-Encoding to identify if data is binary
Browse files Browse the repository at this point in the history
When using _whitenoise_ for caching, which provides compression, binary types
may include mimetypes, "text/", "application/json":

- response.mimetype.startswith("text/")
- response.mimetype == "application/json"

Assuming that Content-Encoding will be set (as whitenoise apparently does)
this allows compression to be applied by the application for "text/" and
"application/json".

About Content-Encoding:
developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding

---

The above commit message and functional code change to zappa/handler.py was
written by GH user @monkut and a PR was provided with
Miserlou/Zappa#2170.

That PR was not merged in before the fork from Miserlou/zappa to Zappa/zappa.

This commit copies the code from that PR, adds a comment line referencing the
new migrated issue, and additionally adds tests to confirm behavior.

Co-authored-by: monkut <[email protected]>
  • Loading branch information
Quidge and monkut committed Apr 29, 2021
1 parent 366cc3c commit 9e99ee7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
18 changes: 18 additions & 0 deletions tests/test_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,24 @@ def test_wsgi_script_binary_support_base64_behavior(self):
self.assertTrue(response['isBase64Encoded'])
self.assertTrue(is_base64(response['body']))

content_encoded_json = {**text_plain_event, **{'path': '/content_encoding_header_json1'}}

response = lh.handler(content_encoded_json, None)

self.assertEqual(response['statusCode'], 200)
self.assertIn('isBase64Encoded', response)
self.assertTrue(response['isBase64Encoded'])
self.assertTrue(is_base64(response['body']))

content_encoded_text_arbitrary = {**text_plain_event, **{'path': '/content_encoding_header_textarbitrary1'}}

response = lh.handler(content_encoded_text_arbitrary, 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
Expand Down
18 changes: 18 additions & 0 deletions tests/test_wsgi_binary_support_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,21 @@ def json_mimetype_response_1():
@app.route('/arbitrarybinary_mimetype_response1', methods=['GET'])
def arbitrary_mimetype_response_1():
return Response(response=b"some binary data", mimetype="arbitrary/binary_mimetype")


@app.route('/content_encoding_header_json1', methods=['GET'])
def response_with_content_encoding_mimetype1():
return Response(
response=json.dumps({'some': 'data'}),
mimetype="application/json",
headers={'Content-Encoding': 'gzip'}
)


@app.route('/content_encoding_header_textarbitrary1', methods=['GET'])
def response_with_content_encoding_mimetype2():
return Response(
response="OK",
mimetype="text/arbitrary",
headers={'Content-Encoding': 'shouldnt_matter'}
)
8 changes: 7 additions & 1 deletion zappa/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,13 @@ def handler(self, event, context):
zappa_returndict.setdefault('statusDescription', response.status)

if response.data:
if settings.BINARY_SUPPORT and \
if settings.BINARY_SUPPORT and response.headers.get("Content-Encoding"):
# We could have a text response that's gzip
# encoded. Therefore, we base-64 encode it.
# Related: https://github.com/zappa/Zappa/issues/908
zappa_returndict['body'] = base64.b64encode(response.data).decode('utf-8')
zappa_returndict["isBase64Encoded"] = True
elif settings.BINARY_SUPPORT and \
not response.mimetype.startswith("text/") \
and response.mimetype != "application/json":
zappa_returndict['body'] = base64.b64encode(response.data).decode('utf-8')
Expand Down

0 comments on commit 9e99ee7

Please sign in to comment.