import os
import logging
import hashlib
-import uuid
from django.http import HttpResponse
from django.template.loader import render_to_string
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
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):
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__)
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."""
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
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."""
# 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
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')
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):