Author: tomaz
Date: Tue Jul 24 04:51:18 2012
New Revision: 1364884

URL: http://svn.apache.org/viewvc?rev=1364884&view=rev
Log:
Fix a bug with content_type and and encoding of object and path names in 
the Atmos driver. Contributed by Russell Keith-Magee, part of LIBCLOUD-232 and 
LIBCLOUD-233.

Modified:
    libcloud/trunk/CHANGES
    libcloud/trunk/libcloud/storage/drivers/atmos.py
    libcloud/trunk/libcloud/test/storage/test_atmos.py

Modified: libcloud/trunk/CHANGES
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1364884&r1=1364883&r2=1364884&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Tue Jul 24 04:51:18 2012
@@ -139,6 +139,10 @@ Changes with Apache Libcloud in developm
       CloudFiles driver.
       [Tomaz Muraus]
 
+    - Fix a bug with content_type and and encoding of object and path names in 
+      the Atmos driver.
+      [Russell Keith-Magee]
+
   *) Other:
 
     - Unify docstrings formatting in the compute drivers. ; LIBCLOUD-229

Modified: libcloud/trunk/libcloud/storage/drivers/atmos.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/storage/drivers/atmos.py?rev=1364884&r1=1364883&r2=1364884&view=diff
==============================================================================
--- libcloud/trunk/libcloud/storage/drivers/atmos.py (original)
+++ libcloud/trunk/libcloud/storage/drivers/atmos.py Tue Jul 24 04:51:18 2012
@@ -31,7 +31,7 @@ from libcloud.utils.py3 import urlunquot
 if PY3:
     from io import FileIO as file
 
-from libcloud.utils.files import read_in_chunks
+from libcloud.utils.files import read_in_chunks, guess_file_mime_type
 from libcloud.common.base import ConnectionUserAndKey, XmlResponse
 from libcloud.common.types import LazyList, LibcloudError
 
@@ -41,14 +41,17 @@ from libcloud.storage.types import Conta
                                    ContainerIsNotEmptyError, \
                                    ObjectDoesNotExistError
 
+
 def collapse(s):
     return ' '.join([x for x in s.split(' ') if x])
 
+
 class AtmosError(LibcloudError):
     def __init__(self, code, message, driver=None):
         super(AtmosError, self).__init__(value=message, driver=driver)
         self.code = code
 
+
 class AtmosResponse(XmlResponse):
     def success(self):
         return self.status in (httplib.OK, httplib.CREATED, httplib.NO_CONTENT,
@@ -65,6 +68,7 @@ class AtmosResponse(XmlResponse):
         raise AtmosError(code=code, message=message,
                          driver=self.connection.driver)
 
+
 class AtmosConnection(ConnectionUserAndKey):
     responseCls = AtmosResponse
 
@@ -113,6 +117,7 @@ class AtmosConnection(ConnectionUserAndK
         signature = hmac.new(b(key), b(signature), hashlib.sha1).digest()
         return base64.b64encode(b(signature)).decode('utf-8')
 
+
 class AtmosDriver(StorageDriver):
     connectionCls = AtmosConnection
 
@@ -121,7 +126,7 @@ class AtmosDriver(StorageDriver):
     api_name = 'atmos'
     supports_chunked_encoding = True
 
-    DEFAULT_CDN_TTL = 60 * 60 * 24 * 7 # 1 week
+    DEFAULT_CDN_TTL = 60 * 60 * 24 * 7  # 1 week
 
     def __init__(self, key, secret=None, secure=True, host=None, port=None):
         host = host or self.host
@@ -270,6 +275,18 @@ class AtmosDriver(StorageDriver):
         path = self._namespace_path(container.name + '/' + object_name)
         method = 'PUT'
 
+        if extra is not None:
+            content_type = extra.get('content_type', None)
+        else:
+            content_type = None
+        if not content_type:
+            content_type, _ = guess_file_mime_type(object_name)
+
+            if not content_type:
+                raise AttributeError(
+                    'File content-type could not be guessed and' +
+                    ' no content_type value provided')
+
         try:
             self.connection.request(path + '?metadata/system')
         except AtmosError:
@@ -283,6 +300,7 @@ class AtmosDriver(StorageDriver):
             data_hash.update(b(chunk))
             headers = {
                 'x-emc-meta': 'md5=' + data_hash.hexdigest(),
+                'Content-Type': content_type,
             }
 
             if len(chunk) > 0 and bytes_transferred > 0:
@@ -413,14 +431,13 @@ class AtmosDriver(StorageDriver):
         return entries
 
     def _clean_object_name(self, name):
-        name = urlquote(name)
-        return name
+        return urlquote(name.encode('ascii'))
 
     def _namespace_path(self, path):
-        return self.path + '/rest/namespace/' + urlquote(path)
+        return self.path + '/rest/namespace/' + urlquote(path.encode('ascii'))
 
     def _object_path(self, object_id):
-        return self.path + '/rest/objects/' + object_id
+        return self.path + '/rest/objects/' + object_id.encode('ascii')
 
     @staticmethod
     def _emc_tag(tag):

Modified: libcloud/trunk/libcloud/test/storage/test_atmos.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/storage/test_atmos.py?rev=1364884&r1=1364883&r2=1364884&view=diff
==============================================================================
--- libcloud/trunk/libcloud/test/storage/test_atmos.py (original)
+++ libcloud/trunk/libcloud/test/storage/test_atmos.py Tue Jul 24 04:51:18 2012
@@ -36,6 +36,7 @@ from libcloud.storage.drivers.dummy impo
 from libcloud.test import StorageMockHttp, MockRawResponse
 from libcloud.test.file_fixtures import StorageFileFixtures
 
+
 class AtmosTests(unittest.TestCase):
     def setUp(self):
         AtmosDriver.connectionCls.conn_classes = (None, AtmosMockHttp)
@@ -377,8 +378,8 @@ class AtmosTests(unittest.TestCase):
         def dummy_content_type(name):
             return 'application/zip', None
 
-        old_func = libcloud.utils.files.guess_file_mime_type
-        libcloud.utils.files.guess_file_mime_type = dummy_content_type
+        old_func = libcloud.storage.drivers.atmos.guess_file_mime_type
+        libcloud.storage.drivers.atmos.guess_file_mime_type = 
dummy_content_type
 
         container = Container(name='fbc', extra={}, driver=self)
         object_name = 'ftsdn'
@@ -388,14 +389,14 @@ class AtmosTests(unittest.TestCase):
                                                  object_name=object_name,
                                                  iterator=iterator)
         finally:
-            libcloud.utils.files.guess_file_mime_type = old_func
+            libcloud.storage.drivers.atmos.guess_file_mime_type = old_func
 
     def test_upload_object_via_stream_existing_object(self):
         def dummy_content_type(name):
             return 'application/zip', None
 
-        old_func = libcloud.utils.files.guess_file_mime_type
-        libcloud.utils.files.guess_file_mime_type = dummy_content_type
+        old_func = libcloud.storage.drivers.atmos.guess_file_mime_type
+        libcloud.storage.drivers.atmos.guess_file_mime_type = 
dummy_content_type
 
         container = Container(name='fbc', extra={}, driver=self)
         object_name = 'ftsde'
@@ -405,7 +406,30 @@ class AtmosTests(unittest.TestCase):
                                                  object_name=object_name,
                                                  iterator=iterator)
         finally:
