diff --git a/swift/storage.py b/swift/storage.py index bc014fc..b5244a8 100644 --- a/swift/storage.py +++ b/swift/storage.py @@ -1,5 +1,6 @@ import mimetypes import os +import posixpath import re from datetime import datetime from functools import wraps @@ -7,6 +8,7 @@ from time import time import magic from django.conf import settings +from django.contrib.staticfiles.storage import CachedFilesMixin, ManifestFilesMixin from django.core.exceptions import ImproperlyConfigured from django.core.files import File from django.core.files.storage import Storage @@ -29,6 +31,17 @@ def setting(name, default=None): return getattr(settings, name, default) +def safe_normpath(path): + """ + Avoid doing normpath on empty path since: + - posixpath.normpath('') -> '.' + - we should avoid relative paths with swift + """ + if path: + return posixpath.normpath(path) + return path + + def validate_settings(backend): # Check mandatory parameters if not backend.api_auth_url: @@ -108,7 +121,7 @@ def prepend_name_prefix(func): """ @wraps(func) def prepend_prefix(self, name, *args, **kwargs): - name = self.name_prefix + name + name = self.name_prefix + safe_normpath(name) return func(self, name, *args, **kwargs) return prepend_prefix @@ -241,7 +254,7 @@ def set_token(self, new_token): def _open(self, name, mode='rb'): original_name = name - name = self.name_prefix + name + name = self.name_prefix + safe_normpath(name) headers, content = swiftclient.get_object(self.storage_url, self.token, @@ -255,7 +268,7 @@ def _open(self, name, mode='rb'): def _save(self, name, content, headers=None): original_name = name - name = self.name_prefix + name + name = self.name_prefix + safe_normpath(name) if self.content_type_from_fd: content_type = magic.from_buffer(content.read(1024), mime=True) @@ -426,3 +439,23 @@ def get_available_name(self, name, max_length=None): overwrite it. """ return name + + +class CachedStaticSwiftStorage(CachedFilesMixin, StaticSwiftStorage): + """ + A static file system storage backend which also saves + hashed copies of the files it saves. + """ + pass + + +class ManifestStaticSwiftStorage(ManifestFilesMixin, StaticSwiftStorage): + """ + A static file system storage backend which also saves + hashed copies of the files it saves. + """ + def read_manifest(self): + try: + super(ManifestStaticSwiftStorage, self).read_manifest() + except swiftclient.ClientException: + return None