========================= ================================
Revision Description
========================= ================================
-0.7 (Oct 4, 2011) Suggest upload/download methods using hashmaps.
+0.7 (Oct 13, 2011) Suggest upload/download methods using hashmaps.
\ Propose syncing algorithm.
\ Support cross-account object copy and move.
\ Pass token as a request parameter when using ``POST`` via an HTML form.
\ Optionally use source account to update object from another object.
\ Use container ``POST`` to upload missing blocks of data.
+\ Report policy in account headers.
0.6 (Sept 13, 2011) Reply with Merkle hash as the ETag when updating objects.
\ Include version id in object replace/change replies.
\ Change conflict (409) replies format to text.
Reply Header Name Value
========================== =====================
X-Account-Container-Count The total number of containers
-X-Account-Object-Count The total number of objects (**TBD**)
X-Account-Bytes-Used The total number of bytes stored
-X-Account-Bytes-Remaining The total number of bytes remaining
-X-Account-Last-Login The last login (**TBD**)
X-Account-Until-Timestamp The last account modification date until the timestamp provided
X-Account-Group-* Optional user defined groups
+X-Account-Policy-* Account behavior and limits
X-Account-Meta-* Optional user defined metadata
Last-Modified The last account modification date (regardless of ``until``)
========================== =====================
* Support for ``X-Account-Meta-*`` style headers at the account level. Use ``POST`` to update.
* Support for ``X-Container-Meta-*`` style headers at the container level. Can be set when creating via ``PUT``. Use ``POST`` to update.
* Header ``X-Container-Object-Meta`` at the container level and parameter ``meta`` in container listings. (**TBD**)
-* Container policies to manage behavior and limits.
+* Account and container policies to manage behavior and limits. Container behavior overrides account settings. Account quota sets the maximum bytes limit, regardless of container values.
* Headers ``X-Container-Block-*`` at the container level, exposing the underlying storage characteristics.
* All metadata replies, at all levels, include latest modification information.
* At all levels, a ``HEAD`` or ``GET`` request may use ``If-Modified-Since`` and ``If-Unmodified-Since`` headers.
try:
meta = request.backend.get_account_meta(request.user, v_account, until)
groups = request.backend.get_account_groups(request.user, v_account)
+ policy = request.backend.get_account_policy(request.user, v_account)
except NotAllowedError:
raise Unauthorized('Access denied')
validate_modification_preconditions(request, meta)
response = HttpResponse(status=204)
- put_account_headers(response, request.quota, meta, groups)
+ put_account_headers(response, meta, groups, policy)
return response
@api_method('POST')
try:
meta = request.backend.get_account_meta(request.user, v_account, until)
groups = request.backend.get_account_groups(request.user, v_account)
+ policy = request.backend.get_account_policy(request.user, v_account)
except NotAllowedError:
raise Unauthorized('Access denied')
validate_modification_preconditions(request, meta)
response = HttpResponse()
- put_account_headers(response, request.quota, meta, groups)
+ put_account_headers(response, meta, groups, policy)
marker = request.GET.get('marker')
limit = get_int_parameter(request.GET.get('limit'))
# badRequest (400)
meta, policy = get_container_headers(request)
- try:
- if policy and int(policy.get('quota', 0)) > request.quota:
- policy['quota'] = request.quota
- except:
- raise BadRequest('Invalid quota header')
try:
request.backend.put_container(request.user, v_account, v_container, policy)
replace = False
if policy:
try:
- if int(policy.get('quota', 0)) > request.quota:
- policy['quota'] = request.quota
- except:
- raise BadRequest('Invalid quota header')
- try:
request.backend.update_container_policy(request.user, v_account,
v_container, policy, replace)
except NotAllowedError:
groups[n].remove('')
return meta, groups
-def put_account_headers(response, quota, meta, groups):
+def put_account_headers(response, meta, groups, policy):
if 'count' in meta:
response['X-Account-Container-Count'] = meta['count']
if 'bytes' in meta:
response['X-Account-Bytes-Used'] = meta['bytes']
- if quota:
- response['X-Account-Bytes-Remaining'] = quota - meta['bytes']
response['Last-Modified'] = http_date(int(meta['modified']))
for k in [x for x in meta.keys() if x.startswith('X-Account-Meta-')]:
response[smart_str(k, strings_only=True)] = smart_str(meta[k], strings_only=True)
k = format_header_key('X-Account-Group-' + k)
v = smart_str(','.join(v), strings_only=True)
response[k] = v
-
+ for k, v in policy.iteritems():
+ response[smart_str(format_header_key('X-Account-Policy-' + k), strings_only=True)] = smart_str(v, strings_only=True)
+
def get_container_headers(request):
meta = get_header_prefix(request, 'X-Container-Meta-')
policy = dict([(k[19:].lower(), v.replace(' ', '')) for k, v in get_header_prefix(request, 'X-Container-Policy-').iteritems()])
logger.debug("get_account_policy: %s", account)
if user != account:
- raise NotAllowedError
+ if account not in self._allowed_accounts(user):
+ raise NotAllowedError
+ return {}
path, node = self._lookup_account(account, True)
- return self.node.policy_get(node)
+ policy = self.default_policy.copy()
+ policy.update(self.node.policy_get(node))
+ return policy
@backend_method
def update_account_policy(self, user, account, policy, replace=False):
raise NotAllowedError
return {}
path, node = self._lookup_container(account, container)
- return self.node.policy_get(node)
+ policy = self.default_policy.copy()
+ policy.update(self.node.policy_get(node))
+ return policy
@backend_method
def update_container_policy(self, user, account, container, policy, replace=False):
request.user_obj = user
request.user = user.uniq
- request.quota = user.quota