Produce new ETag when updating an object.
authorAntony Chazapis <chazapis@gmail.com>
Tue, 31 May 2011 13:45:44 +0000 (16:45 +0300)
committerAntony Chazapis <chazapis@gmail.com>
Tue, 31 May 2011 13:45:44 +0000 (16:45 +0300)
pithos/api/functions.py
pithos/api/util.py

index 91f753b..9e9ecc5 100644 (file)
@@ -47,7 +47,7 @@ from pithos.api.util import (format_meta_key, printable_meta_dict, get_account_m
     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_content_length, get_range, get_content_range, raw_input_socket, socket_read_iterator,
-    ObjectWrapper, api_method)
+    ObjectWrapper, hashmap_hash, api_method)
 from pithos.backends import backend
 
 
@@ -637,11 +637,9 @@ def object_update(request, v_account, v_container, v_object):
         raise ItemNotFound('Container does not exist')
     
     # Update ETag.
-    # TODO: Decide on the new ETag to use here.
+    # TODO: Move this to the backend.
     meta = {}
-    md5 = hashlib.md5()
-    md5.update(str(hashmap))
-    meta['hash'] = md5.hexdigest().lower()
+    meta['hash'] = hashmap_hash(hashmap)
     try:
         backend.update_object_meta(request.user, v_container, v_object, meta)
     except NameError:
index 175e1cd..54a493e 100644 (file)
@@ -35,6 +35,7 @@ from functools import wraps
 from time import time
 from traceback import format_exc
 from wsgiref.handlers import format_date_time
+from binascii import hexlify
 
 from django.conf import settings
 from django.http import HttpResponse
@@ -427,6 +428,21 @@ class ObjectWrapper(object):
                 out.append('')
                 return '\r\n'.join(out)
 
+def hashmap_hash(hashmap):
+    """ Produce the root hash, treating the hashmap as a Merkle-like tree."""
+    
+    def subhash(d):
+        h = hashlib.new(backend.hash_algorithm)
+        h.update(d)
+        return h.digest()
+    
+    # TODO: Should create the whole tree and decide what to do with fillers.
+    h = hashmap
+    h = [subhash(h[x] + (h[x + 1] if x + 1 < len(h) else '')) for x in range(0, len(h), 2)]
+    while len(h) > 1:
+        h = [subhash(h[x] + (h[x + 1] if x + 1 < len(h) else '')) for x in range(0, len(h), 2)]
+    return hexlify(h[0])
+
 def update_response_headers(request, response):
     if request.serialization == 'xml':
         response['Content-Type'] = 'application/xml; charset=UTF-8'