-            libcloud.utils.files.guess_file_mime_type = old_func
+            libcloud.storage.drivers.atmos.guess_file_mime_type = old_func
+
+    def test_upload_object_via_stream_no_content_type(self):
+        def no_content_type(name):
+            return None, None
+
+        old_func = libcloud.storage.drivers.atmos.guess_file_mime_type
+        libcloud.storage.drivers.atmos.guess_file_mime_type = no_content_type
+
+        container = Container(name='fbc', extra={}, driver=self)
+        object_name = 'ftsdct'
+        iterator = DummyIterator(data=['2', '3', '5'])
+        try:
+            self.driver.upload_object_via_stream(container=container,
+                                                 object_name=object_name,
+                                                 iterator=iterator)
+        except AttributeError:
+            pass
+        else:
+            self.fail(
+                'File content type not provided'
+                ' but an exception was not thrown')
+        finally:
+            libcloud.storage.drivers.atmos.guess_file_mime_type = old_func
 
     def test_signature_algorithm(self):
         test_uid = 'fredsmagicuid'
@@ -444,6 +468,7 @@ class AtmosTests(unittest.TestCase):
             self.assertEqual(c._calculate_signature({}, headers),
                              b(expected).decode('utf-8'))
 
+
 class AtmosMockHttp(StorageMockHttp, unittest.TestCase):
     fixtures = StorageFileFixtures('atmos')
     upload_created = False
@@ -666,7 +691,7 @@ class AtmosMockHttp(StorageMockHttp, uni
         return (httplib.OK, '', {}, httplib.responses[httplib.OK])
 
     def _rest_namespace_fbc_ftsdn_metadata_user(self, method, url, body,
-                                               headers):
+                                                headers):
         self.assertTrue('x-emc-meta' in headers)
         return (httplib.OK, '', {}, httplib.responses[httplib.OK])
 
@@ -692,7 +717,7 @@ class AtmosMockHttp(StorageMockHttp, uni
         return (httplib.OK, '', {}, httplib.responses[httplib.OK])
 
     def _rest_namespace_fbc_ftsde_metadata_user(self, method, url, body,
-                                               headers):
+                                                headers):
         self.assertTrue('x-emc-meta' in headers)
         return (httplib.OK, '', {}, httplib.responses[httplib.OK])
 
@@ -708,6 +733,7 @@ class AtmosMockHttp(StorageMockHttp, uni
         }
         return (httplib.OK, '', headers, httplib.responses[httplib.OK])
 
+
 class AtmosMockRawResponse(MockRawResponse):
     fixtures = StorageFileFixtures('atmos')
 


Reply via email to