Revision 8cb45c13 pithos/api/util.py

b/pithos/api/util.py
153 153
            if k in meta:
154 154
                response[k] = meta[k]
155 155

  
156
def update_manifest_meta(request, v_account, meta):
157
    """Update metadata if the object has an X-Object-Manifest."""
158
    
159
    if 'X-Object-Manifest' in meta:
160
        hash = ''
161
        bytes = 0
162
        try:
163
            src_container, src_name = split_container_object_string(meta['X-Object-Manifest'])
164
            objects = backend.list_objects(request.user, v_account, src_container, prefix=src_name, virtual=False)
165
            for x in objects:
166
                src_meta = backend.get_object_meta(request.user, v_account, src_container, x[0], x[1])
167
                hash += src_meta['hash']
168
                bytes += src_meta['bytes']
169
        except:
170
            # Ignore errors.
171
            return
172
        meta['bytes'] = bytes
173
        md5 = hashlib.md5()
174
        md5.update(hash)
175
        meta['hash'] = md5.hexdigest().lower()
176

  
156 177
def validate_modification_preconditions(request, meta):
157 178
    """Check that the modified timestamp conforms with the preconditions set."""
158 179
    
......
188 209
            raise NotModified('Resource Etag matches')
189 210

  
190 211
def split_container_object_string(s):
191
    parts = s.split('/')
192
    if len(parts) < 3 or parts[0] != '':
212
    pos = s.find('/')
213
    if pos == -1:
193 214
        raise ValueError
194
    return parts[1], '/'.join(parts[2:])
215
    return s[:pos], s[(pos + 1):]
195 216

  
196 217
def copy_or_move_object(request, v_account, src_container, src_name, dest_container, dest_name, move=False):
197 218
    """Copy or move an object."""
......
391 412
    Read from the object using the offset and length provided in each entry of the range list.
392 413
    """
393 414
    
394
    def __init__(self, ranges, size, hashmap, boundary):
415
    def __init__(self, ranges, sizes, hashmaps, boundary):
395 416
        self.ranges = ranges
396
        self.size = size
397
        self.hashmap = hashmap
417
        self.sizes = sizes
418
        self.hashmaps = hashmaps
398 419
        self.boundary = boundary
420
        self.size = sum(self.sizes)
399 421
        
400
        self.block_index = -1
422
        self.file_index = 0
423
        self.block_index = 0
424
        self.block_hash = -1
401 425
        self.block = ''
402 426
        
403 427
        self.range_index = -1
......
408 432
    
409 433
    def part_iterator(self):
410 434
        if self.length > 0:
411
            # Get the block for the current offset.
412
            bi = int(self.offset / backend.block_size)
413
            if self.block_index != bi:
435
            # Get the file for the current offset.
436
            file_size = self.sizes[self.file_index]
437
            while self.offset >= file_size:
438
                self.offset -= file_size
439
                self.file_index += 1
440
                file_size = self.sizes[self.file_index]
441
            
442
            # Get the block for the current position.
443
            self.block_index = int(self.offset / backend.block_size)
444
            if self.block_hash != self.hashmaps[self.file_index][self.block_index]:
445
                self.block_hash = self.hashmaps[self.file_index][self.block_index]
414 446
                try:
415
                    self.block = backend.get_block(self.hashmap[bi])
447
                    self.block = backend.get_block(self.block_hash)
416 448
                except NameError:
417 449
                    raise ItemNotFound('Block does not exist')
418
                self.block_index = bi
450
            
419 451
            # Get the data from the block.
420 452
            bo = self.offset % backend.block_size
421
            bl = min(self.length, backend.block_size - bo)
453
            bl = min(self.length, len(self.block) - bo)
422 454
            data = self.block[bo:bo + bl]
423 455
            self.offset += bl
424 456
            self.length -= bl
......
441 473
            if self.range_index < len(self.ranges):
442 474
                # Part header.
443 475
                self.offset, self.length = self.ranges[self.range_index]
476
                self.file_index = 0
444 477
                if self.range_index > 0:
445 478
                    out.append('')
446 479
                out.append('--' + self.boundary)
......
456 489
                out.append('')
457 490
                return '\r\n'.join(out)
458 491

  
459
def object_data_response(request, size, hashmap, meta, public=False):
492
def object_data_response(request, sizes, hashmaps, meta, public=False):
460 493
    """Get the HttpResponse object for replying with the object's data."""
461 494
    
462 495
    # Range handling.
496
    size = sum(sizes)
463 497
    ranges = get_range(request, size)
464 498
    if ranges is None:
465 499
        ranges = [(0, size)]
......
477 511
        boundary = uuid.uuid4().hex
478 512
    else:
479 513
        boundary = ''
480
    wrapper = ObjectWrapper(ranges, size, hashmap, boundary)
514
    wrapper = ObjectWrapper(ranges, sizes, hashmaps, boundary)
481 515
    response = HttpResponse(wrapper, status=ret)
482 516
    put_object_meta(response, meta, public)
483 517
    if ret == 206:

Also available in: Unified diff