Limit metadata in object headers accessed via /public. Simplify implementation.
authorAntony Chazapis <chazapis@gmail.com>
Thu, 9 Jun 2011 14:09:29 +0000 (17:09 +0300)
committerAntony Chazapis <chazapis@gmail.com>
Thu, 9 Jun 2011 14:09:29 +0000 (17:09 +0300)
Refs #595

pithos/api/functions.py
pithos/api/util.py
pithos/public/functions.py

index 71d8b05..68cf2a9 100644 (file)
@@ -34,7 +34,6 @@
 import os
 import logging
 import hashlib
-import uuid
 
 from django.http import HttpResponse
 from django.template.loader import render_to_string
@@ -46,8 +45,8 @@ from pithos.api.faults import (Fault, NotModified, BadRequest, Unauthorized, Ite
 from pithos.api.util import (format_meta_key, printable_meta_dict, get_account_meta,
     put_account_meta, get_container_meta, put_container_meta, get_object_meta, put_object_meta,
     validate_modification_preconditions, validate_matching_preconditions, copy_or_move_object,
-    get_version, get_content_length, get_range, get_content_range, raw_input_socket,
-    socket_read_iterator, ObjectWrapper, hashmap_hash, api_method)
+    get_version, get_content_length, get_content_range, raw_input_socket,
+    socket_read_iterator, object_data_response, hashmap_hash, api_method)
 from pithos.backends import backend
 
 
@@ -422,36 +421,7 @@ def object_read(request, v_account, v_container, v_object):
         response['Content-Length'] = len(data)
         return response
     
-    # Range handling.
-    ranges = get_range(request, size)
-    if ranges is None:
-        ranges = [(0, size)]
-        ret = 200
-    else:
-        check = [True for offset, length in ranges if
-                    length <= 0 or length > size or
-                    offset < 0 or offset >= size or
-                    offset + length > size]
-        if len(check) > 0:
-            raise RangeNotSatisfiable('Requested range exceeds object limits')        
-        ret = 206
-    
-    if ret == 206 and len(ranges) > 1:
-        boundary = uuid.uuid4().hex
-    else:
-        boundary = ''
-    wrapper = ObjectWrapper(v_account, v_container, v_object, ranges, size, hashmap, boundary)
-    response = HttpResponse(wrapper, status=ret)
-    put_object_meta(response, meta)
-    if ret == 206:
-        if len(ranges) == 1:
-            offset, length = ranges[0]
-            response['Content-Length'] = length # Update with the correct length.
-            response['Content-Range'] = 'bytes %d-%d/%d' % (offset, offset + length - 1, size)
-        else:
-            del(response['Content-Length'])
-            response['Content-Type'] = 'multipart/byteranges; boundary=%s' % (boundary,)
-    return response
+    return object_data_response(request, size, hashmap, meta)
 
 @api_method('PUT')
 def object_write(request, v_account, v_container, v_object):
index 2c38f6d..d2dda0c 100644 (file)
@@ -43,13 +43,14 @@ from django.utils.http import http_date, parse_etags
 
 from pithos.api.compat import parse_http_date_safe
 from pithos.api.faults import (Fault, NotModified, BadRequest, ItemNotFound, LengthRequired,
-                                PreconditionFailed, ServiceUnavailable)
+                                PreconditionFailed, RangeNotSatisfiable, ServiceUnavailable)
 from pithos.backends import backend
 
 import datetime
 import logging
 import re
 import hashlib
+import uuid
 
 
 logger = logging.getLogger(__name__)
@@ -120,19 +121,24 @@ def get_object_meta(request):
         meta['X-Object-Public'] = request.META['HTTP_X_OBJECT_PUBLIC']
     return meta
 
-def put_object_meta(response, meta):
+def put_object_meta(response, meta, public=False):
     """Put metadata in an object response."""
     response['ETag'] = meta['hash']
     response['Content-Length'] = meta['bytes']
     response['Content-Type'] = meta.get('Content-Type', 'application/octet-stream')
     response['Last-Modified'] = http_date(int(meta['modified']))
-    response['X-Object-Version'] = meta['version']
-    response['X-Object-Version-Timestamp'] = meta['version_timestamp']
-    for k in [x for x in meta.keys() if x.startswith('X-Object-Meta-')]:
-        response[k.encode('utf-8')] = meta[k].encode('utf-8')
-    for k in ('Content-Encoding', 'Content-Disposition', 'X-Object-Manifest', 'X-Object-Public'):
-        if k in meta:
-            response[k] = meta[k]
+    if not public:
+        response['X-Object-Version'] = meta['version']
+        response['X-Object-Version-Timestamp'] = meta['version_timestamp']
+        for k in [x for x in meta.keys() if x.startswith('X-Object-Meta-')]:
+            response[k.encode('utf-8')] = meta[k].encode('utf-8')
+        for k in ('Content-Encoding', 'Content-Disposition', 'X-Object-Manifest', 'X-Object-Public'):
+            if k in meta:
+                response[k] = meta[k]
+    else:
+        for k in ('Content-Encoding', 'Content-Disposition', 'X-Object-Manifest'):
+            if k in meta:
+                response[k] = meta[k]
 
 def validate_modification_preconditions(request, meta):
     """Check that the modified timestamp conforms with the preconditions set."""
