Revision cfe6939d pithos/api/functions.py

b/pithos/api/functions.py
502 502
    except NameError:
503 503
        raise ItemNotFound('Container does not exist')
504 504
    try:
505
        backend.update_object_meta(request.user, v_container, v_object, meta)
505
        backend.update_object_meta(request.user, v_container, v_object, meta, replace=True)
506 506
    except NameError:
507 507
        raise ItemNotFound('Object does not exist')
508 508
    
......
551 551
    if content_type:
552 552
        del(meta['Content-Type']) # Do not allow changing the Content-Type.
553 553
    
554
    prev_meta = None
554
    try:
555
        prev_meta = backend.get_object_meta(request.user, v_container, v_object)
556
    except NameError:
557
        raise ItemNotFound('Object does not exist')
558
    
559
    # Handle metadata changes.
555 560
    if len(meta) != 0:
556
        try:
557
            prev_meta = backend.get_object_meta(request.user, v_container, v_object)
558
        except NameError:
559
            raise ItemNotFound('Object does not exist')
560 561
        # Keep previous values of 'Content-Type' and 'hash'.
561 562
        for k in ('Content-Type', 'hash'):
562 563
            if k in prev_meta:
......
566 567
        except NameError:
567 568
            raise ItemNotFound('Object does not exist')
568 569
    
570
    # A Content-Type or Content-Range header may indicate data updates.
571
    if content_type and content_type.startswith('multipart/byteranges'):
572
        # TODO: Support multiple update ranges.
573
        return HttpResponse(status=202)
574
    # Single range update. Range must be in Content-Range.
569 575
    # Based on: http://code.google.com/p/gears/wiki/ContentRangePostProposal
576
    # (with the addition that '*' is allowed for the range - will append).
577
    if content_type and content_type != 'application/octet-stream':
578
        return HttpResponse(status=202)
570 579
    content_range = request.META.get('HTTP_CONTENT_RANGE')
571 580
    if not content_range:
572 581
        return HttpResponse(status=202)
573 582
    ranges = get_content_range(request)
574 583
    if not ranges:
575 584
        return HttpResponse(status=202)
585
    # Require either a Content-Length, or 'chunked' Transfer-Encoding.
586
    content_length = -1
587
    if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
588
        content_length = get_content_length(request)
576 589
    
577
#     # Need Content-Type and optional Transfer-Encoding.
578
#     content_length = -1
579
#     if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
580
#         content_length = get_content_length(request)
581
#     # Use BadRequest here, even if the API says otherwise for PUT.
582
#     if not content_type:
583
#         raise BadRequest('Missing Content-Type header')
584
#     
585
#     if not prev_meta:
586
#         try:
587
#             prev_meta = backend.get_object_meta(request.user, v_container, v_object)
588
#         except NameError:
589
#             raise ItemNotFound('Object does not exist')
590
#     size = prev_meta['bytes']
591
#     offset, length, total = ranges
592
#     if offset is None:
593
#         offset = size
594
#     if length is None:
595
#         length = content_length # Nevermind the error.
596
#     if total is not None and (total != size or offset >= size or (length > 0 and offset + length >= size)):
597
#         raise RangeNotSatisfiable('Supplied range will change provided object limits')
598
#     
599
#     sock = raw_input_socket(request)
600
#     for data in socket_read_iterator(sock, length):
601
#         # TODO: Raise 408 (Request Timeout) if this takes too long.
602
#         # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
603
#         try:
604
#             backend.update_object(request.user, v_container, v_object, data, offset)
605
#         except NameError:
606
#             raise ItemNotFound('Container does not exist')
607
#         offset += len(data)
590
    try:
591
        # TODO: Also check for IndexError.
592
        size, hashmap = backend.get_object_hashmap(request.user, v_container, v_object)
593
    except NameError:
594
        raise ItemNotFound('Object does not exist')
595
    
596
    offset, length, total = ranges
597
    if offset is None:
598
        offset = size
599
    if length is None:
600
        length = content_length # Nevermind the error.
601
    elif length != content_length:
602
        raise BadRequest('Content length does not match range length')
603
    if total is not None and (total != size or offset >= size or (length > 0 and offset + length >= size)):
604
        raise RangeNotSatisfiable('Supplied range will change provided object limits')
605
    
606
    sock = raw_input_socket(request)
607
    data = ''
608
    for d in socket_read_iterator(sock, length, backend.block_size):
609
        # TODO: Raise 408 (Request Timeout) if this takes too long.
610
        # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
611
        data += d
612
        bi = int(offset / backend.block_size)
613
        bo = offset % backend.block_size
614
        bl = min(len(data), backend.block_size - bo)
615
        offset += bl
616
        h = backend.update_block(hashmap[bi], data[:bl], bo)
617
        if bi < len(hashmap):
618
            hashmap[bi] = h
619
        else:
620
            hashmap.append(h)
621
        data = data[bl:]
622
    if len(data) > 0:
623
        bi = int(offset / backend.block_size)
624
        offset += len(data)
625
        h = backend.update_block(hashmap[bi], data)
626
        if bi < len(hashmap):
627
            hashmap[bi] = h
628
        else:
629
            hashmap.append(h)
630
    
631
    if offset > size:
632
        size = offset
633
    try:
634
        backend.update_object_hashmap(request.user, v_container, v_object, size, hashmap)
635
    except NameError:
636
        raise ItemNotFound('Container does not exist')
637
    
638
    # Update ETag.
639
    # TODO: Decide on the new ETag to use here.
640
    meta = {}
641
    md5 = hashlib.md5()
642
    md5.update(str(hashmap))
643
    meta['hash'] = md5.hexdigest().lower()
644
    try:
645
        backend.update_object_meta(request.user, v_container, v_object, meta)
646
    except NameError:
647
        raise ItemNotFound('Object does not exist')
608 648
    
609 649
    return HttpResponse(status=202)
610 650

  

Also available in: Unified diff