Revision ab2e317e pithos/api/functions.py

b/pithos/api/functions.py
597 597
    copy_from = request.META.get('HTTP_X_COPY_FROM')
598 598
    move_from = request.META.get('HTTP_X_MOVE_FROM')
599 599
    if copy_from or move_from:
600
        # TODO: Why is this required? Copy this ammount?
601
        content_length = get_content_length(request)
600
        content_length = get_content_length(request) # Required by the API.
602 601
        
603 602
        if move_from:
604 603
            try:
......
745 744
            if k in prev_meta:
746 745
                meta[k] = prev_meta[k]
747 746
    
748
    # A Content-Type header indicates data updates.
749
    if not content_type or content_type != 'application/octet-stream':
747
    # A Content-Type or X-Source-Object header indicates data updates.
748
    src_object = request.META.get('HTTP_X_SOURCE_OBJECT')
749
    if (not content_type or content_type != 'application/octet-stream') and not src_object:
750 750
        # Do permissions first, as it may fail easier.
751 751
        if permissions is not None:
752 752
            try:
......
783 783
    ranges = get_content_range(request)
784 784
    if not ranges:
785 785
        raise RangeNotSatisfiable('Invalid Content-Range header')
786
    # Require either a Content-Length, or 'chunked' Transfer-Encoding.
787
    content_length = -1
788
    if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
789
        content_length = get_content_length(request)
790 786
    
791 787
    try:
792 788
        size, hashmap = backend.get_object_hashmap(request.user, v_account, v_container, v_object)
......
800 796
        offset = size
801 797
    elif offset > size:
802 798
        raise RangeNotSatisfiable('Supplied offset is beyond object limits')
803
    if length is None or content_length == -1:
804
        length = content_length # Nevermind the error.
805
    elif length != content_length:
806
        raise BadRequest('Content length does not match range length')
799
    if src_object:
800
        src_container, src_name = split_container_object_string(src_object)
801
        src_version = request.META.get('HTTP_X_SOURCE_VERSION')
802
        try:
803
            src_size, src_hashmap = backend.get_object_hashmap(request.user, v_account, src_container, src_name, src_version)
804
        except NotAllowedError:
805
            raise Unauthorized('Access denied')
806
        except NameError:
807
            raise ItemNotFound('Source object does not exist')
808
        
809
        if length is None:
810
            length = src_size
811
        elif length > src_size:
812
            raise BadRequest('Object length is smaller than range length')
813
    else:
814
        # Require either a Content-Length, or 'chunked' Transfer-Encoding.
815
        content_length = -1
816
        if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
817
            content_length = get_content_length(request)
818
        
819
        if length is None:
820
            length = content_length
821
        else:
822
            if content_length == -1:
823
                # TODO: Get up to length bytes in chunks.
824
                length = content_length
825
            elif length != content_length:
826
                raise BadRequest('Content length does not match range length')
807 827
    if total is not None and (total != size or offset >= size or (length > 0 and offset + length >= size)):
808 828
        raise RangeNotSatisfiable('Supplied range will change provided object limits')
809 829
    
810
    sock = raw_input_socket(request)
811
    data = ''
812
    for d in socket_read_iterator(sock, length, backend.block_size):
813
        # TODO: Raise 408 (Request Timeout) if this takes too long.
814
        # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
815
        data += d
816
        bytes = put_object_block(hashmap, data, offset)
817
        offset += bytes
818
        data = data[bytes:]
819
    if len(data) > 0:
820
        put_object_block(hashmap, data, offset)
830
    if src_object:
831
        if offset % backend.block_size == 0:
832
            # Update the hashes only.
833
            sbi = 0
834
            while length > 0:
835
                bi = int(offset / backend.block_size)
836
                bl = min(length, backend.block_size)
837
                if bi < len(hashmap):
838
                    if bl == backend.block_size:
839
                        hashmap[bi] = src_hashmap[sbi]
840
                    else:
841
                        data = backend.get_block(src_hashmap[sbi])
842
                        hashmap[bi] = backend.update_block(hashmap[bi], data[:bl], 0)
843
                else:
844
                    hashmap.append(src_hashmap[sbi])
845
                offset += bl
846
                length -= bl
847
                sbi += 1
848
        else:
849
            data = ''
850
            sbi = 0
851
            while length > 0:
852
                data += backend.get_block(src_hashmap[sbi])
853
                if length < backend.block_size:
854
                    data = data[:length]
855
                bytes = put_object_block(hashmap, data, offset)
856
                offset += bytes
857
                data = data[bytes:]
858
                length -= bytes
859
                sbi += 1
860
    else:
861
        sock = raw_input_socket(request)
862
        data = ''
863
        for d in socket_read_iterator(sock, length, backend.block_size):
864
            # TODO: Raise 408 (Request Timeout) if this takes too long.
865
            # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
866
            data += d
867
            bytes = put_object_block(hashmap, data, offset)
868
            offset += bytes
869
            data = data[bytes:]
870
        if len(data) > 0:
871
            put_object_block(hashmap, data, offset)
821 872
    
822 873
    if offset > size:
823 874
        size = offset

Also available in: Unified diff