from sys import stdin
from xml.dom import minidom
from StringIO import StringIO
+from urllib import quote, unquote
import json
import types
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):
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
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)
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')
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={}):
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"""
account = account or self.account
path = '/%s/%s/%s' % (account, container, object)
for k, v in headers.items():
- if not v:
+ if v == None:
headers.pop(k)
l = ['etag', 'content_encoding', 'content_disposition', 'content_type']
account = account or self.account
path = '/%s/%s/%s' % (account, container, object)
for k, v in headers.items():
- if not v:
+ if v == None:
headers.pop(k)
l = ['content_encoding', 'content_disposition', 'content_type',
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
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
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