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