Revision 67100dd2 snf-pithos-app/pithos/api/functions.py

b/snf-pithos-app/pithos/api/functions.py
40 40
from django.utils.encoding import smart_str
41 41
from django.views.decorators.csrf import csrf_exempt
42 42

  
43
from django.conf import settings
44 43
from snf_django.lib.astakos import get_uuids as _get_uuids
45 44

  
46 45
from snf_django.lib import api
......
57 56
    get_content_range, socket_read_iterator, SaveToBackendHandler,
58 57
    object_data_response, put_object_block, hashmap_md5, simple_list_response,
59 58
    api_method, is_uuid,
60
    retrieve_uuid, retrieve_displayname, retrieve_uuids, retrieve_displaynames,
59
    retrieve_uuid, retrieve_uuids, retrieve_displaynames,
61 60
    get_pithos_usage
62 61
)
63 62

  
......
146 145

  
147 146
@csrf_exempt
148 147
def object_demux(request, v_account, v_container, v_object):
149
    # Helper to avoid placing the token in the URL when loading objects from a browser.
148
    # Helper to avoid placing the token in the URL
149
    # when loading objects from a browser.
150 150
    if TRANSLATE_UUIDS:
151 151
        if not is_uuid(v_account):
152 152
            uuids = get_uuids([v_account])
......
165 165
    elif request.method == 'MOVE':
166 166
        return object_move(request, v_account, v_container, v_object)
167 167
    elif request.method == 'POST':
168
        if request.META.get('CONTENT_TYPE', '').startswith('multipart/form-data'):
168
        if request.META.get(
169
                'CONTENT_TYPE', '').startswith('multipart/form-data'):
169 170
            return object_write_form(request, v_account, v_container, v_object)
170 171
        return object_update(request, v_account, v_container, v_object)
171 172
    elif request.method == 'DELETE':
......
214 215
    if request.serialization == 'text':
215 216
        if TRANSLATE_UUIDS:
216 217
            accounts = retrieve_displaynames(
217
                    getattr(request, 'token', None), accounts)
218
                getattr(request, 'token', None), accounts)
218 219
        if len(accounts) == 0:
219 220
            # The cloudfiles python bindings expect 200 if json/xml.
220 221
            response.status_code = 204
......
247 248
    if TRANSLATE_UUIDS:
248 249
        uuids = list(d['name'] for d in account_meta)
249 250
        catalog = retrieve_displaynames(
250
                getattr(request, 'token', None), uuids, return_dict=True)
251
            getattr(request, 'token', None), uuids, return_dict=True)
251 252
        for meta in account_meta:
252 253
            meta['name'] = catalog.get(meta.get('name'))
253 254

  
......
279 280
        if TRANSLATE_UUIDS:
280 281
            for k in groups:
281 282
                groups[k] = retrieve_displaynames(
282
                        getattr(request, 'token', None), groups[k])
283
                    getattr(request, 'token', None), groups[k])
283 284
        policy = request.backend.get_account_policy(
284 285
            request.user_uniq, v_account, external_quota=usage)
285 286
    except NotAllowedError:
......
304 305
        if TRANSLATE_UUIDS:
305 306
            try:
306 307
                groups[k] = retrieve_uuids(
307
                        getattr(request, 'token', None),
308
                        groups[k],
309
                        fail_silently=False)
308
                    getattr(request, 'token', None),
309
                    groups[k],
310
                    fail_silently=False)
310 311
            except ItemNotExists, e:
311 312
                raise faults.BadRequest(
312
                        'Bad X-Account-Group header value: %s' % e)
313
                    'Bad X-Account-Group header value: %s' % e)
313 314
        else:
314 315
            try:
315 316
                retrieve_displaynames(
......
318 319
                    fail_silently=False)
319 320
            except ItemNotExists, e:
320 321
                raise faults.BadRequest(
321
                        'Bad X-Account-Group header value: %s' % e)
322
                    'Bad X-Account-Group header value: %s' % e)
322 323
    replace = True
323 324
    if 'update' in request.GET:
324 325
        replace = False
......
437 438
    try:
