Revision ae75584f pithos/lib/client.py

b/pithos/lib/client.py
38 38
import json
39 39
import types
40 40
import socket
41
import urllib
41 42
import pithos.api.faults
42 43

  
43 44
ERROR_CODES = {304:'Not Modified',
......
71 72
        self.token = token
72 73
    
73 74
    def _req(self, method, path, body=None, headers={}, format='text',
74
            params={}):
75
        full_path = '/%s/%s%s?format=%s' % (self.api, self.account, path,
76
                                            format)
75
             params={}, top_level_req=False):
76
        path = urllib.quote(path)
77
        account = '' if top_level_req else self.account
78
        full_path = '/%s/%s%s?format=%s' % (self.api, account, path, format)
79
        
77 80
        for k,v in params.items():
78 81
            if v:
79 82
                full_path = '%s&%s=%s' %(full_path, k, v)
......
97 100
            kwargs['headers'].setdefault('content-type',
98 101
                                         'application/octet-stream')
99 102
        kwargs['headers'].setdefault('content-length', len(body) if body else 0)
100
        try:
101
            #print '*', method, full_path, kwargs
102
            conn.request(method, full_path, **kwargs)
103
        except socket.error, e:
104
            raise Fault(status=503)
103
        kwargs['headers'] = _encode_headers(kwargs['headers'])
104
        #print '#', method, full_path, kwargs
105
        conn.request(method, full_path, **kwargs)
106
        
107
        #try:
108
        #    conn.request(method, full_path, **kwargs)
109
        #except socket.error, e:
110
        #    print '###', e[0], conn.auto_open
111
        #    raise Fault(status=503)
105 112
            
106 113
        resp = conn.getresponse()
107 114
        headers = dict(resp.getheaders())
......
128 135
    def delete(self, path, format='text', params={}):
129 136
        return self._req('DELETE', path, format=format, params=params)
130 137
    
131
    def get(self, path, format='text', headers=None, params={}):
138
    def get(self, path, format='text', headers={}, params={},
139
            top_level_req=False):
132 140
        return self._req('GET', path, headers=headers, format=format,
133
                        params=params)
141
                        params=params, top_level_req=top_level_req)
134 142
    
135 143
    def head(self, path, format='text', params={}):
136
        return self._req('HEAD', path, format=format, params=params)
144
         return self._req('HEAD', path, format=format, params=params)
137 145
    
138 146
    def post(self, path, body=None, format='text', headers=None, params={}):
139 147
        return self._req('POST', path, body, headers=headers, format=format,
......
142 150
    def put(self, path, body=None, format='text', headers=None):
143 151
        return self._req('PUT', path, body, headers=headers, format=format)
144 152
    
145
    def _list(self, path, format='text', params={}, **headers):
153
    def _list(self, path, format='text', params={}, top_level_req=False, 
154
              **headers):
146 155
        status, headers, data = self.get(path, format=format, headers=headers,
147
                                         params=params)
156
                                         params=params,
157
                                         top_level_req=top_level_req)
148 158
        if format == 'json':
149 159
            data = json.loads(data) if data else ''
150 160
        elif format == 'xml':
......
216 226
    
217 227
    # Storage Account Services
218 228
    
