diff --git a/.gitignore b/.gitignore index 4930881..5672901 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ *.pyc +.DS_Store +*.egg +*.egg-info +dist +/.idea _build diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 3d0750f..96f3929 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -3,3 +3,4 @@ Contributors * Edward Robinson (e-dard) * Rehan Dalal (rehandalal) +* Hannes Ljungberg (hannseman) diff --git a/docs/index.rst b/docs/index.rst index 459ecde..2bf473e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -163,12 +163,6 @@ uploading assets to S3. **Default:** ``u's3.amazonaws.com'`` `S3_BUCKET_NAME` The desired name for your Amazon S3 bucket. Note: the name will be visible in all your assets' URLs. -`S3_CACHE_CONTROL` This sets the value of the Cache-Control header that - is set in the metadata when `S3_USE_CACHE_CONTRL` is - set to `True`. -`S3_USE_CACHE_CONTROL` Specifies whether or not to set the metadata for the - Cache-Control headers. - **Default:** `False` `S3_USE_HTTPS` Specifies whether or not to serve your assets stored in S3 over HTTPS. **Default:** `True` @@ -186,6 +180,19 @@ uploading assets to S3. **Note**: if `USE_S3` is set to `False` then templates will always include asset locations specified by `flask.url_for`. +`S3_HEADERS` Sets custom headers to be sent with each file to S3. + + .. code-block:: python + + S3_HEADERS = { + 'Expires': 'Thu, 15 Apr 2010 20:00:00 GMT', + 'Cache-Control': 'max-age=86400', + } + + See http://developer.yahoo.com/performance/rules.html#expires + for more information. + + **Default:** `{}` =========================== =================================================== .. _debug: http://flask.pocoo.org/docs/config/#configuration-basics diff --git a/flask_s3.py b/flask_s3.py index c163c7d..03c4f3a 100644 --- a/flask_s3.py +++ b/flask_s3.py @@ -101,9 +101,9 @@ def _write_files(app, static_url_loc, static_folder, files, bucket, logger.debug("%s excluded from upload" % key_name) else: k = Key(bucket=bucket, name=key_name) - if (app.config['S3_USE_CACHE_CONTROL'] and - 'S3_CACHE_CONTROL' in app.config): - k.set_metadata('Cache-Control', app.config['S3_CACHE_CONTROL']) + # Set custom headers + for header, value in app.config['S3_HEADERS'].items(): + k.set_metadata(header, value) k.set_contents_from_filename(file_path) k.make_public() @@ -211,7 +211,7 @@ class FlaskS3(object): ('USE_S3', True), ('USE_S3_DEBUG', False), ('S3_BUCKET_DOMAIN', 's3.amazonaws.com'), - ('S3_USE_CACHE_CONTROL', False)] + ('S3_HEADERS', {})] for k, v in defaults: app.config.setdefault(k, v) diff --git a/tests/test_flask_static.py b/tests/test_flask_static.py index 9cdf3fc..1c9803a 100644 --- a/tests/test_flask_static.py +++ b/tests/test_flask_static.py @@ -28,7 +28,7 @@ class FlaskStaticTest(unittest.TestCase): """ Tests configuration vars exist. """ FlaskS3(self.app) defaults = ('S3_USE_HTTPS', 'USE_S3', 'USE_S3_DEBUG', - 'S3_BUCKET_DOMAIN', 'S3_USE_CACHE_CONTROL') + 'S3_BUCKET_DOMAIN', 'S3_HEADERS') for default in defaults: self.assertIn(default, self.app.config) @@ -117,7 +117,11 @@ class S3Tests(unittest.TestCase): self.app.testing = True self.app.config['S3_BUCKET_NAME'] = 'foo' self.app.config['S3_USE_CACHE_CONTROL'] = True - self.app.config['S3_CACHE_CONTROL'] = 'cache instruction' + self.app.config['S3_HEADERS'] = { + 'Expires': 'Thu, 31 Dec 2037 23:59:59 GMT', + 'Content-Encoding': 'gzip', + 'Cache-Control': 'max-age=86400' + } def test__bp_static_url(self): """ Tests test__bp_static_url """ @@ -141,12 +145,12 @@ class S3Tests(unittest.TestCase): url_prefix=None) bp_c = Mock(static_folder=None) - self.app.blueprints = { 'a': bp_a, 'b': bp_b, 'c': bp_c} - dirs = { '/home': [('/home', None, ['.a'])], - '/home/bar': [('/home/bar', None, ['b'])], - '/home/zoo': [('/home/zoo', None, ['c']), - ('/home/zoo/foo', None, ['d', 'e'])] } - os_mock.side_effect=dirs.get + self.app.blueprints = {'a': bp_a, 'b': bp_b, 'c': bp_c} + dirs = {'/home': [('/home', None, ['.a'])], + '/home/bar': [('/home/bar', None, ['b'])], + '/home/zoo': [('/home/zoo', None, ['c']), + ('/home/zoo/foo', None, ['d', 'e'])]} + os_mock.side_effect = dirs.get path_mock.return_value = True expected = {('/home/bar', u'/a/bar'): ['/home/bar/b'], @@ -169,7 +173,7 @@ class S3Tests(unittest.TestCase): """ self.app.static_folder = '/foo' dirs = {'/foo': [('/foo', None, [])]} - os_mock.side_effect=dirs.get + os_mock.side_effect = dirs.get path_mock.return_value = True actual = flask_s3._gather_files(self.app, False) @@ -183,7 +187,7 @@ class S3Tests(unittest.TestCase): """ self.app.static_folder = '/bad' dirs = {'/bad': []} - os_mock.side_effect=dirs.get + os_mock.side_effect = dirs.get path_mock.return_value = False actual = flask_s3._gather_files(self.app, False) @@ -209,7 +213,9 @@ class S3Tests(unittest.TestCase): exclude = ['/foo/static/foo.css', '/foo/static/foo/bar.css'] # we expect foo.css to be excluded and not uploaded expected = [call(bucket=None, name=u'/foo/static/bar.css'), - call().set_metadata('Cache-Control', 'cache instruction'), + call().set_metadata('Expires', 'Thu, 31 Dec 2037 23:59:59 GMT'), + call().set_metadata('Cache-Control', 'max-age=86400'), + call().set_metadata('Content-Encoding', 'gzip'), call().set_contents_from_filename('/home/z/bar.css')] flask_s3._write_files(self.app, static_url_loc, static_folder, assets, None, exclude) @@ -226,4 +232,4 @@ class S3Tests(unittest.TestCase): self.assertEquals(e, flask_s3._static_folder_path(*i)) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main()