438 439
        meta = request.backend.get_container_meta(request.user_uniq, v_account,
439 440
                                                  v_container, 'pithos', until)
440
        meta['object_meta'] = request.backend.list_container_meta(request.user_uniq,
441
                                                                  v_account, v_container, 'pithos', until)
441
        meta['object_meta'] = \
442
            request.backend.list_container_meta(request.user_uniq,
443
                                                v_account, v_container,
444
                                                'pithos', until)
442 445
        policy = request.backend.get_container_policy(
443 446
            request.user_uniq, v_account,
444 447
            v_container)
......
489 492
    if meta:
490 493
        try:
491 494
            request.backend.update_container_meta(request.user_uniq, v_account,
492
                                                  v_container, 'pithos', meta, replace=False)
495
                                                  v_container, 'pithos',
496
                                                  meta, replace=False)
493 497
        except NotAllowedError:
494 498
            raise faults.Forbidden('Not allowed')
495 499
        except ItemNotExists:
......
524 528
    if meta or replace:
525 529
        try:
526 530
            request.backend.update_container_meta(request.user_uniq, v_account,
527
                                                  v_container, 'pithos', meta, replace)
531
                                                  v_container, 'pithos',
532
                                                  meta, replace)
528 533
        except NotAllowedError:
529 534
            raise faults.Forbidden('Not allowed')
530 535
        except ItemNotExists:
......
536 541
            request.META.get('CONTENT_LENGTH', 0))
537 542
    content_type = request.META.get('CONTENT_TYPE')
538 543
    hashmap = []
539
    if content_type and content_type == 'application/octet-stream' and content_length != 0:
544
    if (content_type
545
            and content_type == 'application/octet-stream'
546
            and content_length != 0):
540 547
        for data in socket_read_iterator(request, content_length,
541 548
                                         request.backend.block_size):
542 549
            # TODO: Raise 408 (Request Timeout) if this takes too long.
543
            # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
550
            # TODO: Raise 499 (Client Disconnect) if a length is defined
551
            #       and we stop before getting this much data.
544 552
            hashmap.append(request.backend.put_block(data))
545 553

  
546 554
    response = HttpResponse(status=202)
......
590 598
    try:
591 599
        meta = request.backend.get_container_meta(request.user_uniq, v_account,
592 600
                                                  v_container, 'pithos', until)
593
        meta['object_meta'] = request.backend.list_container_meta(request.user_uniq,
594
                                                                  v_account, v_container, 'pithos', until)
601
        meta['object_meta'] = \
602
            request.backend.list_container_meta(request.user_uniq,
603
                                                v_account, v_container,
604
                                                'pithos', until)
595 605
        policy = request.backend.get_container_policy(
596 606
            request.user_uniq, v_account,
597 607
            v_container)
......
679 689
        if until is None:
680 690
            name = '/'.join((v_account, v_container, ''))
681 691
            name_idx = len(name)
682
            for x in request.backend.list_object_permissions(request.user_uniq,
683
                                                             v_account, v_container, prefix):
692
            for x in request.backend.list_object_permissions(
693
                    request.user_uniq, v_account, v_container, prefix):
684 694

  
685 695
                # filter out objects which are not under the container
686 696
                if name != x[:name_idx]:
687 697
                    continue
688 698

  
689 699
                object = x[name_idx:]
690
                object_permissions[object] = request.backend.get_object_permissions(
691
                    request.user_uniq, v_account, v_container, object)
700
                object_permissions[object] = \
701
                    request.backend.get_object_permissions(
702
                        request.user_uniq, v_account, v_container, object)
692 703

  
693 704
            if public_granted:
694 705
                for k, v in request.backend.list_object_public(
......
706 717
            modified_by = meta.get('modified_by')
707 718
            if modified_by:
708 719
                l = retrieve_displaynames(
709
                        getattr(request, 'token', None), [meta['modified_by']])
720
                    getattr(request, 'token', None), [meta['modified_by']])
710 721
                if l is not None and len(l) == 1:
711 722
                    meta['modified_by'] = l[0]