219
    def list_containers(self, format='text', limit=10000, marker=None, params={},
229
    def list_containers(self, format='text', limit=None, marker=None, params={},
220 230
                        **headers):
221 231
        """lists containers"""
222
        if not params:
223
            params = {}
224 232
        params.update({'limit':limit, 'marker':marker})
225 233
        return self._list('', format, params, **headers)
226 234
    
......
246 254
    def _filter_trashed(self, l):
247 255
        return self._filter(l, {'trash':'true'})
248 256
    
249
    def list_objects(self, container, format='text', limit=10000, marker=None,
257
    def list_objects(self, container, format='text', limit=None, marker=None,
250 258
                     prefix=None, delimiter=None, path=None,
251 259
                     include_trashed=False, params={}, **headers):
252 260
        """returns a list with the container objects"""
......
369 377
        path = '/%s/%s' % (dst_container, dst_object)
370 378
        headers = {} if not headers else headers
371 379
        for k, v in meta.items():
372
            headers['x-object-meta-%s' % k] = v 
380
            headers['x-object-meta-%s' % k] = v
373 381
        if remove:
374 382
            headers['x-move-from'] = '/%s/%s' % (src_container, src_object)
375 383
        else:
......
440 448
            block = f.read(blocksize)
441 449
            if block == '':
442 450
                break
443
            data = '%s\r\n%s\r\n' % (hex(len(block)), block)
451
            data = '%x\r\n%s\r\n' % (len(block), block)
444 452
            try:
445 453
                http.send(data)
446 454
            except:
447 455
                #retry
448 456
                http.send(data)
449
        data = '0x0\r\n'
457
        data = '0\r\n\r\n'
450 458
        try:
451 459
            http.send(data)
452 460
        except:
......
505 513
                        if_unmodified_since=None, limit=1000, marker=None,
506 514
                        until=None):
507 515
        """returns a list with the account containers"""
508
        params = {'until':until} if until else None
516
        params = {'until':until} if until else {}
509 517
        headers = {'if-modified-since':if_modified_since,
510 518
                   'if-unmodified-since':if_unmodified_since}
511 519
        return OOS_Client.list_containers(self, format=format, limit=limit,
......
521 529
    def set_account_groups(self, **groups):
522 530
        """create account groups"""
523 531
        headers = {}
524
        for key, val in groups.items():
525
            headers['x-account-group-%s' % key] = val
532
        for k, v in groups.items():
533
            headers['x-account-group-%s' % k] = v
526 534
        params = {'update':None}
527 535
        return self.post('', headers=headers, params=params)
528 536
    
......
551 559
    def reset_account_groups(self, **groups):
552 560
        """overrides account groups"""
553 561
        headers = {}
554
        for key, val in groups.items():
555
            headers['x-account-group-%s' % key] = val
562
        for k, v in groups.items():
563
            v = v.strip()
564
            headers['x-account-group-%s' % k] = v
556 565
        meta = self.retrieve_account_metadata()
557 566
        headers.update(meta)
558 567
        return self.post('', headers=headers)
559 568
    
560 569
    # Storage Container Services
561 570
    
562
    def list_objects(self, container, format='text', limit=10000, marker=None,
571
    def list_objects(self, container, format='text', limit=None, marker=None,
563 572
                     prefix=None, delimiter=None, path=None,
564 573
                     include_trashed=False, params={}, if_modified_since=None,
565 574
                     if_unmodified_since=None, meta={}, until=None):
......
672 681
            headers.update({elem:eval(elem)})
673 682
        
674 683
        for k,v in meta.items():
675
            headers['x-object-meta-%s' %k.strip()] = v.strip()
684
            v = v.strip()
685
            headers['x-object-meta-%s' %k.strip()] = v
676 686
        
677 687
        return self._chunked_transfer(path, 'PUT', f, headers=headers,
678 688
                                      blocksize=blocksize)
......
738 748
            headers['content_range'] = 'bytes */*'
739 749
        
740 750
        for k,v in meta.items():
741
            headers['x-object-meta-%s' %k.strip()] = v.strip()
751
            v = v.strip()
752
            headers['x-object-meta-%s' %k.strip()] = v
742 753
        
743 754
        return self._chunked_transfer(path, 'POST', f, headers=headers,
744 755
                                      blocksize=blocksize)
......
777 788
        path = '/%s/%s' % (dst_container, dst_object)
778 789
        headers = {} if not headers else headers
779 790
        for k, v in meta.items():
780
            headers['x-object-meta-%s' % k] = v 
791
            headers['x-object-meta-%s' % k] = v
781 792
        if remove:
782 793
            headers['x-move-from'] = '/%s/%s' % (src_container, src_object)
783 794
        else:
......
805 816
            headers['x_object_version'] = version
806 817
        return OOS_Client.move_object(self, src_container, src_object,
807 818
                                      dst_container, dst_object, meta=meta,
808
                                      **headers)
819
                                      **headers)
820
    
821
    def list_shared_by_others(self, limit=None, marker=None, format='text'):
822
         l = ['limit', 'marker']
823
         params = {}
824
         for elem in [elem for elem in l if eval(elem)]:
825
             params[elem] = eval(elem)
826
         return self._list('', format, params, top_level_req=True)
827
    
828
    def share_object(self, container, object, l, read=True):
829
        action = 'read' if read else 'write'
830
        sharing = '%s=%s' % (action, ','.join(l))
831
        self.update_object(container, object, f=None, x_object_sharing=sharing)
832

  
833
def _encode_headers(headers):
834
    h = {}
835
    for k, v in headers.items():
836
        k = urllib.quote(k)
837
        if v and type(v) == types.StringType:
838
            v = urllib.quote(v, '/=,-* :"')
839
        h[k] = v
840
    return h

Also available in: Unified diff