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
import datetime
import logging
import re
+import hashlib
logger = logging.getLogger(__name__)
for k in [x for x in meta.keys() if x.startswith('X-Container-Meta-')]:
response[k.encode('utf-8')] = meta[k].encode('utf-8')
response['X-Container-Object-Meta'] = [x[14:] for x in meta['object_meta'] if x.startswith('X-Object-Meta-')]
+ response['X-Container-Block-Size'] = backend.block_size
+ response['X-Container-Block-Hash'] = backend.hash_algorithm
def get_object_meta(request):
"""Get metadata from an object request"""
if if_modified_since is not None:
if_modified_since = parse_http_date_safe(if_modified_since)
if if_modified_since is not None and int(meta['modified']) <= if_modified_since:
- raise NotModified('Object has not been modified')
+ raise NotModified('Resource has not been modified')
if_unmodified_since = request.META.get('HTTP_IF_UNMODIFIED_SINCE')
if if_unmodified_since is not None:
if_unmodified_since = parse_http_date_safe(if_unmodified_since)
if if_unmodified_since is not None and int(meta['modified']) > if_unmodified_since:
- raise PreconditionFailed('Object has been modified')
+ raise PreconditionFailed('Resource has been modified')
def validate_matching_preconditions(request, meta):
"""Check that the ETag conforms with the preconditions set"""
if_match = request.META.get('HTTP_IF_MATCH')
if if_match is not None and if_match != '*':
if meta['hash'] not in [x.lower() for x in parse_etags(if_match)]:
- raise PreconditionFailed('Object Etag does not match')
+ raise PreconditionFailed('Resource Etag does not match')
if_none_match = request.META.get('HTTP_IF_NONE_MATCH')
if if_none_match is not None:
if if_none_match == '*' or meta['hash'] in [x.lower() for x in parse_etags(if_none_match)]:
- raise NotModified('Object Etag matches')
+ raise NotModified('Resource Etag matches')
def copy_or_move_object(request, src_path, dest_path, move=False):
"""Copy or move an object"""
total = int(total)
else:
total = None
- if (upto and offset > upto) or \
- (total and offset >= total) or \
- (total and upto and upto >= total):
+ if (upto is not None and offset > upto) or \
+ (total is not None and offset >= total) or \
+ (total is not None and upto is not None and upto >= total):
return None
- if not upto:
+ if upto is None:
length = None
else:
length = upto - offset + 1
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()
+
+ if len(hashmap) == 0:
+ return hexlify(subhash(''))
+ if len(hashmap) == 1:
+ return hexlify(subhash(hashmap[0]))
+ s = 2
+ while s < len(hashmap):
+ s = s * 2
+ h = hashmap + ([('\x00' * len(hashmap[0]))] * (s - len(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'