-# Copyright 2011 GRNET S.A. All rights reserved.
+# Copyright 2011-2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
-import logging
-import hashlib
+from xml.dom import minidom
from django.conf import settings
from django.http import HttpResponse
from django.utils import simplejson as json
from django.utils.http import parse_etags
from django.utils.encoding import smart_str
-from xml.dom import minidom
+from django.views.decorators.csrf import csrf_exempt
from pithos.lib.filter import parse_filters
from pithos.api.faults import (Fault, NotModified, BadRequest, Unauthorized, Forbidden, ItemNotFound, Conflict,
LengthRequired, PreconditionFailed, RequestEntityTooLarge, RangeNotSatisfiable, UnprocessableEntity)
-from pithos.api.util import (rename_meta_key, format_header_key, printable_header_dict, get_account_headers,
- put_account_headers, get_container_headers, put_container_headers, get_object_headers, put_object_headers,
- update_manifest_meta, update_sharing_meta, update_public_meta, validate_modification_preconditions,
- validate_matching_preconditions, split_container_object_string, copy_or_move_object,
- get_int_parameter, get_content_length, get_content_range, socket_read_iterator, SaveToBackendHandler,
- object_data_response, put_object_block, hashmap_hash, api_method, json_encode_decimal)
+from pithos.api.util import (json_encode_decimal, rename_meta_key, format_header_key, printable_header_dict,
+ get_account_headers, put_account_headers, get_container_headers, put_container_headers, get_object_headers,
+ put_object_headers, update_manifest_meta, update_sharing_meta, update_public_meta,
+ validate_modification_preconditions, validate_matching_preconditions, split_container_object_string,
+ copy_or_move_object, get_int_parameter, get_content_length, get_content_range, socket_read_iterator,
+ SaveToBackendHandler, object_data_response, put_object_block, hashmap_md5, simple_list_response, api_method)
from pithos.backends.base import NotAllowedError, QuotaError
+import logging
+import hashlib
+
logger = logging.getLogger(__name__)
+@csrf_exempt
def top_demux(request):
if request.method == 'GET':
if getattr(request, 'user', None) is not None:
else:
return method_not_allowed(request)
+@csrf_exempt
def account_demux(request, v_account):
if request.method == 'HEAD':
return account_meta(request, v_account)
else:
return method_not_allowed(request)
+@csrf_exempt
def container_demux(request, v_account, v_container):
if request.method == 'HEAD':
return container_meta(request, v_account, v_container)
else:
return method_not_allowed(request)
+@csrf_exempt
def object_demux(request, v_account, v_container, v_object):
if request.method == 'HEAD':
return object_meta(request, v_account, v_container, v_object)
@api_method('GET', user_required=False)
def authenticate(request):
# Normal Response Codes: 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# forbidden (403),
# badRequest (400)
@api_method('GET', format_allowed=True)
def account_list(request):
# Normal Response Codes: 200, 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# badRequest (400)
response = HttpResponse()
if x == request.user_uniq:
continue
try:
- meta = request.backend.get_account_meta(request.user_uniq, x)
+ meta = request.backend.get_account_meta(request.user_uniq, x, 'pithos')
groups = request.backend.get_account_groups(request.user_uniq, x)
except NotAllowedError:
raise Forbidden('Not allowed')
@api_method('HEAD')
def account_meta(request, v_account):
# Normal Response Codes: 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# forbidden (403),
# badRequest (400)
until = get_int_parameter(request.GET.get('until'))
try:
- meta = request.backend.get_account_meta(request.user_uniq, v_account, until)
+ meta = request.backend.get_account_meta(request.user_uniq, v_account, 'pithos', until)
groups = request.backend.get_account_groups(request.user_uniq, v_account)
policy = request.backend.get_account_policy(request.user_uniq, v_account)
except NotAllowedError:
@api_method('POST')
def account_update(request, v_account):
# Normal Response Codes: 202
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# forbidden (403),
# badRequest (400)
raise BadRequest('Invalid groups header')
if meta or replace:
try:
- request.backend.update_account_meta(request.user_uniq, v_account, meta,
- replace)
+ request.backend.update_account_meta(request.user_uniq, v_account,
+ 'pithos', meta, replace)
except NotAllowedError:
raise Forbidden('Not allowed')
return HttpResponse(status=202)
@api_method('GET', format_allowed=True)
def container_list(request, v_account):
# Normal Response Codes: 200, 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
until = get_int_parameter(request.GET.get('until'))
try:
- meta = request.backend.get_account_meta(request.user_uniq, v_account, until)
+ meta = request.backend.get_account_meta(request.user_uniq, v_account, 'pithos', until)
groups = request.backend.get_account_groups(request.user_uniq, v_account)
policy = request.backend.get_account_policy(request.user_uniq, v_account)
except NotAllowedError:
for x in containers:
try:
meta = request.backend.get_container_meta(request.user_uniq, v_account,
- x, until)
+ x, 'pithos', until)
policy = request.backend.get_container_policy(request.user_uniq,
v_account, x)
except NotAllowedError:
@api_method('HEAD')
def container_meta(request, v_account, v_container):
# Normal Response Codes: 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
until = get_int_parameter(request.GET.get('until'))
try:
meta = request.backend.get_container_meta(request.user_uniq, v_account,
- v_container, until)
+ v_container, 'pithos', until)
meta['object_meta'] = request.backend.list_object_meta(request.user_uniq,
- v_account, v_container, until)
+ v_account, v_container, 'pithos', until)
policy = request.backend.get_container_policy(request.user_uniq, v_account,
v_container)
except NotAllowedError:
@api_method('PUT')
def container_create(request, v_account, v_container):
# Normal Response Codes: 201, 202
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
if meta:
try:
request.backend.update_container_meta(request.user_uniq, v_account,
- v_container, meta, replace=False)
+ v_container, 'pithos', meta, replace=False)
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
return HttpResponse(status=ret)
-@api_method('POST')
+@api_method('POST', format_allowed=True)
def container_update(request, v_account, v_container):
# Normal Response Codes: 202
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
if meta or replace:
try:
request.backend.update_container_meta(request.user_uniq, v_account,
- v_container, meta, replace)
+ v_container, 'pithos', meta, replace)
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
response = HttpResponse(status=202)
if hashmap:
- response.content = '\n'.join(hashmap) + '\n'
+ response.content = simple_list_response(request, hashmap)
return response
@api_method('DELETE')
def container_delete(request, v_account, v_container):
# Normal Response Codes: 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# conflict (409),
# itemNotFound (404),
# forbidden (403),
@api_method('GET', format_allowed=True)
def object_list(request, v_account, v_container):
# Normal Response Codes: 200, 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
until = get_int_parameter(request.GET.get('until'))
try:
meta = request.backend.get_container_meta(request.user_uniq, v_account,
- v_container, until)
+ v_container, 'pithos', until)
meta['object_meta'] = request.backend.list_object_meta(request.user_uniq,
- v_account, v_container, until)
+ v_account, v_container, 'pithos', until)
policy = request.backend.get_container_policy(request.user_uniq, v_account,
v_container)
except NotAllowedError:
try:
objects = request.backend.list_objects(request.user_uniq, v_account,
v_container, prefix, delimiter, marker,
- limit, virtual, keys, shared, until)
+ limit, virtual, 'pithos', keys, shared, until)
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
else:
try:
meta = request.backend.get_object_meta(request.user_uniq, v_account,
- v_container, x[0], x[1])
+ v_container, x[0], 'pithos', x[1])
if until is None:
permissions = request.backend.get_object_permissions(
request.user_uniq, v_account, v_container, x[0])
else:
rename_meta_key(meta, 'hash', 'x_object_hash') # Will be replaced by ETag.
rename_meta_key(meta, 'ETag', 'hash')
+ rename_meta_key(meta, 'uuid', 'x_object_uuid')
rename_meta_key(meta, 'modified', 'last_modified')
rename_meta_key(meta, 'modified_by', 'x_object_modified_by')
rename_meta_key(meta, 'version', 'x_object_version')
@api_method('HEAD')
def object_meta(request, v_account, v_container, v_object):
# Normal Response Codes: 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
version = request.GET.get('version')
try:
meta = request.backend.get_object_meta(request.user_uniq, v_account,
- v_container, v_object, version)
+ v_container, v_object, 'pithos', version)
if version is None:
permissions = request.backend.get_object_permissions(request.user_uniq,
v_account, v_container, v_object)
@api_method('GET', format_allowed=True)
def object_read(request, v_account, v_container, v_object):
# Normal Response Codes: 200, 206
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# rangeNotSatisfiable (416),
# preconditionFailed (412),
# itemNotFound (404),
try:
meta = request.backend.get_object_meta(request.user_uniq, v_account,
- v_container, v_object, version)
+ v_container, v_object, 'pithos', version)
if version is None:
permissions = request.backend.get_object_permissions(request.user_uniq,
v_account, v_container, v_object)
@api_method('PUT', format_allowed=True)
def object_write(request, v_account, v_container, v_object):
# Normal Response Codes: 201
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# unprocessableEntity (422),
# lengthRequired (411),
# conflict (409),
if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
try:
meta = request.backend.get_object_meta(request.user_uniq, v_account,
- v_container, v_object)
+ v_container, v_object, 'pithos')
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
hashmap.append(hash.firstChild.data)
except:
raise BadRequest('Invalid data formatting')
-
- meta.update({'ETag': hashmap_hash(request, hashmap)}) # Update ETag.
else:
md5 = hashlib.md5()
size = 0
try:
version_id = request.backend.update_object_hashmap(request.user_uniq,
- v_account, v_container, v_object, size, hashmap, meta,
- True, permissions)
+ v_account, v_container, v_object, size, hashmap,
+ 'pithos', meta, True, permissions)
except NotAllowedError:
raise Forbidden('Not allowed')
except IndexError, e:
- raise Conflict('\n'.join(e.data) + '\n')
+ raise Conflict(simple_list_response(request, e.data))
except NameError:
raise ItemNotFound('Container does not exist')
except ValueError:
raise BadRequest('Invalid sharing header')
- except AttributeError, e:
- raise Conflict('\n'.join(e.data) + '\n')
except QuotaError:
raise RequestEntityTooLarge('Quota exceeded')
+ if 'ETag' not in meta:
+ # Update the MD5 after the hashmap, as there may be missing hashes.
+ # TODO: This will create a new version, even if done synchronously...
+ etag = hashmap_md5(request, hashmap, size)
+ meta.update({'ETag': etag}) # Update ETag.
+ try:
+ version_id = request.backend.update_object_meta(request.user_uniq,
+ v_account, v_container, v_object, 'pithos', {'ETag': etag}, False)
+ except NotAllowedError:
+ raise Forbidden('Not allowed')
if public is not None:
try:
request.backend.update_object_public(request.user_uniq, v_account,
@api_method('POST')
def object_write_form(request, v_account, v_container, v_object):
# Normal Response Codes: 201
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
try:
version_id = request.backend.update_object_hashmap(request.user_uniq,
- v_account, v_container, v_object, file.size, file.hashmap, meta, True)
+ v_account, v_container, v_object, file.size, file.hashmap,
+ 'pithos', meta, True)
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
response = HttpResponse(status=201)
response['ETag'] = meta['ETag']
response['X-Object-Version'] = version_id
+ response.content = meta['ETag']
return response
-@api_method('COPY')
+@api_method('COPY', format_allowed=True)
def object_copy(request, v_account, v_container, v_object):
# Normal Response Codes: 201
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
src_version = request.META.get('HTTP_X_SOURCE_VERSION')
try:
meta = request.backend.get_object_meta(request.user_uniq, v_account,
- v_container, v_object, src_version)
+ v_container, v_object, 'pithos', src_version)
except NotAllowedError:
raise Forbidden('Not allowed')
except (NameError, IndexError):
response['X-Object-Version'] = version_id
return response
-@api_method('MOVE')
+@api_method('MOVE', format_allowed=True)
def object_move(request, v_account, v_container, v_object):
# Normal Response Codes: 201
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
try:
meta = request.backend.get_object_meta(request.user_uniq, v_account,
- v_container, v_object)
+ v_container, v_object, 'pithos')
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
response['X-Object-Version'] = version_id
return response
-@api_method('POST')
+@api_method('POST', format_allowed=True)
def object_update(request, v_account, v_container, v_object):
# Normal Response Codes: 202, 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# conflict (409),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)
+
meta, permissions, public = get_object_headers(request)
content_type = meta.get('Content-Type')
if content_type:
try:
prev_meta = request.backend.get_object_meta(request.user_uniq, v_account,
- v_container, v_object)
+ v_container, v_object, 'pithos')
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
raise ItemNotFound('Object does not exist')
except ValueError:
raise BadRequest('Invalid sharing header')
- except AttributeError, e:
- raise Conflict('\n'.join(e.data) + '\n')
if public is not None:
try:
request.backend.update_object_public(request.user_uniq, v_account,
if meta or replace:
try:
version_id = request.backend.update_object_meta(request.user_uniq,
- v_account, v_container, v_object, meta, replace)
+ v_account, v_container, v_object, 'pithos', meta, replace)
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
if dest_bytes is not None and dest_bytes < size:
size = dest_bytes
hashmap = hashmap[:(int((size - 1) / request.backend.block_size) + 1)]
- meta.update({'ETag': hashmap_hash(request, hashmap)}) # Update ETag.
+ meta.update({'ETag': hashmap_md5(request, hashmap, size)}) # Update ETag.
try:
version_id = request.backend.update_object_hashmap(request.user_uniq,
- v_account, v_container, v_object, size, hashmap, meta,
- replace, permissions)
+ v_account, v_container, v_object, size, hashmap,
+ 'pithos', meta, replace, permissions)
except NotAllowedError:
raise Forbidden('Not allowed')
except NameError:
raise ItemNotFound('Container does not exist')
except ValueError:
raise BadRequest('Invalid sharing header')
- except AttributeError, e:
- raise Conflict('\n'.join(e.data) + '\n')
except QuotaError:
raise RequestEntityTooLarge('Quota exceeded')
if public is not None:
@api_method('DELETE')
def object_delete(request, v_account, v_container, v_object):
# Normal Response Codes: 204
- # Error Response Codes: serviceUnavailable (503),
+ # Error Response Codes: internalServerError (500),
# itemNotFound (404),
# forbidden (403),
# badRequest (400)