========================= ================================
Revision Description
========================= ================================
-0.7 (Oct 13, 2011) Suggest upload/download methods using hashmaps.
+0.7 (Oct 17, 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.
+\ Add insufficient quota reply.
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.
The ``X-Object-Sharing`` header may include either a ``read=...`` comma-separated user/group list, or a ``write=...`` comma-separated user/group list, or both separated by a semicolon (``;``). Groups are specified as ``<account>:<group>``. To publish the object, set ``X-Object-Public`` to ``true``. To unpublish, set to ``false``, or use an empty header value.
-=========================== ==============================
-Return Code Description
-=========================== ==============================
-201 (Created) The object has been created
-409 (Conflict) The object can not be created from the provided hashmap, or there are conflicting permissions (a list of missing hashes, or a list of conflicting sharing paths will be included in the reply - in simple text format)
-411 (Length Required) Missing ``Content-Length`` or ``Content-Type`` in the request
-422 (Unprocessable Entity) The MD5 checksum of the data written to the storage system does not match the (optionally) supplied ETag value
-=========================== ==============================
+============================== ==============================
+Return Code Description
+============================== ==============================
+201 (Created) The object has been created
+409 (Conflict) The object can not be created from the provided hashmap, or there are conflicting permissions (a list of missing hashes, or a list of conflicting sharing paths will be included in the reply - in simple text format)
+411 (Length Required) Missing ``Content-Length`` or ``Content-Type`` in the request
+413 (Request Entity Too Large) Insufficient quota to complete the request
+422 (Unprocessable Entity) The MD5 checksum of the data written to the storage system does not match the (optionally) supplied ETag value
+============================== ==============================
COPY
|
-=========================== ==============================
-Return Code Description
-=========================== ==============================
-201 (Created) The object has been created
-409 (Conflict) There are conflicting permissions (a list of conflicting sharing paths will be included in the reply - in simple text format)
-=========================== ==============================
+============================== ==============================
+Return Code Description
+============================== ==============================
+201 (Created) The object has been created
+409 (Conflict) There are conflicting permissions (a list of conflicting sharing paths will be included in the reply - in simple text format)
+413 (Request Entity Too Large) Insufficient quota to complete the request
+============================== ==============================
MOVE
|
-=========================== ==============================
-Return Code Description
-=========================== ==============================
-202 (Accepted) The request has been accepted (not a data update)
-204 (No Content) The request succeeded (data updated)
-409 (Conflict) There are conflicting permissions (a list of conflicting sharing paths will be included in the reply - in simple text format)
-411 (Length Required) Missing ``Content-Length`` in the request
-416 (Range Not Satisfiable) The supplied range is invalid
-=========================== ==============================
+============================== ==============================
+Return Code Description
+============================== ==============================
+202 (Accepted) The request has been accepted (not a data update)
+204 (No Content) The request succeeded (data updated)
+409 (Conflict) There are conflicting permissions (a list of conflicting sharing paths will be included in the reply - in simple text format)
+411 (Length Required) Missing ``Content-Length`` in the request
+413 (Request Entity Too Large) Insufficient quota to complete the request
+416 (Range Not Satisfiable) The supplied range is invalid
+============================== ==============================
The ``POST`` method can also be used for creating an object via a standard HTML form. If the request ``Content-Type`` is ``multipart/form-data``, none of the above headers will be processed. The form should have an ``X-Object-Data`` field, as in the following example. The token is passed as a request parameter. ::
|
-=========================== ==============================
-Return Code Description
-=========================== ==============================
-201 (Created) The object has been created
-=========================== ==============================
+============================== ==============================
+Return Code Description
+============================== ==============================
+201 (Created) The object has been created
+413 (Request Entity Too Large) Insufficient quota to complete the request
+============================== ==============================
DELETE
from xml.dom import minidom
from pithos.api.faults import (Fault, NotModified, BadRequest, Unauthorized, ItemNotFound, Conflict,
- LengthRequired, PreconditionFailed, RangeNotSatisfiable, UnprocessableEntity)
+ LengthRequired, PreconditionFailed, RequestEntityTooLarge, RangeNotSatisfiable, UnprocessableEntity)
from pithos.api.util import (rename_meta_key, format_header_key, printable_header_dict, get_account_headers,
put_account_headers, get_container_headers, put_container_headers, get_object_headers, put_object_headers,
update_manifest_meta, update_sharing_meta, update_public_meta, validate_modification_preconditions,
get_int_parameter, get_content_length, get_content_range, socket_read_iterator,
object_data_response, put_object_block, hashmap_hash, api_method, json_encode_decimal)
from pithos.backends import connect_backend
-from pithos.backends.base import NotAllowedError
+from pithos.backends.base import NotAllowedError, QuotaError
logger = logging.getLogger(__name__)
raise BadRequest('Invalid sharing header')
except AttributeError, e:
raise Conflict('\n'.join(e.data) + '\n')
+ except QuotaError:
+ raise RequestEntityTooLarge('Quota exceeded')
if public is not None:
try:
request.backend.update_object_public(request.user, v_account,
raise Unauthorized('Access denied')
except NameError:
raise ItemNotFound('Container does not exist')
+ except QuotaError:
+ raise RequestEntityTooLarge('Quota exceeded')
response = HttpResponse(status=201)
response['ETag'] = meta['hash']
raise BadRequest('Invalid sharing header')
except AttributeError, e:
raise Conflict('\n'.join(e.data) + '\n')
+ except QuotaError:
+ raise RequestEntityTooLarge('Quota exceeded')
if public is not None:
try:
request.backend.update_object_public(request.user, v_account,
from pithos.api.compat import parse_http_date_safe, parse_http_date
from pithos.api.faults import (Fault, NotModified, BadRequest, Unauthorized, ItemNotFound,
- Conflict, LengthRequired, PreconditionFailed, RangeNotSatisfiable,
- ServiceUnavailable)
+ Conflict, LengthRequired, PreconditionFailed, RequestEntityTooLarge,
+ RangeNotSatisfiable, ServiceUnavailable)
from pithos.backends import connect_backend
-from pithos.backends.base import NotAllowedError
+from pithos.backends.base import NotAllowedError, QuotaError
import logging
import re
raise BadRequest('Invalid sharing header')
except AttributeError, e:
raise Conflict('\n'.join(e.data) + '\n')
+ except QuotaError:
+ raise RequestEntityTooLarge('Quota exceeded')
if public is not None:
try:
request.backend.update_object_public(request.user, dest_account, dest_container, dest_name, public)
class NotAllowedError(Exception):
pass
+class QuotaError(Exception):
+ pass
+
class BaseBackend(object):
"""Abstract backend class that serves as a reference for actual implementations.
ValueError: Invalid users/groups in permissions
AttributeError: Can not set permissions
+
+ QuotaError: Account or container quota exceeded
"""
return ''
ValueError: Invalid users/groups in permissions
AttributeError: Can not set permissions
+
+ QuotaError: Account or container quota exceeded
"""
return ''
ValueError: Invalid users/groups in permissions
AttributeError: Can not set permissions
+
+ QuotaError: Account or container quota exceeded
"""
return ''
import hashlib
import binascii
-from base import NotAllowedError, BaseBackend
+from base import NotAllowedError, QuotaError, BaseBackend
from lib.hashfiler import Mapper, Blocker
( CLUSTER_NORMAL, CLUSTER_HISTORY, CLUSTER_DELETED ) = range(3)
if (account_quota > 0 and self._get_statistics(account_node)[1] + size_delta > account_quota) or \
(container_quota > 0 and self._get_statistics(container_node)[1] + size_delta > container_quota):
# This must be executed in a transaction, so the version is never created if it fails.
- raise
+ raise QuotaError
if not replace_meta and src_version_id is not None:
self.node.attribute_copy(src_version_id, dest_version_id)