@@ -376,10 +382,7 @@ class ObjectWrapper(object):
     Read from the object using the offset and length provided in each entry of the range list.
     """
     
-    def __init__(self, v_account, v_container, v_object, ranges, size, hashmap, boundary):
-        self.v_account = v_account
-        self.v_container = v_container
-        self.v_object = v_object
+    def __init__(self, ranges, size, hashmap, boundary):
         self.ranges = ranges
         self.size = size
         self.hashmap = hashmap
@@ -444,6 +447,40 @@ class ObjectWrapper(object):
                 out.append('')
                 return '\r\n'.join(out)
 
+def object_data_response(request, size, hashmap, meta, public=False):
+    """Get the HttpResponse object for replying with the object's data."""
+    
+    # Range handling.
+    ranges = get_range(request, size)
+    if ranges is None:
+        ranges = [(0, size)]
+        ret = 200
+    else:
+        check = [True for offset, length in ranges if
+                    length <= 0 or length > size or
+                    offset < 0 or offset >= size or
+                    offset + length > size]
+        if len(check) > 0:
+            raise RangeNotSatisfiable('Requested range exceeds object limits')        
+        ret = 206
+    
+    if ret == 206 and len(ranges) > 1:
+        boundary = uuid.uuid4().hex
+    else:
+        boundary = ''
+    wrapper = ObjectWrapper(ranges, size, hashmap, boundary)
+    response = HttpResponse(wrapper, status=ret)
+    put_object_meta(response, meta, public)
+    if ret == 206:
+        if len(ranges) == 1:
+            offset, length = ranges[0]
+            response['Content-Length'] = length # Update with the correct length.
+            response['Content-Range'] = 'bytes %d-%d/%d' % (offset, offset + length - 1, size)
+        else:
+            del(response['Content-Length'])
+            response['Content-Type'] = 'multipart/byteranges; boundary=%s' % (boundary,)
+    return response
+
 def hashmap_hash(hashmap):
     """Produce the root hash, treating the hashmap as a Merkle-like tree."""
     
index 3d62d6d..8fc54cb 100644 (file)
 # or implied, of GRNET S.A.
 
 import logging
-import uuid
 
 from django.http import HttpResponse
 
-from pithos.api.faults import (Fault, BadRequest, ItemNotFound, RangeNotSatisfiable)
+from pithos.api.faults import (Fault, BadRequest, ItemNotFound)
 from pithos.api.util import (put_object_meta, validate_modification_preconditions,
-    validate_matching_preconditions, get_range, ObjectWrapper, api_method)
+    validate_matching_preconditions, object_data_response, api_method)
 from pithos.backends import backend
 
 
@@ -72,7 +71,7 @@ def object_meta(request, v_account, v_container, v_object):
         raise ItemNotFound('Object does not exist')
     
     response = HttpResponse(status=204)
-    put_object_meta(response, meta)
+    put_object_meta(response, meta, True)
     return response
 
 @api_method('GET')
@@ -108,36 +107,7 @@ def object_read(request, v_account, v_container, v_object):
     except NameError:
         raise ItemNotFound('Object does not exist')
     
-    # Range handling.
-    ranges = get_range(request, size)
-    if ranges is None:
-        ranges = [(0, size)]
-        ret = 200
-    else:
-        check = [True for offset, length in ranges if
-                    length <= 0 or length > size or
-                    offset < 0 or offset >= size or
-                    offset + length > size]
-        if len(check) > 0:
-            raise RangeNotSatisfiable('Requested range exceeds object limits')        
-        ret = 206
-    
-    if ret == 206 and len(ranges) > 1:
-        boundary = uuid.uuid4().hex
-    else:
-        boundary = ''
-    wrapper = ObjectWrapper(v_account, v_container, v_object, ranges, size, hashmap, boundary)
-    response = HttpResponse(wrapper, status=ret)
-    put_object_meta(response, meta)
-    if ret == 206:
-        if len(ranges) == 1:
-            offset, length = ranges[0]
-            response['Content-Length'] = length # Update with the correct length.
-            response['Content-Range'] = 'bytes %d-%d/%d' % (offset, offset + length - 1, size)
-        else:
-            del(response['Content-Length'])
-            response['Content-Type'] = 'multipart/byteranges; boundary=%s' % (boundary,)
-    return response
+    return object_data_response(request, size, hashmap, meta, True)
 
 @api_method()
 def method_not_allowed(request):