diff --git a/docs/index.rst b/docs/index.rst index 276659d..25092fc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -184,6 +184,11 @@ uploading assets to S3. bucket name in the base url. `S3_BUCKET_NAME` The desired name for your Amazon S3 bucket. Note: the name will be visible in all your assets' URLs. +`S3_URL_STYLE` Set to `'host'` to use virtual-host-style URLs, + e.g. ``bucketname.s3.amazonaws.com``. Set to + `'path'` to use path-style URLs, e.g. + ``s3.amazonaws.com/bucketname``. + **Default:** `'host'` `S3_USE_HTTPS` Specifies whether or not to serve your assets stored in S3 over HTTPS. **Default:** `True` diff --git a/flask_s3.py b/flask_s3.py index 0c87362..225d40c 100644 --- a/flask_s3.py +++ b/flask_s3.py @@ -50,8 +50,20 @@ def url_for(endpoint, **values): scheme = 'http' if app.config['S3_USE_HTTPS']: scheme = 'https' - bucket_path = '%s.%s' % (app.config['S3_BUCKET_NAME'], - app.config['S3_BUCKET_DOMAIN']) + + if app.config['S3_URL_STYLE'] == 'host': + url_format = '%(bucket_name)s.%(bucket_domain)s' + elif app.config['S3_URL_STYLE'] == 'path': + url_format = '%(bucket_domain)s/%(bucket_name)s' + else: + raise ValueError('Invalid S3 URL style: "%s"' + % app.config['S3_URL_STYLE']) + + bucket_path = url_format % { + 'bucket_name': app.config['S3_BUCKET_NAME'], + 'bucket_domain': app.config['S3_BUCKET_DOMAIN'], + } + if app.config['S3_CDN_DOMAIN']: bucket_path = '%s' % app.config['S3_CDN_DOMAIN'] urls = app.url_map.bind(bucket_path, url_scheme=scheme) @@ -285,7 +297,8 @@ class FlaskS3(object): ('S3_CDN_DOMAIN', ''), ('S3_USE_CACHE_CONTROL', False), ('S3_HEADERS', {}), - ('S3_ONLY_MODIFIED', False)] + ('S3_ONLY_MODIFIED', False), + ('S3_URL_STYLE', 'host')] 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 464065c..152e34d 100644 --- a/tests/test_flask_static.py +++ b/tests/test_flask_static.py @@ -33,7 +33,8 @@ class FlaskStaticTest(unittest.TestCase): FlaskS3(self.app) defaults = ('S3_USE_HTTPS', 'USE_S3', 'USE_S3_DEBUG', 'S3_BUCKET_DOMAIN', 'S3_CDN_DOMAIN', - 'S3_USE_CACHE_CONTROL', 'S3_HEADERS') + 'S3_USE_CACHE_CONTROL', 'S3_HEADERS', + 'S3_URL_STYLE') for default in defaults: self.assertIn(default, self.app.config) @@ -124,6 +125,18 @@ class UrlTests(unittest.TestCase): exp = 'https://foo.cloudfront.net/static/bah.js' self.assertEquals(self.client_get(ufs).data, exp) + def test_url_for_url_style_path(self): + """Tests that the URL returned uses the path style.""" + self.app.config['S3_URL_STYLE'] = 'path' + ufs = "{{url_for('static', filename='bah.js')}}" + exp = 'https://s3.amazonaws.com/foo/static/bah.js' + self.assertEquals(self.client_get(ufs).data, exp) + + def test_url_for_url_style_invalid(self): + """Tests that an exception is raised for invalid URL styles.""" + self.app.config['S3_URL_STYLE'] = 'balderdash' + ufs = "{{url_for('static', filename='bah.js')}}" + self.assertRaises(ValueError, self.client_get, ufs) class S3Tests(unittest.TestCase):