diff --git a/docs/index.rst b/docs/index.rst index 5ed9621..6bd7458 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -229,6 +229,9 @@ uploading assets to S3. your S3 bucket to force all files to upload again. `S3_CACHE_CONTROL` **Deprecated**. Please use `S3_HEADERS` instead. `S3_USE_CACHE_CONTROL` **Deprecated**. Please use `S3_HEADERS` instead. +`S3_GZIP` Compress all assets using GZIP and set the + corresponding Content-Type and Content-Encoding + headers on the S3 files. =========================== =================================================== .. _debug: http://flask.pocoo.org/docs/config/#configuration-basics diff --git a/flask_s3.py b/flask_s3.py index 67dc89f..a4e80b9 100644 --- a/flask_s3.py +++ b/flask_s3.py @@ -3,6 +3,12 @@ import json import logging import os import re +import gzip +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO +import mimetypes from collections import defaultdict import boto3 @@ -175,6 +181,7 @@ def _static_folder_path(static_url, static_folder, static_asset): def _write_files(s3, app, static_url_loc, static_folder, files, bucket, ex_keys=None, hashes=None): """ Writes all the files inside a static folder to S3. """ + should_gzip = app.config.get('S3_GZIP') new_hashes = [] static_folder_rel = _path_to_relative_url(static_folder) for file_path in files: @@ -206,11 +213,34 @@ def _write_files(s3, app, static_url_loc, static_folder, files, bucket, for header, value in headers.iteritems(): h[header] = value + if should_gzip: + h["content-encoding"] = "gzip" + if "content-type" not in h: + # When we use GZIP we have to explicitly set the content type + (mimetype, encoding) = mimetypes.guess_type(file_path, + False) + if mimetype: + h["content-type"] = mimetype + else: + logger.warn("Unable to detect mimetype for %s" % + file_path) + with open(file_path) as fp: metadata, params = split_metadata_params(merge_two_dicts(app.config['S3_HEADERS'], h)) + if should_gzip: + compressed = StringIO() + z = gzip.GzipFile(os.path.basename(file_path), 'wb', 9, + compressed) + z.write(fp.read()) + z.close() + + data = compressed.getvalue() + else: + data = fp.read() + s3.put_object(Bucket=bucket, Key=key_name, - Body=fp.read(), + Body=data, ACL="public-read", Metadata=metadata, **params) @@ -370,7 +400,8 @@ class FlaskS3(object): ('S3_HEADERS', {}), ('S3_FILEPATH_HEADERS', {}), ('S3_ONLY_MODIFIED', False), - ('S3_URL_STYLE', 'host')] + ('S3_URL_STYLE', 'host'), + ('S3_GZIP', False)] for k, v in defaults: app.config.setdefault(k, v)