712 723

  
......
757 768
    version = request.GET.get('version')
758 769
    try:
759 770
        meta = request.backend.get_object_meta(request.user_uniq, v_account,
760
                                               v_container, v_object, 'pithos', version)
771
                                               v_container, v_object,
772
                                               'pithos', version)
761 773
        if version is None:
762 774
            permissions = request.backend.get_object_permissions(
763 775
                request.user_uniq,
......
833 845

  
834 846
    try:
835 847
        meta = request.backend.get_object_meta(request.user_uniq, v_account,
836
                                               v_container, v_object, 'pithos', version)
848
                                               v_container, v_object,
849
                                               'pithos', version)
837 850
        if version is None:
838 851
            permissions = request.backend.get_object_permissions(
839 852
                request.user_uniq,
......
888 901

  
889 902
        try:
890 903
            for x in objects:
891
                s, h = request.backend.get_object_hashmap(request.user_uniq,
892
                                                          v_account, src_container, x[0], x[1])
904
                s, h = \
905
                    request.backend.get_object_hashmap(request.user_uniq,
906
                                                       v_account, src_container,
907
                                                       x[0], x[1])
893 908
                sizes.append(s)
894 909
                hashmaps.append(h)
895 910
        except NotAllowedError:
......
929 944

  
930 945
        response = HttpResponse(data, status=200)
931 946
        put_object_headers(
932
                response, meta, token=getattr(request, 'token', None))
947
            response, meta, token=getattr(request, 'token', None))
933 948
        response['Content-Length'] = len(data)
934 949
        return response
935 950

  
......
951 966
    #                       requestentitytoolarge (413)
952 967

  
953 968
    # Evaluate conditions.
954
    if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
969
    if (request.META.get('HTTP_IF_MATCH')
970
            or request.META.get('HTTP_IF_NONE_MATCH')):
955 971
        try:
956 972
            meta = request.backend.get_object_meta(
957 973
                request.user_uniq, v_account,
......
988 1004
                raise faults.BadRequest('Invalid X-Move-From header')
989 1005
            version_id = copy_or_move_object(
990 1006
                request, src_account, src_container, src_name,
991
                v_account, v_container, v_object, move=True, delimiter=delimiter)
1007
                v_account, v_container, v_object,
1008
                move=True, delimiter=delimiter)
992 1009
        else:
993 1010
            try:
994 1011
                src_container, src_name = split_container_object_string(
......
997 1014
                raise faults.BadRequest('Invalid X-Copy-From header')
998 1015
            version_id = copy_or_move_object(
999 1016
                request, src_account, src_container, src_name,
1000
                v_account, v_container, v_object, move=False, delimiter=delimiter)
1017
                v_account, v_container, v_object,
1018
                move=False, delimiter=delimiter)
1001 1019
        response = HttpResponse(status=201)
1002 1020
        response['X-Object-Version'] = version_id
1003 1021
        return response
......
1049 1067
        for data in socket_read_iterator(request, content_length,
1050 1068
                                         request.backend.block_size):
1051 1069
            # TODO: Raise 408 (Request Timeout) if this takes too long.
1052
            # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
1070
            # TODO: Raise 499 (Client Disconnect) if a length is defined
1071
            #       and we stop before getting this much data.
1053 1072
            size += len(data)
1054 1073
            hashmap.append(request.backend.put_block(data))
1055 1074
            md5.update(data)
......
1060 1079
            raise faults.UnprocessableEntity('Object ETag does not match')
1061 1080

  
1062 1081
    try:
1063
        version_id = request.backend.update_object_hashmap(request.user_uniq,
1064
                                                           v_account, v_container, v_object, size, content_type,
1065
                                                           hashmap, checksum, 'pithos', meta, True, permissions)
1082
        version_id = \
1083
            request.backend.update_object_hashmap(request.user_uniq,
1084
                                                  v_account, v_container,
1085
                                                  v_object, size, content_type,
1086
                                                  hashmap, checksum,
1087
                                                  'pithos', meta, True,
1088
                                                  permissions)
1066 1089
    except NotAllowedError:
1067 1090
        raise faults.Forbidden('Not allowed')
1068 1091
    except IndexError, e:
......
1081 1104
        checksum = hashmap_md5(request.backend, hashmap, size)
1082 1105
        try:
1083 1106
            request.backend.update_object_checksum(request.user_uniq,
1084
                                                   v_account, v_container, v_object, version_id, checksum)
1107
                                                   v_account, v_container,
1108
                                                   v_object, version_id,
1109
                                                   checksum)
1085 1110
        except NotAllowedError:
1086 1111
            raise faults.Forbidden('Not allowed')
1087 1112
    if public is not None:
......
1116 1141

  
1117 1142
    checksum = file.etag
1118 1143
    try:
1119
        version_id = request.backend.update_object_hashmap(request.user_uniq,
1120
                                                           v_account, v_container, v_object, file.size, file.content_type,
1121
                                                           file.hashmap, checksum, 'pithos', {}, True)
1144
        version_id = \
1145
            request.backend.update_object_hashmap(request.user_uniq,
1146
                                                  v_account, v_container,
1147
                                                  v_object, file.size,
1148
                                                  file.content_type,
1149
                                                  file.hashmap, checksum,
1150
                                                  'pithos', {}, True)
1122 1151
    except NotAllowedError:
1123 1152
        raise faults.Forbidden('Not allowed')
1124 1153
    except ItemNotExists:
......
1154 1183
        raise faults.BadRequest('Invalid Destination header')
1155 1184

  
1156 1185
    # Evaluate conditions.
1157
    if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
1186
    if (request.META.get('HTTP_IF_MATCH')
1187
            or request.META.get('HTTP_IF_NONE_MATCH')):
1158 1188
        src_version = request.META.get('HTTP_X_SOURCE_VERSION')
1159 1189
        try:
1160 1190
            meta = request.backend.get_object_meta(
......
1169 1199
    delimiter = request.GET.get('delimiter')
1170 1200

  
1171 1201
    version_id = copy_or_move_object(request, v_account, v_container, v_object,
1172
                                     dest_account, dest_container, dest_name, move=False, delimiter=delimiter)
1202
                                     dest_account, dest_container, dest_name,
1203
                                     move=False, delimiter=delimiter)
1173 1204
    response = HttpResponse(status=201)
1174 1205
    response['X-Object-Version'] = version_id
1175 1206
    return response
......
1196 1227
        raise faults.BadRequest('Invalid Destination header')
1197 1228

  
1198 1229
    # Evaluate conditions.
1199
    if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
1230
    if (request.META.get('HTTP_IF_MATCH')
1231
            or request.META.get('HTTP_IF_NONE_MATCH')):
1200 1232
        try:
1201 1233
            meta = request.backend.get_object_meta(
1202 1234
                request.user_uniq, v_account,
......
1210 1242
    delimiter = request.GET.get('delimiter')
1211 1243

  
1212 1244
    version_id = copy_or_move_object(request, v_account, v_container, v_object,
1213
                                     dest_account, dest_container, dest_name, move=True, delimiter=delimiter)
1245
                                     dest_account, dest_container, dest_name,
1246
                                     move=True, delimiter=delimiter)
1214 1247
    response = HttpResponse(status=201)
1215 1248
    response['X-Object-Version'] = version_id
1216 1249
    return response
......
1237 1270
        raise faults.ItemNotFound('Object does not exist')
1238 1271

  
1239 1272
    # Evaluate conditions.
1240
    if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
1273
    if (request.META.get('HTTP_IF_MATCH')
1274
            or request.META.get('HTTP_IF_NONE_MATCH')):
1241 1275
        validate_matching_preconditions(request, prev_meta)
1242 1276

  
1243 1277
    replace = True
......
1246 1280

  
1247 1281
    # A Content-Type or X-Source-Object header indicates data updates.
1248 1282
    src_object = request.META.get('HTTP_X_SOURCE_OBJECT')
1249
    if (not content_type or content_type != 'application/octet-stream') and not src_object:
1283
    if ((not content_type or content_type != 'application/octet-stream')
1284
            and not src_object):
