Use format for uploaded blocks hash lists at the container level.
[pithos] / pithos / api / util.py
index 449a96a..5e80dec 100644 (file)
@@ -1,4 +1,4 @@
-# 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
@@ -41,6 +41,7 @@ from urllib import quote, unquote
 
 from django.conf import settings
 from django.http import HttpResponse
+from django.template.loader import render_to_string
 from django.utils import simplejson as json
 from django.utils.http import http_date, parse_etags
 from django.utils.encoding import smart_unicode, smart_str
@@ -48,11 +49,10 @@ from django.core.files.uploadhandler import FileUploadHandler
 from django.core.files.uploadedfile import UploadedFile
 
 from pithos.lib.compat import parse_http_date_safe, parse_http_date
-from pithos.lib.hashmap import HashMap
 
 from pithos.api.faults import (Fault, NotModified, BadRequest, Unauthorized, Forbidden, ItemNotFound,
                                 Conflict, LengthRequired, PreconditionFailed, RequestEntityTooLarge,
-                                RangeNotSatisfiable, ServiceUnavailable)
+                                RangeNotSatisfiable, InternalServerError, NotImplemented)
 from pithos.api.short_url import encode_url
 from pithos.backends import connect_backend
 from pithos.backends.base import NotAllowedError, QuotaError
@@ -180,7 +180,8 @@ def get_object_headers(request):
     return meta, get_sharing(request), get_public(request)
 
 def put_object_headers(response, meta, restricted=False):
-    response['ETag'] = meta['ETag'] if 'ETag' in meta else meta['hash']
+    if 'ETag' in meta:
+        response['ETag'] = meta['ETag']
     response['Content-Length'] = meta['bytes']
     response['Content-Type'] = meta.get('Content-Type', 'application/octet-stream')
     response['Last-Modified'] = http_date(int(meta['modified']))
@@ -302,6 +303,8 @@ def split_container_object_string(s):
 def copy_or_move_object(request, src_account, src_container, src_name, dest_account, dest_container, dest_name, move=False):
     """Copy or move an object."""
     
+    if 'ignore_content_type' in request.GET and 'CONTENT_TYPE' in request.META:
+        del(request.META['CONTENT_TYPE'])
     meta, permissions, public = get_object_headers(request)
     src_version = request.META.get('HTTP_X_SOURCE_VERSION')
     try:
@@ -320,7 +323,7 @@ def copy_or_move_object(request, src_account, src_container, src_name, dest_acco
     except ValueError:
         raise BadRequest('Invalid sharing header')
     except AttributeError, e:
-        raise Conflict('\n'.join(e.data) + '\n')
+        raise Conflict(simple_list_response(request, e.data))
     except QuotaError:
         raise RequestEntityTooLarge('Quota exceeded')
     if public is not None:
@@ -497,7 +500,7 @@ def raw_input_socket(request):
         return request._req
     if 'wsgi.input' in request.environ:
         return request.environ['wsgi.input']
-    raise ServiceUnavailable('Unknown server software')
+    raise NotImplemented('Unknown server software')
 
 MAX_UPLOAD_SIZE = 5 * (1024 * 1024 * 1024) # 5GB
 
@@ -742,13 +745,6 @@ def put_object_block(request, hashmap, data, offset):
         hashmap.append(request.backend.put_block(('\x00' * bo) + data[:bl]))
     return bl # Return ammount of data written.
 
-#def hashmap_hash(request, hashmap):
-#    """Produce the root hash, treating the hashmap as a Merkle-like tree."""
-#    
-#    map = HashMap(request.backend.block_size, request.backend.hash_algorithm)
-#    map.extend([unhexlify(x) for x in hashmap])
-#    return hexlify(map.hash())
-
 def hashmap_md5(request, hashmap, size):
     """Produce the MD5 sum from the data in the hashmap."""
     
@@ -763,6 +759,23 @@ def hashmap_md5(request, hashmap, size):
         md5.update(data + ('\x00' * pad))
     return md5.hexdigest().lower()
 
+def simple_list_response(request, l):
+    if request.serialization == 'text':
+        return '\n'.join(l) + '\n'
+    if request.serialization == 'xml':
+        return render_to_string('items.xml', {'items': l})
+    if request.serialization == 'json':
+        return json.dumps(l)
+
+def get_backend():
+    backend = connect_backend(db_module=settings.BACKEND_DB_MODULE,
+                              db_connection=settings.BACKEND_DB_CONNECTION,
+                              block_module=settings.BACKEND_BLOCK_MODULE,
+                              block_path=settings.BACKEND_BLOCK_PATH)
+    backend.default_policy['quota'] = settings.BACKEND_QUOTA
+    backend.default_policy['versioning'] = settings.BACKEND_VERSIONING
+    return backend
+
 def update_request_headers(request):
     # Handle URL-encoded keys and values.
     # Handle URL-encoded keys and values.
@@ -808,11 +821,13 @@ def update_response_headers(request, response):
         response['Date'] = format_date_time(time())
 
 def render_fault(request, fault):
-    if settings.DEBUG or settings.TEST:
+    if isinstance(fault, InternalServerError) and (settings.DEBUG or settings.TEST):
         fault.details = format_exc(fault)
     
     request.serialization = 'text'
-    data = '\n'.join((fault.message, fault.details)) + '\n'
+    data = fault.message + '\n'
+    if fault.details:
+        data += '\n' + fault.details
     response = HttpResponse(data, status=fault.code)
     update_response_headers(request, response)
     return response
@@ -864,7 +879,7 @@ def api_method(http_method=None, format_allowed=False, user_required=True):
                 
                 # Fill in custom request variables.
                 request.serialization = request_serialization(request, format_allowed)
-                request.backend = connect_backend()
+                request.backend = get_backend()
                 
                 response = func(request, *args, **kwargs)
                 update_response_headers(request, response)
@@ -873,7 +888,7 @@ def api_method(http_method=None, format_allowed=False, user_required=True):
                 return render_fault(request, fault)
             except BaseException, e:
                 logger.exception('Unexpected error: %s' % e)
-                fault = ServiceUnavailable('Unexpected error')
+                fault = InternalServerError('Unexpected error')
                 return render_fault(request, fault)
             finally:
                 if getattr(request, 'backend', None) is not None: