From 9b8159c4531565894e5b6da3008ad879ecec7269 Mon Sep 17 00:00:00 2001 From: Ethan Dalool Date: Tue, 5 Jan 2021 01:27:14 -0800 Subject: [PATCH] Improve gzip decision logic. Previous called get_data which is dangerous for large but indeterminate response sizes, and the bail chain was more difficult to reason about than a simple should_gzip true/false. --- frontends/etiquette_flask/backend/common.py | 53 ++++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/frontends/etiquette_flask/backend/common.py b/frontends/etiquette_flask/backend/common.py index 0cac7fb..47b4827 100644 --- a/frontends/etiquette_flask/backend/common.py +++ b/frontends/etiquette_flask/backend/common.py @@ -80,29 +80,46 @@ def before_request(): if site.localhost_only and ip != '127.0.0.1': flask.abort(403) -gzip_minimum_size = 500 -gzip_maximum_size = 5 * 2**20 +gzip_minimum_size = 500 * bytestring.BYTE +gzip_maximum_size = 5 * bytestring.MIBIBYTE gzip_level = 3 +def should_gzip(response): + if response.direct_passthrough: + return False + + if response.status_code < 200: + return False + + if response.status_code >= 300: + return False + + content_length = response.headers.get('Content-Length', None) + if content_length is not None and int(content_length) > gzip_maximum_size: + return False + + if content_length is not None and int(content_length) < gzip_minimum_size: + return False + + if 'Content-Encoding' in response.headers: + return False + + accept_encoding = request.headers.get('Accept-Encoding', '') + if 'gzip' not in accept_encoding.lower(): + return False + + content_type = response.headers.get('Content-Type', '') + if not (content_type.startswith('application/json') or content_type.startswith('text/')): + return False + + return True + @site.after_request def after_request(response): - ''' - Thank you close.io. - https://github.com/closeio/Flask-gzip - ''' - accept_encoding = request.headers.get('Accept-Encoding', '') - - bail = False - bail = bail or response.status_code < 200 - bail = bail or response.status_code >= 300 - bail = bail or response.direct_passthrough - bail = bail or int(response.headers.get('Content-Length', 0)) > gzip_maximum_size - bail = bail or len(response.get_data()) < gzip_minimum_size - bail = bail or 'gzip' not in accept_encoding.lower() - bail = bail or 'Content-Encoding' in response.headers - - if bail: + if not should_gzip(response): return response + ### + gzip_buffer = io.BytesIO() gzip_file = gzip.GzipFile(mode='wb', compresslevel=gzip_level, fileobj=gzip_buffer) gzip_file.write(response.get_data())