Fix download in transfer lib.
[pithos] / tools / lib / client.py
index 2208fb6..a18bbc3 100644 (file)
@@ -35,6 +35,7 @@ from httplib import HTTPConnection, HTTP
 from sys import stdin
 from xml.dom import minidom
 from StringIO import StringIO
+from urllib import quote, unquote
 
 import json
 import types
@@ -45,13 +46,16 @@ import datetime
 ERROR_CODES = {304:'Not Modified',
                400:'Bad Request',
                401:'Unauthorized',
+               403:'Forbidden',
                404:'Not Found',
                409:'Conflict',
                411:'Length Required',
                412:'Precondition Failed',
+               413:'Request Entity Too Large',
                416:'Range Not Satisfiable',
                422:'Unprocessable Entity',
-               503:'Service Unavailable'}
+               503:'Service Unavailable',
+               }
 
 class Fault(Exception):
     def __init__(self, data='', status=None):
@@ -74,23 +78,20 @@ class Client(object):
     
     def _req(self, method, path, body=None, headers={}, format='text', params={}):
         slash = '/' if self.api else ''
-        full_path = '%s%s%s?format=%s' % (slash, self.api, path, format)
+        full_path = '%s%s%s?format=%s' % (slash, self.api, quote(path), format)
         
         for k,v in params.items():
             if v:
-                full_path = '%s&%s=%s' %(full_path, k, v)
+                full_path = '%s&%s=%s' %(full_path, quote(k), quote(str(v)))
             else:
                 full_path = '%s&%s=' %(full_path, k)
         conn = HTTPConnection(self.host)
         
-        #encode whitespace
-        full_path = full_path.replace(' ', '%20')
-        
         kwargs = {}
         for k,v in headers.items():
             headers.pop(k)
             k = k.replace('_', '-')
-            headers[k] = v
+            headers[k] = quote(v, safe='/=,:@ *"') if type(v) == types.StringType else v
         
         kwargs['headers'] = headers
         kwargs['headers']['X-Auth-Token'] = self.token
@@ -106,7 +107,8 @@ class Client(object):
         resp = conn.getresponse()
         t2 = datetime.datetime.utcnow()
         #print 'response time:', str(t2-t1)
-        headers = dict(resp.getheaders())
+        headers = resp.getheaders()
+        headers = dict((unquote(h), unquote(v)) for h,v in headers)
         
         if self.verbose:
             print '%d %s' % (resp.status, resp.reason)
@@ -139,6 +141,9 @@ class Client(object):
                 full_path = '%s&%s=%s' %(full_path, k, v)
             else:
                 full_path = '%s&%s=' %(full_path, k)
+        
+        full_path = urllib.quote(full_path, '?&:=/')
+        
         http.putrequest(method, full_path)
         http.putheader('x-auth-token', self.token)
         http.putheader('content-type', 'application/octet-stream')
@@ -218,7 +223,7 @@ class Client(object):
         elif format == 'xml':
             data = minidom.parseString(data)
         else:
-            data = data.strip().split('\n') if data else ''
+            data = data.split('\n')[:-1] if data else ''
         return data
     
     def _get_metadata(self, path, prefix=None, params={}):
@@ -405,8 +410,7 @@ class OOS_Client(Client):
         args = locals().copy()
         for elem in ['self', 'container', 'object']:
             args.pop(elem)
-        data = self.retrieve_object(container, object, format='json', **args)
-        return data['hashes']
+        return self.retrieve_object(container, object, format='json', **args)
     
     def create_directory_marker(self, container, object, account=None):
         """creates a dierectory marker"""
@@ -464,7 +468,7 @@ class OOS_Client(Client):
         l = [elem for elem in l if eval(elem)]
         for elem in l:
             headers.update({elem:eval(elem)})
-            
+        
         if 'content_range' not in headers.keys():
             if offset != None:
                 headers['content_range'] = 'bytes %s-/*' % offset
@@ -709,6 +713,16 @@ class Pithos_Client(OOS_Client):
             headers['x-container-policy-%s' % key] = val
         return self.post(path, headers=headers)
     
+    def update_container_data(self, container, f=stdin):
+        """adds blocks of data to the container"""
+        account = self.account
+        path = '/%s/%s' % (account, container)
+        params = {'update': None}
+        headers = {'content_type': 'application/octet-stream'}
+        data = f.read() if f else None
+        headers['content_length'] = len(data)
+        return self.post(path, data, headers=headers, params=params)
+    
     def delete_container(self, container, until=None, account=None):
         """deletes a container or the container history until the date provided"""
         account = account or self.account
@@ -963,12 +977,3 @@ class Pithos_Client(OOS_Client):
         action = 'read' if read else 'write'
         sharing = '%s=%s' % (action, ','.join(l))
         self.update_object(container, object, f=None, x_object_sharing=sharing)
-
-def _encode_headers(headers):
-    h = {}
-    for k, v in headers.items():
-        k = urllib.quote(k)
-        if v and type(v) == types.StringType:
-            v = urllib.quote(v, '/=,-* :"')
-        h[k] = v
-    return h