1250 1285
        response = HttpResponse(status=202)
1251 1286

  
1252 1287
        # Do permissions first, as it may fail easier.
1253 1288
        if permissions is not None:
1254 1289
            try:
1255 1290
                request.backend.update_object_permissions(request.user_uniq,
1256
                                                          v_account, v_container, v_object, permissions)
1291
                                                          v_account,
1292
                                                          v_container, v_object,
1293
                                                          permissions)
1257 1294
            except NotAllowedError:
1258 1295
                raise faults.Forbidden('Not allowed')
1259 1296
            except ItemNotExists:
......
1293 1330
        raise faults.RangeNotSatisfiable('Invalid Content-Range header')
1294 1331

  
1295 1332
    try:
1296
        size, hashmap = request.backend.get_object_hashmap(request.user_uniq,
1297
                                                           v_account, v_container, v_object)
1333
        size, hashmap = \
1334
            request.backend.get_object_hashmap(request.user_uniq,
1335
                                               v_account, v_container, v_object)
1298 1336
    except NotAllowedError:
1299 1337
        raise faults.Forbidden('Not allowed')
1300 1338
    except ItemNotExists:
......
1304 1342
    if offset is None:
1305 1343
        offset = size
1306 1344
    elif offset > size:
1307
        raise faults.RangeNotSatisfiable('Supplied offset is beyond object limits')
1345
        raise faults.RangeNotSatisfiable(
1346
            'Supplied offset is beyond object limits')
1308 1347
    if src_object:
1309 1348
        src_account = request.META.get('HTTP_X_SOURCE_ACCOUNT')
1310 1349
        if not src_account:
......
1323 1362
        if length is None:
1324 1363
            length = src_size
1325 1364
        elif length > src_size:
1326
            raise faults.BadRequest('Object length is smaller than range length')
1365
            raise faults.BadRequest(
1366
                'Object length is smaller than range length')
1327 1367
    else:
1328 1368
        # Require either a Content-Length, or 'chunked' Transfer-Encoding.
1329 1369
        content_length = -1
......
1337 1377
                # TODO: Get up to length bytes in chunks.
1338 1378
                length = content_length
1339 1379
            elif length != content_length:
1340
                raise faults.BadRequest('Content length does not match range length')
1341
    if total is not None and (total != size or offset >= size or (length > 0 and offset + length >= size)):
1380
                raise faults.BadRequest(
1381
                    'Content length does not match range length')
1382
    if (total is not None
1383
            and (total != size or offset >= size
1384
                 or (length > 0 and offset + length >= size))):
1342 1385
        raise faults.RangeNotSatisfiable(
1343 1386
            'Supplied range will change provided object limits')
1344 1387

  
......
1384 1427
        for d in socket_read_iterator(request, length,
1385 1428
                                      request.backend.block_size):
1386 1429
            # TODO: Raise 408 (Request Timeout) if this takes too long.
1387
            # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
1430
            # TODO: Raise 499 (Client Disconnect) if a length is defined
1431
            #       and we stop before getting this much data.
1388 1432
            data += d
1389 1433
            bytes = put_object_block(request, hashmap, data, offset)
1390 1434
            offset += bytes
......
1400 1444
    checksum = hashmap_md5(
1401 1445
        request.backend, hashmap, size) if UPDATE_MD5 else ''
1402 1446
    try:
1403
        version_id = request.backend.update_object_hashmap(request.user_uniq,
1404
                                                           v_account, v_container, v_object, size, prev_meta[
1405
                                                           'type'],
1406
                                                           hashmap, checksum, 'pithos', meta, replace, permissions)
1447
        version_id = \
1448
            request.backend.update_object_hashmap(request.user_uniq,
1449
                                                  v_account, v_container,
1450
                                                  v_object, size,
1451
                                                  prev_meta['type'],
1452
                                                  hashmap, checksum, 'pithos',
1453
                                                  meta, replace, permissions)
1407 1454
    except NotAllowedError:
1408 1455
        raise faults.Forbidden('Not allowed')
1409 1456
    except ItemNotExists:

Also available in: Unified diff