Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / functions.py @ 27932481

History | View | Annotate | Download (51.7 kB)

1 2e662088 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 2715ade4 Sofia Papagiannaki
#
3 5635f9ef Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 5635f9ef Antony Chazapis
# without modification, are permitted provided that the following
5 5635f9ef Antony Chazapis
# conditions are met:
6 2715ade4 Sofia Papagiannaki
#
7 5635f9ef Antony Chazapis
#   1. Redistributions of source code must retain the above
8 5635f9ef Antony Chazapis
#      copyright notice, this list of conditions and the following
9 5635f9ef Antony Chazapis
#      disclaimer.
10 2715ade4 Sofia Papagiannaki
#
11 5635f9ef Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 5635f9ef Antony Chazapis
#      copyright notice, this list of conditions and the following
13 5635f9ef Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 5635f9ef Antony Chazapis
#      provided with the distribution.
15 2715ade4 Sofia Papagiannaki
#
16 5635f9ef Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 5635f9ef Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 5635f9ef Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 5635f9ef Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 5635f9ef Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 5635f9ef Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 5635f9ef Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 5635f9ef Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 5635f9ef Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 5635f9ef Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 5635f9ef Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 5635f9ef Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 2715ade4 Sofia Papagiannaki
#
29 5635f9ef Antony Chazapis
# The views and conclusions contained in the software and
30 5635f9ef Antony Chazapis
# documentation are those of the authors and should not be
31 5635f9ef Antony Chazapis
# interpreted as representing official policies, either expressed
32 5635f9ef Antony Chazapis
# or implied, of GRNET S.A.
33 5635f9ef Antony Chazapis
34 a7dff008 Antony Chazapis
from xml.dom import minidom
35 64b6bc45 root
from urllib import unquote
36 b956618e Antony Chazapis
37 486b2dc2 Giorgos Verigakis
from django.conf import settings
38 b956618e Antony Chazapis
from django.http import HttpResponse
39 b956618e Antony Chazapis
from django.template.loader import render_to_string
40 b956618e Antony Chazapis
from django.utils import simplejson as json
41 b956618e Antony Chazapis
from django.utils.http import parse_etags
42 88283e9e Antony Chazapis
from django.utils.encoding import smart_str
43 8fbfd37b Antony Chazapis
from django.views.decorators.csrf import csrf_exempt
44 b956618e Antony Chazapis
45 6e147ecc Antony Chazapis
from synnefo.lib.astakos import get_user
46 1713c946 Antony Chazapis
47 2715ade4 Sofia Papagiannaki
from pithos.api.faults import (
48 6255b97d Sofia Papagiannaki
    Fault, NotModified, BadRequest, Unauthorized, Forbidden, ItemNotFound,
49 6255b97d Sofia Papagiannaki
    Conflict, LengthRequired, PreconditionFailed, RequestEntityTooLarge,
50 6255b97d Sofia Papagiannaki
    RangeNotSatisfiable, UnprocessableEntity)
51 2715ade4 Sofia Papagiannaki
from pithos.api.util import (
52 6255b97d Sofia Papagiannaki
    json_encode_decimal, rename_meta_key, format_header_key,
53 6255b97d Sofia Papagiannaki
    printable_header_dict, get_account_headers, put_account_headers,
54 6255b97d Sofia Papagiannaki
    get_container_headers, put_container_headers, get_object_headers,
55 6255b97d Sofia Papagiannaki
    put_object_headers, update_manifest_meta, update_sharing_meta,
56 6255b97d Sofia Papagiannaki
    update_public_meta, validate_modification_preconditions,
57 6255b97d Sofia Papagiannaki
    validate_matching_preconditions, split_container_object_string,
58 6255b97d Sofia Papagiannaki
    copy_or_move_object, get_int_parameter, get_content_length,
59 6255b97d Sofia Papagiannaki
    get_content_range, socket_read_iterator, SaveToBackendHandler,
60 6255b97d Sofia Papagiannaki
    object_data_response, put_object_block, hashmap_md5, simple_list_response,
61 27932481 Sofia Papagiannaki
    api_method,
62 27932481 Sofia Papagiannaki
#    retrieve_uuid
63 27932481 Sofia Papagiannaki
)
64 890c2065 Sofia Papagiannaki
65 dfdf4802 Sofia Papagiannaki
from pithos.api.settings import UPDATE_MD5
66 b956618e Antony Chazapis
67 6255b97d Sofia Papagiannaki
from pithos.backends.base import (
68 6255b97d Sofia Papagiannaki
    NotAllowedError, QuotaError, ContainerNotEmpty, ItemNotExists,
69 6255b97d Sofia Papagiannaki
    VersionNotExists, ContainerExists)
70 7efc9f86 Sofia Papagiannaki
71 6e147ecc Antony Chazapis
from pithos.backends.filter import parse_filters
72 6e147ecc Antony Chazapis
73 a7dff008 Antony Chazapis
import logging
74 a7dff008 Antony Chazapis
import hashlib
75 a7dff008 Antony Chazapis
76 b956618e Antony Chazapis
77 b956618e Antony Chazapis
logger = logging.getLogger(__name__)
78 b956618e Antony Chazapis
79 b956618e Antony Chazapis
80 8fbfd37b Antony Chazapis
@csrf_exempt
81 b956618e Antony Chazapis
def top_demux(request):
82 b956618e Antony Chazapis
    if request.method == 'GET':
83 2715ade4 Sofia Papagiannaki
        try:
84 2715ade4 Sofia Papagiannaki
            request.GET['X-Auth-Token']
85 2715ade4 Sofia Papagiannaki
        except KeyError:
86 2715ade4 Sofia Papagiannaki
            try:
87 2715ade4 Sofia Papagiannaki
                request.META['HTTP_X_AUTH_TOKEN']
88 2715ade4 Sofia Papagiannaki
            except KeyError:
89 2715ade4 Sofia Papagiannaki
                return authenticate(request)
90 2715ade4 Sofia Papagiannaki
        return account_list(request)
91 b956618e Antony Chazapis
    else:
92 b956618e Antony Chazapis
        return method_not_allowed(request)
93 b956618e Antony Chazapis
94 2715ade4 Sofia Papagiannaki
95 8fbfd37b Antony Chazapis
@csrf_exempt
96 b956618e Antony Chazapis
def account_demux(request, v_account):
97 b956618e Antony Chazapis
    if request.method == 'HEAD':
98 b956618e Antony Chazapis
        return account_meta(request, v_account)
99 b956618e Antony Chazapis
    elif request.method == 'POST':
100 b956618e Antony Chazapis
        return account_update(request, v_account)
101 83dd59c5 Antony Chazapis
    elif request.method == 'GET':
102 83dd59c5 Antony Chazapis
        return container_list(request, v_account)
103 b956618e Antony Chazapis
    else:
104 b956618e Antony Chazapis
        return method_not_allowed(request)
105 b956618e Antony Chazapis
106 2715ade4 Sofia Papagiannaki
107 8fbfd37b Antony Chazapis
@csrf_exempt
108 b956618e Antony Chazapis
def container_demux(request, v_account, v_container):
109 b956618e Antony Chazapis
    if request.method == 'HEAD':
110 b956618e Antony Chazapis
        return container_meta(request, v_account, v_container)
111 b956618e Antony Chazapis
    elif request.method == 'PUT':
112 b956618e Antony Chazapis
        return container_create(request, v_account, v_container)
113 b956618e Antony Chazapis
    elif request.method == 'POST':
114 b956618e Antony Chazapis
        return container_update(request, v_account, v_container)
115 b956618e Antony Chazapis
    elif request.method == 'DELETE':
116 b956618e Antony Chazapis
        return container_delete(request, v_account, v_container)
117 83dd59c5 Antony Chazapis
    elif request.method == 'GET':
118 83dd59c5 Antony Chazapis
        return object_list(request, v_account, v_container)
119 b956618e Antony Chazapis
    else:
120 b956618e Antony Chazapis
        return method_not_allowed(request)
121 b956618e Antony Chazapis
122 2715ade4 Sofia Papagiannaki
123 8fbfd37b Antony Chazapis
@csrf_exempt
124 b956618e Antony Chazapis
def object_demux(request, v_account, v_container, v_object):
125 ce2a2ef0 Antony Chazapis
    # Helper to avoid placing the token in the URL when loading objects from a browser.
126 b956618e Antony Chazapis
    if request.method == 'HEAD':
127 b956618e Antony Chazapis
        return object_meta(request, v_account, v_container, v_object)
128 b956618e Antony Chazapis
    elif request.method == 'GET':
129 b956618e Antony Chazapis
        return object_read(request, v_account, v_container, v_object)
130 b956618e Antony Chazapis
    elif request.method == 'PUT':
131 b956618e Antony Chazapis
        return object_write(request, v_account, v_container, v_object)
132 b956618e Antony Chazapis
    elif request.method == 'COPY':
133 b956618e Antony Chazapis
        return object_copy(request, v_account, v_container, v_object)
134 b956618e Antony Chazapis
    elif request.method == 'MOVE':
135 b956618e Antony Chazapis
        return object_move(request, v_account, v_container, v_object)
136 b956618e Antony Chazapis
    elif request.method == 'POST':
137 1d5c57d3 Antony Chazapis
        if request.META.get('CONTENT_TYPE', '').startswith('multipart/form-data'):
138 1d5c57d3 Antony Chazapis
            return object_write_form(request, v_account, v_container, v_object)
139 b956618e Antony Chazapis
        return object_update(request, v_account, v_container, v_object)
140 b956618e Antony Chazapis
    elif request.method == 'DELETE':
141 b956618e Antony Chazapis
        return object_delete(request, v_account, v_container, v_object)
142 b956618e Antony Chazapis
    else:
143 b956618e Antony Chazapis
        return method_not_allowed(request)
144 b956618e Antony Chazapis
145 2715ade4 Sofia Papagiannaki
146 a70c5269 Antony Chazapis
@api_method('GET', user_required=False)
147 b956618e Antony Chazapis
def authenticate(request):
148 b956618e Antony Chazapis
    # Normal Response Codes: 204
149 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
150 297513ba Antony Chazapis
    #                       forbidden (403),
151 b956618e Antony Chazapis
    #                       badRequest (400)
152 2715ade4 Sofia Papagiannaki
153 b956618e Antony Chazapis
    x_auth_user = request.META.get('HTTP_X_AUTH_USER')
154 b956618e Antony Chazapis
    x_auth_key = request.META.get('HTTP_X_AUTH_KEY')
155 b956618e Antony Chazapis
    if not x_auth_user or not x_auth_key:
156 b956618e Antony Chazapis
        raise BadRequest('Missing X-Auth-User or X-Auth-Key header')
157 b956618e Antony Chazapis
    response = HttpResponse(status=204)
158 2715ade4 Sofia Papagiannaki
159 f7667baf Antony Chazapis
    uri = request.build_absolute_uri()
160 f7667baf Antony Chazapis
    if '?' in uri:
161 f7667baf Antony Chazapis
        uri = uri[:uri.find('?')]
162 2715ade4 Sofia Papagiannaki
163 36d368f7 Antony Chazapis
    response['X-Auth-Token'] = x_auth_key
164 2715ade4 Sofia Papagiannaki
    response['X-Storage-Url'] = uri + ('' if uri.endswith('/')
165 2715ade4 Sofia Papagiannaki
                                       else '/') + x_auth_user
166 b956618e Antony Chazapis
    return response
167 b956618e Antony Chazapis
168 2715ade4 Sofia Papagiannaki
169 c846fad1 Sofia Papagiannaki
@api_method('GET', format_allowed=True, request_usage=True)
170 f6c97079 Antony Chazapis
def account_list(request):
171 f6c97079 Antony Chazapis
    # Normal Response Codes: 200, 204
172 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
173 f6c97079 Antony Chazapis
    #                       badRequest (400)
174 f6c97079 Antony Chazapis
    response = HttpResponse()
175 2715ade4 Sofia Papagiannaki
176 f6c97079 Antony Chazapis
    marker = request.GET.get('marker')
177 f6c97079 Antony Chazapis
    limit = get_int_parameter(request.GET.get('limit'))
178 f6c97079 Antony Chazapis
    if not limit:
179 f6c97079 Antony Chazapis
        limit = 10000
180 2715ade4 Sofia Papagiannaki
181 61efb530 Antony Chazapis
    accounts = request.backend.list_accounts(request.user_uniq, marker, limit)
182 2715ade4 Sofia Papagiannaki
183 f6c97079 Antony Chazapis
    if request.serialization == 'text':
184 f6c97079 Antony Chazapis
        if len(accounts) == 0:
185 f6c97079 Antony Chazapis
            # The cloudfiles python bindings expect 200 if json/xml.
186 f6c97079 Antony Chazapis
            response.status_code = 204
187 f6c97079 Antony Chazapis
            return response
188 f6c97079 Antony Chazapis
        response.status_code = 200
189 f6c97079 Antony Chazapis
        response.content = '\n'.join(accounts) + '\n'
190 f6c97079 Antony Chazapis
        return response
191 2715ade4 Sofia Papagiannaki
192 f6c97079 Antony Chazapis
    account_meta = []
193 f6c97079 Antony Chazapis
    for x in accounts:
194 690747fe Antony Chazapis
        if x == request.user_uniq:
195 690747fe Antony Chazapis
            continue
196 f6c97079 Antony Chazapis
        try:
197 2715ade4 Sofia Papagiannaki
            meta = request.backend.get_account_meta(
198 c846fad1 Sofia Papagiannaki
                request.user_uniq, x, 'pithos', include_user_defined=False,
199 c846fad1 Sofia Papagiannaki
                external_quota=request.user_usage)
200 61efb530 Antony Chazapis
            groups = request.backend.get_account_groups(request.user_uniq, x)
201 f6c97079 Antony Chazapis
        except NotAllowedError:
202 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
203 f6c97079 Antony Chazapis
        else:
204 804e8fe7 Antony Chazapis
            rename_meta_key(meta, 'modified', 'last_modified')
205 2715ade4 Sofia Papagiannaki
            rename_meta_key(
206 2715ade4 Sofia Papagiannaki
                meta, 'until_timestamp', 'x_account_until_timestamp')
207 690747fe Antony Chazapis
            if groups:
208 2715ade4 Sofia Papagiannaki
                meta['X-Account-Group'] = printable_header_dict(
209 2715ade4 Sofia Papagiannaki
                    dict([(k, ','.join(v)) for k, v in groups.iteritems()]))
210 f6c97079 Antony Chazapis
            account_meta.append(printable_header_dict(meta))
211 f6c97079 Antony Chazapis
    if request.serialization == 'xml':
212 f6c97079 Antony Chazapis
        data = render_to_string('accounts.xml', {'accounts': account_meta})
213 2715ade4 Sofia Papagiannaki
    elif request.serialization == 'json':
214 f6c97079 Antony Chazapis
        data = json.dumps(account_meta)
215 f6c97079 Antony Chazapis
    response.status_code = 200
216 f6c97079 Antony Chazapis
    response.content = data
217 f6c97079 Antony Chazapis
    return response
218 f6c97079 Antony Chazapis
219 2715ade4 Sofia Papagiannaki
220 c846fad1 Sofia Papagiannaki
@api_method('HEAD', request_usage=True)
221 b956618e Antony Chazapis
def account_meta(request, v_account):
222 b956618e Antony Chazapis
    # Normal Response Codes: 204
223 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
224 297513ba Antony Chazapis
    #                       forbidden (403),
225 b956618e Antony Chazapis
    #                       badRequest (400)
226 2715ade4 Sofia Papagiannaki
227 1495b972 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
228 cca6c617 Antony Chazapis
    try:
229 2715ade4 Sofia Papagiannaki
        meta = request.backend.get_account_meta(
230 c846fad1 Sofia Papagiannaki
            request.user_uniq, v_account, 'pithos', until,
231 c846fad1 Sofia Papagiannaki
            external_quota=request.user_usage)
232 2715ade4 Sofia Papagiannaki
        groups = request.backend.get_account_groups(
233 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account)
234 2715ade4 Sofia Papagiannaki
        policy = request.backend.get_account_policy(
235 c846fad1 Sofia Papagiannaki
            request.user_uniq, v_account, external_quota=request.user_usage)
236 cca6c617 Antony Chazapis
    except NotAllowedError:
237 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
238 2715ade4 Sofia Papagiannaki
239 a8326bef Antony Chazapis
    validate_modification_preconditions(request, meta)
240 2715ade4 Sofia Papagiannaki
241 b956618e Antony Chazapis
    response = HttpResponse(status=204)
242 647a5f48 Antony Chazapis
    put_account_headers(response, meta, groups, policy)
243 b956618e Antony Chazapis
    return response
244 b956618e Antony Chazapis
245 2715ade4 Sofia Papagiannaki
246 b956618e Antony Chazapis
@api_method('POST')
247 b956618e Antony Chazapis
def account_update(request, v_account):
248 b956618e Antony Chazapis
    # Normal Response Codes: 202
249 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
250 297513ba Antony Chazapis
    #                       forbidden (403),
251 b956618e Antony Chazapis
    #                       badRequest (400)
252 2715ade4 Sofia Papagiannaki
253 02c0c3fa Antony Chazapis
    meta, groups = get_account_headers(request)
254 27932481 Sofia Papagiannaki
#    for k in groups:
255 27932481 Sofia Papagiannaki
#        try:
256 27932481 Sofia Papagiannaki
#            groups[k] = [retrieve_uuid(request.token, x) for x in groups[k]]
257 27932481 Sofia Papagiannaki
#        except ItemNotExists, e:
258 27932481 Sofia Papagiannaki
#            raise BadRequest(
259 27932481 Sofia Papagiannaki
#                'Bad X-Account-Group header value: unknown account: %s' % e)
260 a6eb13e9 Antony Chazapis
    replace = True
261 a6eb13e9 Antony Chazapis
    if 'update' in request.GET:
262 b18ef3ad Antony Chazapis
        replace = False
263 02c0c3fa Antony Chazapis
    if groups:
264 02c0c3fa Antony Chazapis
        try:
265 61efb530 Antony Chazapis
            request.backend.update_account_groups(request.user_uniq, v_account,
266 2715ade4 Sofia Papagiannaki
                                                  groups, replace)
267 02c0c3fa Antony Chazapis
        except NotAllowedError:
268 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
269 02c0c3fa Antony Chazapis
        except ValueError:
270 02c0c3fa Antony Chazapis
            raise BadRequest('Invalid groups header')
271 77edd23d Antony Chazapis
    if meta or replace:
272 77edd23d Antony Chazapis
        try:
273 808cea65 Antony Chazapis
            request.backend.update_account_meta(request.user_uniq, v_account,
274 808cea65 Antony Chazapis
                                                'pithos', meta, replace)
275 77edd23d Antony Chazapis
        except NotAllowedError:
276 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
277 b956618e Antony Chazapis
    return HttpResponse(status=202)
278 b956618e Antony Chazapis
279 2715ade4 Sofia Papagiannaki
280 c846fad1 Sofia Papagiannaki
@api_method('GET', format_allowed=True, request_usage=True)
281 b956618e Antony Chazapis
def container_list(request, v_account):
282 b956618e Antony Chazapis
    # Normal Response Codes: 200, 204
283 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
284 b956618e Antony Chazapis
    #                       itemNotFound (404),
285 297513ba Antony Chazapis
    #                       forbidden (403),
286 b956618e Antony Chazapis
    #                       badRequest (400)
287 2715ade4 Sofia Papagiannaki
288 1495b972 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
289 cca6c617 Antony Chazapis
    try:
290 2715ade4 Sofia Papagiannaki
        meta = request.backend.get_account_meta(
291 c846fad1 Sofia Papagiannaki
            request.user_uniq, v_account, 'pithos', until,
292 c846fad1 Sofia Papagiannaki
            external_quota=request.user_usage)
293 2715ade4 Sofia Papagiannaki
        groups = request.backend.get_account_groups(
294 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account)
295 2715ade4 Sofia Papagiannaki
        policy = request.backend.get_account_policy(
296 c846fad1 Sofia Papagiannaki
            request.user_uniq, v_account, external_quota = request.user_usage)
297 cca6c617 Antony Chazapis
    except NotAllowedError:
298 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
299 2715ade4 Sofia Papagiannaki
300 b956618e Antony Chazapis
    validate_modification_preconditions(request, meta)
301 2715ade4 Sofia Papagiannaki
302 b956618e Antony Chazapis
    response = HttpResponse()
303 647a5f48 Antony Chazapis
    put_account_headers(response, meta, groups, policy)
304 2715ade4 Sofia Papagiannaki
305 b956618e Antony Chazapis
    marker = request.GET.get('marker')
306 f6c97079 Antony Chazapis
    limit = get_int_parameter(request.GET.get('limit'))
307 f6c97079 Antony Chazapis
    if not limit:
308 f6c97079 Antony Chazapis
        limit = 10000
309 2715ade4 Sofia Papagiannaki
310 b18ef3ad Antony Chazapis
    shared = False
311 b18ef3ad Antony Chazapis
    if 'shared' in request.GET:
312 b18ef3ad Antony Chazapis
        shared = True
313 90ee1eb3 Sofia Papagiannaki
    public = False
314 90ee1eb3 Sofia Papagiannaki
    if 'public' in request.GET:
315 90ee1eb3 Sofia Papagiannaki
        public = True
316 2715ade4 Sofia Papagiannaki
317 b956618e Antony Chazapis
    try:
318 2715ade4 Sofia Papagiannaki
        containers = request.backend.list_containers(
319 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account,
320 2715ade4 Sofia Papagiannaki
            marker, limit, shared, until, public)
321 cca6c617 Antony Chazapis
    except NotAllowedError:
322 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
323 b956618e Antony Chazapis
    except NameError:
324 b956618e Antony Chazapis
        containers = []
325 2715ade4 Sofia Papagiannaki
326 b956618e Antony Chazapis
    if request.serialization == 'text':
327 b956618e Antony Chazapis
        if len(containers) == 0:
328 b956618e Antony Chazapis
            # The cloudfiles python bindings expect 200 if json/xml.
329 b956618e Antony Chazapis
            response.status_code = 204
330 b956618e Antony Chazapis
            return response
331 b956618e Antony Chazapis
        response.status_code = 200
332 f6c97079 Antony Chazapis
        response.content = '\n'.join(containers) + '\n'
333 b956618e Antony Chazapis
        return response
334 2715ade4 Sofia Papagiannaki
335 b956618e Antony Chazapis
    container_meta = []
336 b956618e Antony Chazapis
    for x in containers:
337 f6c97079 Antony Chazapis
        try:
338 2715ade4 Sofia Papagiannaki
            meta = request.backend.get_container_meta(
339 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
340 2715ade4 Sofia Papagiannaki
                x, 'pithos', until, include_user_defined=False)
341 61efb530 Antony Chazapis
            policy = request.backend.get_container_policy(request.user_uniq,
342 2715ade4 Sofia Papagiannaki
                                                          v_account, x)
343 f6c97079 Antony Chazapis
        except NotAllowedError:
344 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
345 f6c97079 Antony Chazapis
        except NameError:
346 f6c97079 Antony Chazapis
            pass
347 f6c97079 Antony Chazapis
        else:
348 804e8fe7 Antony Chazapis
            rename_meta_key(meta, 'modified', 'last_modified')
349 2715ade4 Sofia Papagiannaki
            rename_meta_key(
350 2715ade4 Sofia Papagiannaki
                meta, 'until_timestamp', 'x_container_until_timestamp')
351 690747fe Antony Chazapis
            if policy:
352 2715ade4 Sofia Papagiannaki
                meta['X-Container-Policy'] = printable_header_dict(
353 2715ade4 Sofia Papagiannaki
                    dict([(k, v) for k, v in policy.iteritems()]))
354 f6c97079 Antony Chazapis
            container_meta.append(printable_header_dict(meta))
355 b956618e Antony Chazapis
    if request.serialization == 'xml':
356 2715ade4 Sofia Papagiannaki
        data = render_to_string('containers.xml', {'account':
357 2715ade4 Sofia Papagiannaki
                                v_account, 'containers': container_meta})
358 2715ade4 Sofia Papagiannaki
    elif request.serialization == 'json':
359 b956618e Antony Chazapis
        data = json.dumps(container_meta)
360 b956618e Antony Chazapis
    response.status_code = 200
361 b956618e Antony Chazapis
    response.content = data
362 b956618e Antony Chazapis
    return response
363 b956618e Antony Chazapis
364 2715ade4 Sofia Papagiannaki
365 b956618e Antony Chazapis
@api_method('HEAD')
366 b956618e Antony Chazapis
def container_meta(request, v_account, v_container):
367 b956618e Antony Chazapis
    # Normal Response Codes: 204
368 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
369 b956618e Antony Chazapis
    #                       itemNotFound (404),
370 297513ba Antony Chazapis
    #                       forbidden (403),
371 b956618e Antony Chazapis
    #                       badRequest (400)
372 2715ade4 Sofia Papagiannaki
373 1495b972 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
374 b956618e Antony Chazapis
    try:
375 61efb530 Antony Chazapis
        meta = request.backend.get_container_meta(request.user_uniq, v_account,
376 2715ade4 Sofia Papagiannaki
                                                  v_container, 'pithos', until)
377 371d907a Antony Chazapis
        meta['object_meta'] = request.backend.list_container_meta(request.user_uniq,
378 2715ade4 Sofia Papagiannaki
                                                                  v_account, v_container, 'pithos', until)
379 2715ade4 Sofia Papagiannaki
        policy = request.backend.get_container_policy(
380 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account,
381 2715ade4 Sofia Papagiannaki
            v_container)
382 cca6c617 Antony Chazapis
    except NotAllowedError:
383 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
384 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
385 b956618e Antony Chazapis
        raise ItemNotFound('Container does not exist')
386 2715ade4 Sofia Papagiannaki
387 a8326bef Antony Chazapis
    validate_modification_preconditions(request, meta)
388 2715ade4 Sofia Papagiannaki
389 b956618e Antony Chazapis
    response = HttpResponse(status=204)
390 39593b2b Giorgos Verigakis
    put_container_headers(request, response, meta, policy)
391 b956618e Antony Chazapis
    return response
392 b956618e Antony Chazapis
393 2715ade4 Sofia Papagiannaki
394 b956618e Antony Chazapis
@api_method('PUT')
395 b956618e Antony Chazapis
def container_create(request, v_account, v_container):
396 b956618e Antony Chazapis
    # Normal Response Codes: 201, 202
397 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
398 b956618e Antony Chazapis
    #                       itemNotFound (404),
399 297513ba Antony Chazapis
    #                       forbidden (403),
400 b956618e Antony Chazapis
    #                       badRequest (400)
401 2715ade4 Sofia Papagiannaki
402 3ab38c43 Antony Chazapis
    meta, policy = get_container_headers(request)
403 2715ade4 Sofia Papagiannaki
404 b956618e Antony Chazapis
    try:
405 2715ade4 Sofia Papagiannaki
        request.backend.put_container(
406 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account, v_container, policy)
407 b956618e Antony Chazapis
        ret = 201
408 cca6c617 Antony Chazapis
    except NotAllowedError:
409 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
410 a8326bef Antony Chazapis
    except ValueError:
411 a8326bef Antony Chazapis
        raise BadRequest('Invalid policy header')
412 7c09b0b7 Sofia Papagiannaki
    except ContainerExists:
413 b956618e Antony Chazapis
        ret = 202
414 2715ade4 Sofia Papagiannaki
415 c5d308c6 Antony Chazapis
    if ret == 202 and policy:
416 cca6c617 Antony Chazapis
        try:
417 2715ade4 Sofia Papagiannaki
            request.backend.update_container_policy(
418 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
419 2715ade4 Sofia Papagiannaki
                v_container, policy, replace=False)
420 c5d308c6 Antony Chazapis
        except NotAllowedError:
421 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
422 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
423 c5d308c6 Antony Chazapis
            raise ItemNotFound('Container does not exist')
424 c5d308c6 Antony Chazapis
        except ValueError:
425 c5d308c6 Antony Chazapis
            raise BadRequest('Invalid policy header')
426 c5d308c6 Antony Chazapis
    if meta:
427 c5d308c6 Antony Chazapis
        try:
428 61efb530 Antony Chazapis
            request.backend.update_container_meta(request.user_uniq, v_account,
429 2715ade4 Sofia Papagiannaki
                                                  v_container, 'pithos', meta, replace=False)
430 cca6c617 Antony Chazapis
        except NotAllowedError:
431 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
432 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
433 cca6c617 Antony Chazapis
            raise ItemNotFound('Container does not exist')
434 2715ade4 Sofia Papagiannaki
435 b956618e Antony Chazapis
    return HttpResponse(status=ret)
436 b956618e Antony Chazapis
437 2715ade4 Sofia Papagiannaki
438 af7bb62f Antony Chazapis
@api_method('POST', format_allowed=True)
439 b956618e Antony Chazapis
def container_update(request, v_account, v_container):
440 b956618e Antony Chazapis
    # Normal Response Codes: 202
441 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
442 b956618e Antony Chazapis
    #                       itemNotFound (404),
443 297513ba Antony Chazapis
    #                       forbidden (403),
444 b956618e Antony Chazapis
    #                       badRequest (400)
445 2715ade4 Sofia Papagiannaki
446 3ab38c43 Antony Chazapis
    meta, policy = get_container_headers(request)
447 a6eb13e9 Antony Chazapis
    replace = True
448 a6eb13e9 Antony Chazapis
    if 'update' in request.GET:
449 a6eb13e9 Antony Chazapis
        replace = False
450 3ab38c43 Antony Chazapis
    if policy:
451 3ab38c43 Antony Chazapis
        try:
452 2715ade4 Sofia Papagiannaki
            request.backend.update_container_policy(
453 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
454 2715ade4 Sofia Papagiannaki
                v_container, policy, replace)
455 3ab38c43 Antony Chazapis
        except NotAllowedError:
456 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
457 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
458 3ab38c43 Antony Chazapis
            raise ItemNotFound('Container does not exist')
459 3ab38c43 Antony Chazapis
        except ValueError:
460 3ab38c43 Antony Chazapis
            raise BadRequest('Invalid policy header')
461 77edd23d Antony Chazapis
    if meta or replace:
462 77edd23d Antony Chazapis
        try:
463 61efb530 Antony Chazapis
            request.backend.update_container_meta(request.user_uniq, v_account,
464 2715ade4 Sofia Papagiannaki
                                                  v_container, 'pithos', meta, replace)
465 77edd23d Antony Chazapis
        except NotAllowedError:
466 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
467 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
468 77edd23d Antony Chazapis
            raise ItemNotFound('Container does not exist')
469 2715ade4 Sofia Papagiannaki
470 5144b772 Antony Chazapis
    content_length = -1
471 5144b772 Antony Chazapis
    if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
472 2715ade4 Sofia Papagiannaki
        content_length = get_int_parameter(
473 2715ade4 Sofia Papagiannaki
            request.META.get('CONTENT_LENGTH', 0))
474 bd08f5c0 Antony Chazapis
    content_type = request.META.get('CONTENT_TYPE')
475 5144b772 Antony Chazapis
    hashmap = []
476 5144b772 Antony Chazapis
    if content_type and content_type == 'application/octet-stream' and content_length != 0:
477 5144b772 Antony Chazapis
        for data in socket_read_iterator(request, content_length,
478 2715ade4 Sofia Papagiannaki
                                         request.backend.block_size):
479 5144b772 Antony Chazapis
            # TODO: Raise 408 (Request Timeout) if this takes too long.
480 5144b772 Antony Chazapis
            # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
481 5144b772 Antony Chazapis
            hashmap.append(request.backend.put_block(data))
482 2715ade4 Sofia Papagiannaki
483 5144b772 Antony Chazapis
    response = HttpResponse(status=202)
484 5144b772 Antony Chazapis
    if hashmap:
485 af7bb62f Antony Chazapis
        response.content = simple_list_response(request, hashmap)
486 5144b772 Antony Chazapis
    return response
487 b956618e Antony Chazapis
488 2715ade4 Sofia Papagiannaki
489 b956618e Antony Chazapis
@api_method('DELETE')
490 b956618e Antony Chazapis
def container_delete(request, v_account, v_container):
491 b956618e Antony Chazapis
    # Normal Response Codes: 204
492 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
493 b956618e Antony Chazapis
    #                       conflict (409),
494 b956618e Antony Chazapis
    #                       itemNotFound (404),
495 297513ba Antony Chazapis
    #                       forbidden (403),
496 b956618e Antony Chazapis
    #                       badRequest (400)
497 2715ade4 Sofia Papagiannaki
498 bbd20b55 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
499 2715ade4 Sofia Papagiannaki
500 e46b2bcf Sofia Papagiannaki
    delimiter = request.GET.get('delimiter')
501 2715ade4 Sofia Papagiannaki
502 b956618e Antony Chazapis
    try:
503 2715ade4 Sofia Papagiannaki
        request.backend.delete_container(
504 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account, v_container,
505 2715ade4 Sofia Papagiannaki
            until, delimiter=delimiter)
506 cca6c617 Antony Chazapis
    except NotAllowedError:
507 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
508 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
509 b956618e Antony Chazapis
        raise ItemNotFound('Container does not exist')
510 7efc9f86 Sofia Papagiannaki
    except ContainerNotEmpty:
511 b956618e Antony Chazapis
        raise Conflict('Container is not empty')
512 b956618e Antony Chazapis
    return HttpResponse(status=204)
513 b956618e Antony Chazapis
514 2715ade4 Sofia Papagiannaki
515 b956618e Antony Chazapis
@api_method('GET', format_allowed=True)
516 b956618e Antony Chazapis
def object_list(request, v_account, v_container):
517 b956618e Antony Chazapis
    # Normal Response Codes: 200, 204
518 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
519 b956618e Antony Chazapis
    #                       itemNotFound (404),
520 297513ba Antony Chazapis
    #                       forbidden (403),
521 b956618e Antony Chazapis
    #                       badRequest (400)
522 2715ade4 Sofia Papagiannaki
523 1495b972 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
524 b956618e Antony Chazapis
    try:
525 61efb530 Antony Chazapis
        meta = request.backend.get_container_meta(request.user_uniq, v_account,
526 2715ade4 Sofia Papagiannaki
                                                  v_container, 'pithos', until)
527 371d907a Antony Chazapis
        meta['object_meta'] = request.backend.list_container_meta(request.user_uniq,
528 2715ade4 Sofia Papagiannaki
                                                                  v_account, v_container, 'pithos', until)
529 2715ade4 Sofia Papagiannaki
        policy = request.backend.get_container_policy(
530 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account,
531 2715ade4 Sofia Papagiannaki
            v_container)
532 cca6c617 Antony Chazapis
    except NotAllowedError:
533 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
534 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
535 b956618e Antony Chazapis
        raise ItemNotFound('Container does not exist')
536 2715ade4 Sofia Papagiannaki
537 b956618e Antony Chazapis
    validate_modification_preconditions(request, meta)
538 2715ade4 Sofia Papagiannaki
539 b956618e Antony Chazapis
    response = HttpResponse()
540 39593b2b Giorgos Verigakis
    put_container_headers(request, response, meta, policy)
541 2715ade4 Sofia Papagiannaki
542 b956618e Antony Chazapis
    path = request.GET.get('path')
543 b956618e Antony Chazapis
    prefix = request.GET.get('prefix')
544 b956618e Antony Chazapis
    delimiter = request.GET.get('delimiter')
545 2715ade4 Sofia Papagiannaki
546 b956618e Antony Chazapis
    # Path overrides prefix and delimiter.
547 b956618e Antony Chazapis
    virtual = True
548 b956618e Antony Chazapis
    if path:
549 b956618e Antony Chazapis
        prefix = path
550 b956618e Antony Chazapis
        delimiter = '/'
551 b956618e Antony Chazapis
        virtual = False
552 2715ade4 Sofia Papagiannaki
553 b956618e Antony Chazapis
    # Naming policy.
554 dcffd53e Antony Chazapis
    if prefix and delimiter and not prefix.endswith(delimiter):
555 b956618e Antony Chazapis
        prefix = prefix + delimiter
556 b956618e Antony Chazapis
    if not prefix:
557 b956618e Antony Chazapis
        prefix = ''
558 b956618e Antony Chazapis
    prefix = prefix.lstrip('/')
559 2715ade4 Sofia Papagiannaki
560 b956618e Antony Chazapis
    marker = request.GET.get('marker')
561 f6c97079 Antony Chazapis
    limit = get_int_parameter(request.GET.get('limit'))
562 f6c97079 Antony Chazapis
    if not limit:
563 f6c97079 Antony Chazapis
        limit = 10000
564 2715ade4 Sofia Papagiannaki
565 22dab079 Antony Chazapis
    keys = request.GET.get('meta')
566 22dab079 Antony Chazapis
    if keys:
567 2715ade4 Sofia Papagiannaki
        keys = [smart_str(x.strip()) for x in keys.split(',')
568 2715ade4 Sofia Papagiannaki
                if x.strip() != '']
569 1713c946 Antony Chazapis
        included, excluded, opers = parse_filters(keys)
570 1713c946 Antony Chazapis
        keys = []
571 1713c946 Antony Chazapis
        keys += [format_header_key('X-Object-Meta-' + x) for x in included]
572 2715ade4 Sofia Papagiannaki
        keys += ['!' + format_header_key('X-Object-Meta-' + x)
573 2715ade4 Sofia Papagiannaki
                 for x in excluded]
574 2715ade4 Sofia Papagiannaki
        keys += ['%s%s%s' % (format_header_key(
575 2715ade4 Sofia Papagiannaki
            'X-Object-Meta-' + k), o, v) for k, o, v in opers]
576 22dab079 Antony Chazapis
    else:
577 22dab079 Antony Chazapis
        keys = []
578 2715ade4 Sofia Papagiannaki
579 b18ef3ad Antony Chazapis
    shared = False
580 b18ef3ad Antony Chazapis
    if 'shared' in request.GET:
581 b18ef3ad Antony Chazapis
        shared = True
582 90ee1eb3 Sofia Papagiannaki
    public = False
583 90ee1eb3 Sofia Papagiannaki
    if 'public' in request.GET:
584 90ee1eb3 Sofia Papagiannaki
        public = True
585 2715ade4 Sofia Papagiannaki
586 b956618e Antony Chazapis
    if request.serialization == 'text':
587 371d907a Antony Chazapis
        try:
588 2715ade4 Sofia Papagiannaki
            objects = request.backend.list_objects(
589 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
590 2715ade4 Sofia Papagiannaki
                v_container, prefix, delimiter, marker,
591 2715ade4 Sofia Papagiannaki
                limit, virtual, 'pithos', keys, shared,
592 2715ade4 Sofia Papagiannaki
                until, None, public)
593 371d907a Antony Chazapis
        except NotAllowedError:
594 371d907a Antony Chazapis
            raise Forbidden('Not allowed')
595 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
596 371d907a Antony Chazapis
            raise ItemNotFound('Container does not exist')
597 2715ade4 Sofia Papagiannaki
598 b956618e Antony Chazapis
        if len(objects) == 0:
599 b956618e Antony Chazapis
            # The cloudfiles python bindings expect 200 if json/xml.
600 b956618e Antony Chazapis
            response.status_code = 204
601 b956618e Antony Chazapis
            return response
602 b956618e Antony Chazapis
        response.status_code = 200
603 83dd59c5 Antony Chazapis
        response.content = '\n'.join([x[0] for x in objects]) + '\n'
604 b956618e Antony Chazapis
        return response
605 dcffd53e Antony Chazapis
606 371d907a Antony Chazapis
    try:
607 2715ade4 Sofia Papagiannaki
        objects = request.backend.list_object_meta(
608 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account,
609 2715ade4 Sofia Papagiannaki
            v_container, prefix, delimiter, marker,
610 2715ade4 Sofia Papagiannaki
            limit, virtual, 'pithos', keys, shared, until, None, public)
611 15a96c3e Antony Chazapis
        object_permissions = {}
612 15a96c3e Antony Chazapis
        object_public = {}
613 15a96c3e Antony Chazapis
        if until is None:
614 ddea3095 Sofia Papagiannaki
            name = '/'.join((v_account, v_container, ''))
615 ddea3095 Sofia Papagiannaki
            name_idx = len(name)
616 15a96c3e Antony Chazapis
            for x in request.backend.list_object_permissions(request.user_uniq,
617 2715ade4 Sofia Papagiannaki
                                                             v_account, v_container, prefix):
618 ddea3095 Sofia Papagiannaki
619 ddea3095 Sofia Papagiannaki
                # filter out objects which are not under the container
620 ddea3095 Sofia Papagiannaki
                if name != x[:name_idx]:
621 ddea3095 Sofia Papagiannaki
                    continue
622 ddea3095 Sofia Papagiannaki
623 15a96c3e Antony Chazapis
                object = x[name_idx:]
624 15a96c3e Antony Chazapis
                object_permissions[object] = request.backend.get_object_permissions(
625 2715ade4 Sofia Papagiannaki
                    request.user_uniq, v_account, v_container, object)
626 15a96c3e Antony Chazapis
            for k, v in request.backend.list_object_public(request.user_uniq,
627 2715ade4 Sofia Papagiannaki
                                                           v_account, v_container, prefix).iteritems():
628 15a96c3e Antony Chazapis
                object_public[k[name_idx:]] = v
629 371d907a Antony Chazapis
    except NotAllowedError:
630 371d907a Antony Chazapis
        raise Forbidden('Not allowed')
631 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
632 371d907a Antony Chazapis
        raise ItemNotFound('Container does not exist')
633 2715ade4 Sofia Papagiannaki
634 b956618e Antony Chazapis
    object_meta = []
635 371d907a Antony Chazapis
    for meta in objects:
636 371d907a Antony Chazapis
        if len(meta) == 1:
637 b956618e Antony Chazapis
            # Virtual objects/directories.
638 371d907a Antony Chazapis
            object_meta.append(meta)
639 83dd59c5 Antony Chazapis
        else:
640 2715ade4 Sofia Papagiannaki
            rename_meta_key(
641 2715ade4 Sofia Papagiannaki
                meta, 'hash', 'x_object_hash')  # Will be replaced by checksum.
642 371d907a Antony Chazapis
            rename_meta_key(meta, 'checksum', 'hash')
643 371d907a Antony Chazapis
            rename_meta_key(meta, 'type', 'content_type')
644 371d907a Antony Chazapis
            rename_meta_key(meta, 'uuid', 'x_object_uuid')
645 371d907a Antony Chazapis
            if until is not None and 'modified' in meta:
646 371d907a Antony Chazapis
                del(meta['modified'])
647 038f1ae9 Antony Chazapis
            else:
648 804e8fe7 Antony Chazapis
                rename_meta_key(meta, 'modified', 'last_modified')
649 371d907a Antony Chazapis
            rename_meta_key(meta, 'modified_by', 'x_object_modified_by')
650 371d907a Antony Chazapis
            rename_meta_key(meta, 'version', 'x_object_version')
651 2715ade4 Sofia Papagiannaki
            rename_meta_key(
652 2715ade4 Sofia Papagiannaki
                meta, 'version_timestamp', 'x_object_version_timestamp')
653 15a96c3e Antony Chazapis
            permissions = object_permissions.get(meta['name'], None)
654 15a96c3e Antony Chazapis
            if permissions:
655 2715ade4 Sofia Papagiannaki
                update_sharing_meta(request, permissions, v_account,
656 2715ade4 Sofia Papagiannaki
                                    v_container, meta['name'], meta)
657 15a96c3e Antony Chazapis
            public = object_public.get(meta['name'], None)
658 15a96c3e Antony Chazapis
            if public:
659 15a96c3e Antony Chazapis
                update_public_meta(public, meta)
660 371d907a Antony Chazapis
            object_meta.append(printable_header_dict(meta))
661 b956618e Antony Chazapis
    if request.serialization == 'xml':
662 2715ade4 Sofia Papagiannaki
        data = render_to_string(
663 2715ade4 Sofia Papagiannaki
            'objects.xml', {'container': v_container, 'objects': object_meta})
664 2715ade4 Sofia Papagiannaki
    elif request.serialization == 'json':
665 c48acbfd Sofia Papagiannaki
        data = json.dumps(object_meta, default=json_encode_decimal)
666 b956618e Antony Chazapis
    response.status_code = 200
667 b956618e Antony Chazapis
    response.content = data
668 b956618e Antony Chazapis
    return response
669 b956618e Antony Chazapis
670 2715ade4 Sofia Papagiannaki
671 b956618e Antony Chazapis
@api_method('HEAD')
672 b956618e Antony Chazapis
def object_meta(request, v_account, v_container, v_object):
673 b956618e Antony Chazapis
    # Normal Response Codes: 204
674 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
675 b956618e Antony Chazapis
    #                       itemNotFound (404),
676 297513ba Antony Chazapis
    #                       forbidden (403),
677 b956618e Antony Chazapis
    #                       badRequest (400)
678 2715ade4 Sofia Papagiannaki
679 104626e3 Antony Chazapis
    version = request.GET.get('version')
680 b956618e Antony Chazapis
    try:
681 61efb530 Antony Chazapis
        meta = request.backend.get_object_meta(request.user_uniq, v_account,
682 2715ade4 Sofia Papagiannaki
                                               v_container, v_object, 'pithos', version)
683 e8886082 Antony Chazapis
        if version is None:
684 2715ade4 Sofia Papagiannaki
            permissions = request.backend.get_object_permissions(
685 2715ade4 Sofia Papagiannaki
                request.user_uniq,
686 2715ade4 Sofia Papagiannaki
                v_account, v_container, v_object)
687 2715ade4 Sofia Papagiannaki
            public = request.backend.get_object_public(
688 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
689 2715ade4 Sofia Papagiannaki
                v_container, v_object)
690 e8886082 Antony Chazapis
        else:
691 e8886082 Antony Chazapis
            permissions = None
692 e0f916bb Antony Chazapis
            public = None
693 cca6c617 Antony Chazapis
    except NotAllowedError:
694 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
695 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
696 b956618e Antony Chazapis
        raise ItemNotFound('Object does not exist')
697 7efc9f86 Sofia Papagiannaki
    except VersionNotExists:
698 58a6c894 Antony Chazapis
        raise ItemNotFound('Version does not exist')
699 2715ade4 Sofia Papagiannaki
700 8cb45c13 Antony Chazapis
    update_manifest_meta(request, v_account, meta)
701 2715ade4 Sofia Papagiannaki
    update_sharing_meta(
702 2715ade4 Sofia Papagiannaki
        request, permissions, v_account, v_container, v_object, meta)
703 e0f916bb Antony Chazapis
    update_public_meta(public, meta)
704 2715ade4 Sofia Papagiannaki
705 a8326bef Antony Chazapis
    # Evaluate conditions.
706 a8326bef Antony Chazapis
    validate_modification_preconditions(request, meta)
707 a8326bef Antony Chazapis
    try:
708 a8326bef Antony Chazapis
        validate_matching_preconditions(request, meta)
709 a8326bef Antony Chazapis
    except NotModified:
710 a8326bef Antony Chazapis
        response = HttpResponse(status=304)
711 33b4e4a6 Antony Chazapis
        response['ETag'] = meta['checksum']
712 a8326bef Antony Chazapis
        return response
713 2715ade4 Sofia Papagiannaki
714 cb146cf9 Antony Chazapis
    response = HttpResponse(status=200)
715 02c0c3fa Antony Chazapis
    put_object_headers(response, meta)
716 b956618e Antony Chazapis
    return response
717 b956618e Antony Chazapis
718 2715ade4 Sofia Papagiannaki
719 22dab079 Antony Chazapis
@api_method('GET', format_allowed=True)
720 b956618e Antony Chazapis
def object_read(request, v_account, v_container, v_object):
721 b956618e Antony Chazapis
    # Normal Response Codes: 200, 206
722 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
723 b956618e Antony Chazapis
    #                       rangeNotSatisfiable (416),
724 b956618e Antony Chazapis
    #                       preconditionFailed (412),
725 b956618e Antony Chazapis
    #                       itemNotFound (404),
726 297513ba Antony Chazapis
    #                       forbidden (403),
727 b956618e Antony Chazapis
    #                       badRequest (400),
728 b956618e Antony Chazapis
    #                       notModified (304)
729 2715ade4 Sofia Papagiannaki
730 104626e3 Antony Chazapis
    version = request.GET.get('version')
731 2715ade4 Sofia Papagiannaki
732 e8886082 Antony Chazapis
    # Reply with the version list. Do this first, as the object may be deleted.
733 104626e3 Antony Chazapis
    if version == 'list':
734 e8886082 Antony Chazapis
        if request.serialization == 'text':
735 e8886082 Antony Chazapis
            raise BadRequest('No format specified for version list.')
736 2715ade4 Sofia Papagiannaki
737 cca6c617 Antony Chazapis
        try:
738 61efb530 Antony Chazapis
            v = request.backend.list_versions(request.user_uniq, v_account,
739 2715ade4 Sofia Papagiannaki
                                              v_container, v_object)
740 cca6c617 Antony Chazapis
        except NotAllowedError:
741 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
742 02b8c298 Sofia Papagiannaki
        except ItemNotExists:
743 02b8c298 Sofia Papagiannaki
            raise ItemNotFound('Object does not exist')
744 cca6c617 Antony Chazapis
        d = {'versions': v}
745 e8886082 Antony Chazapis
        if request.serialization == 'xml':
746 e8886082 Antony Chazapis
            d['object'] = v_object
747 e8886082 Antony Chazapis
            data = render_to_string('versions.xml', d)
748 2715ade4 Sofia Papagiannaki
        elif request.serialization == 'json':
749 c48acbfd Sofia Papagiannaki
            data = json.dumps(d, default=json_encode_decimal)
750 2715ade4 Sofia Papagiannaki
751 e8886082 Antony Chazapis
        response = HttpResponse(data, status=200)
752 e8886082 Antony Chazapis
        response['Content-Length'] = len(data)
753 e8886082 Antony Chazapis
        return response
754 2715ade4 Sofia Papagiannaki
755 b956618e Antony Chazapis
    try:
756 61efb530 Antony Chazapis
        meta = request.backend.get_object_meta(request.user_uniq, v_account,
757 2715ade4 Sofia Papagiannaki
                                               v_container, v_object, 'pithos', version)
758 e8886082 Antony Chazapis
        if version is None:
759 2715ade4 Sofia Papagiannaki
            permissions = request.backend.get_object_permissions(
760 2715ade4 Sofia Papagiannaki
                request.user_uniq,
761 2715ade4 Sofia Papagiannaki
                v_account, v_container, v_object)
762 2715ade4 Sofia Papagiannaki
            public = request.backend.get_object_public(
763 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
764 2715ade4 Sofia Papagiannaki
                v_container, v_object)
765 e8886082 Antony Chazapis
        else:
766 e8886082 Antony Chazapis
            permissions = None
767 e0f916bb Antony Chazapis
            public = None
768 cca6c617 Antony Chazapis
    except NotAllowedError:
769 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
770 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
771 b956618e Antony Chazapis
        raise ItemNotFound('Object does not exist')
772 7efc9f86 Sofia Papagiannaki
    except VersionNotExists:
773 58a6c894 Antony Chazapis
        raise ItemNotFound('Version does not exist')
774 2715ade4 Sofia Papagiannaki
775 8cb45c13 Antony Chazapis
    update_manifest_meta(request, v_account, meta)
776 2715ade4 Sofia Papagiannaki
    update_sharing_meta(
777 2715ade4 Sofia Papagiannaki
        request, permissions, v_account, v_container, v_object, meta)
778 e0f916bb Antony Chazapis
    update_public_meta(public, meta)
779 2715ade4 Sofia Papagiannaki
780 22dab079 Antony Chazapis
    # Evaluate conditions.
781 b956618e Antony Chazapis
    validate_modification_preconditions(request, meta)
782 22dab079 Antony Chazapis
    try:
783 22dab079 Antony Chazapis
        validate_matching_preconditions(request, meta)
784 22dab079 Antony Chazapis
    except NotModified:
785 22dab079 Antony Chazapis
        response = HttpResponse(status=304)
786 33b4e4a6 Antony Chazapis
        response['ETag'] = meta['checksum']
787 22dab079 Antony Chazapis
        return response
788 2715ade4 Sofia Papagiannaki
789 2fd10ff4 Antony Chazapis
    hashmap_reply = False
790 2fd10ff4 Antony Chazapis
    if 'hashmap' in request.GET and request.serialization != 'text':
791 2fd10ff4 Antony Chazapis
        hashmap_reply = True
792 2715ade4 Sofia Papagiannaki
793 8cb45c13 Antony Chazapis
    sizes = []
794 8cb45c13 Antony Chazapis
    hashmaps = []
795 2fd10ff4 Antony Chazapis
    if 'X-Object-Manifest' in meta and not hashmap_reply:
796 8cb45c13 Antony Chazapis
        try:
797 2715ade4 Sofia Papagiannaki
            src_container, src_name = split_container_object_string(
798 2715ade4 Sofia Papagiannaki
                '/' + meta['X-Object-Manifest'])
799 2715ade4 Sofia Papagiannaki
            objects = request.backend.list_objects(
800 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
801 2715ade4 Sofia Papagiannaki
                src_container, prefix=src_name, virtual=False)
802 cca6c617 Antony Chazapis
        except NotAllowedError:
803 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
804 8cb45c13 Antony Chazapis
        except ValueError:
805 8cb45c13 Antony Chazapis
            raise BadRequest('Invalid X-Object-Manifest header')
806 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
807 8cb45c13 Antony Chazapis
            raise ItemNotFound('Container does not exist')
808 2715ade4 Sofia Papagiannaki
809 8cb45c13 Antony Chazapis
        try:
810 8cb45c13 Antony Chazapis
            for x in objects:
811 61efb530 Antony Chazapis
                s, h = request.backend.get_object_hashmap(request.user_uniq,
812 2715ade4 Sofia Papagiannaki
                                                          v_account, src_container, x[0], x[1])
813 8cb45c13 Antony Chazapis
                sizes.append(s)
814 8cb45c13 Antony Chazapis
                hashmaps.append(h)
815 cca6c617 Antony Chazapis
        except NotAllowedError:
816 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
817 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
818 8cb45c13 Antony Chazapis
            raise ItemNotFound('Object does not exist')
819 7efc9f86 Sofia Papagiannaki
        except VersionNotExists:
820 8cb45c13 Antony Chazapis
            raise ItemNotFound('Version does not exist')
821 8cb45c13 Antony Chazapis
    else:
822 8cb45c13 Antony Chazapis
        try:
823 2715ade4 Sofia Papagiannaki
            s, h = request.backend.get_object_hashmap(
824 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
825 2715ade4 Sofia Papagiannaki
                v_container, v_object, version)
826 8cb45c13 Antony Chazapis
            sizes.append(s)
827 8cb45c13 Antony Chazapis
            hashmaps.append(h)
828 cca6c617 Antony Chazapis
        except NotAllowedError:
829 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
830 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
831 8cb45c13 Antony Chazapis
            raise ItemNotFound('Object does not exist')
832 7efc9f86 Sofia Papagiannaki
        except VersionNotExists:
833 8cb45c13 Antony Chazapis
            raise ItemNotFound('Version does not exist')
834 2715ade4 Sofia Papagiannaki
835 22dab079 Antony Chazapis
    # Reply with the hashmap.
836 2fd10ff4 Antony Chazapis
    if hashmap_reply:
837 8cb45c13 Antony Chazapis
        size = sum(sizes)
838 8cb45c13 Antony Chazapis
        hashmap = sum(hashmaps, [])
839 39593b2b Giorgos Verigakis
        d = {
840 39593b2b Giorgos Verigakis
            'block_size': request.backend.block_size,
841 39593b2b Giorgos Verigakis
            'block_hash': request.backend.hash_algorithm,
842 39593b2b Giorgos Verigakis
            'bytes': size,
843 39593b2b Giorgos Verigakis
            'hashes': hashmap}
844 22dab079 Antony Chazapis
        if request.serialization == 'xml':
845 6bc372a4 Antony Chazapis
            d['object'] = v_object
846 6bc372a4 Antony Chazapis
            data = render_to_string('hashes.xml', d)
847 2715ade4 Sofia Papagiannaki
        elif request.serialization == 'json':
848 6bc372a4 Antony Chazapis
            data = json.dumps(d)
849 2715ade4 Sofia Papagiannaki
850 22dab079 Antony Chazapis
        response = HttpResponse(data, status=200)
851 02c0c3fa Antony Chazapis
        put_object_headers(response, meta)
852 22dab079 Antony Chazapis
        response['Content-Length'] = len(data)
853 22dab079 Antony Chazapis
        return response
854 2715ade4 Sofia Papagiannaki
855 2715ade4 Sofia Papagiannaki
    request.serialization = 'text'  # Unset.
856 8cb45c13 Antony Chazapis
    return object_data_response(request, sizes, hashmaps, meta)
857 b956618e Antony Chazapis
858 2715ade4 Sofia Papagiannaki
859 76985443 Sofia Papagiannaki
@api_method('PUT', format_allowed=True)
860 b956618e Antony Chazapis
def object_write(request, v_account, v_container, v_object):
861 b956618e Antony Chazapis
    # Normal Response Codes: 201
862 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
863 b956618e Antony Chazapis
    #                       unprocessableEntity (422),
864 b956618e Antony Chazapis
    #                       lengthRequired (411),
865 3436eeb0 Antony Chazapis
    #                       conflict (409),
866 b956618e Antony Chazapis
    #                       itemNotFound (404),
867 297513ba Antony Chazapis
    #                       forbidden (403),
868 b956618e Antony Chazapis
    #                       badRequest (400)
869 2715ade4 Sofia Papagiannaki
870 a8326bef Antony Chazapis
    # Evaluate conditions.
871 a8326bef Antony Chazapis
    if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
872 a8326bef Antony Chazapis
        try:
873 2715ade4 Sofia Papagiannaki
            meta = request.backend.get_object_meta(
874 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
875 2715ade4 Sofia Papagiannaki
                v_container, v_object, 'pithos')
876 a8326bef Antony Chazapis
        except NotAllowedError:
877 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
878 a8326bef Antony Chazapis
        except NameError:
879 a8326bef Antony Chazapis
            meta = {}
880 a8326bef Antony Chazapis
        validate_matching_preconditions(request, meta)
881 2715ade4 Sofia Papagiannaki
882 88283e9e Antony Chazapis
    copy_from = request.META.get('HTTP_X_COPY_FROM')
883 88283e9e Antony Chazapis
    move_from = request.META.get('HTTP_X_MOVE_FROM')
884 b956618e Antony Chazapis
    if copy_from or move_from:
885 4d15c94e Sofia Papagiannaki
        delimiter = request.GET.get('delimiter')
886 2715ade4 Sofia Papagiannaki
        content_length = get_content_length(request)  # Required by the API.
887 2715ade4 Sofia Papagiannaki
888 88283e9e Antony Chazapis
        src_account = request.META.get('HTTP_X_SOURCE_ACCOUNT')
889 79bb41b7 Antony Chazapis
        if not src_account:
890 61efb530 Antony Chazapis
            src_account = request.user_uniq
891 b956618e Antony Chazapis
        if move_from:
892 83dd59c5 Antony Chazapis
            try:
893 2715ade4 Sofia Papagiannaki
                src_container, src_name = split_container_object_string(
894 2715ade4 Sofia Papagiannaki
                    move_from)
895 83dd59c5 Antony Chazapis
            except ValueError:
896 83dd59c5 Antony Chazapis
                raise BadRequest('Invalid X-Move-From header')
897 2715ade4 Sofia Papagiannaki
            version_id = copy_or_move_object(
898 2715ade4 Sofia Papagiannaki
                request, src_account, src_container, src_name,
899 2715ade4 Sofia Papagiannaki
                v_account, v_container, v_object, move=True, delimiter=delimiter)
900 b956618e Antony Chazapis
        else:
901 83dd59c5 Antony Chazapis
            try:
902 2715ade4 Sofia Papagiannaki
                src_container, src_name = split_container_object_string(
903 2715ade4 Sofia Papagiannaki
                    copy_from)
904 83dd59c5 Antony Chazapis
            except ValueError:
905 83dd59c5 Antony Chazapis
                raise BadRequest('Invalid X-Copy-From header')
906 2715ade4 Sofia Papagiannaki
            version_id = copy_or_move_object(
907 2715ade4 Sofia Papagiannaki
                request, src_account, src_container, src_name,
908 2715ade4 Sofia Papagiannaki
                v_account, v_container, v_object, move=False, delimiter=delimiter)
909 7dd293a0 Antony Chazapis
        response = HttpResponse(status=201)
910 7dd293a0 Antony Chazapis
        response['X-Object-Version'] = version_id
911 7dd293a0 Antony Chazapis
        return response
912 2715ade4 Sofia Papagiannaki
913 66ce2ca5 Antony Chazapis
    content_type, meta, permissions, public = get_object_headers(request)
914 b956618e Antony Chazapis
    content_length = -1
915 b956618e Antony Chazapis
    if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
916 22dab079 Antony Chazapis
        content_length = get_content_length(request)
917 b956618e Antony Chazapis
    # Should be BadRequest, but API says otherwise.
918 dcffd53e Antony Chazapis
    if content_type is None:
919 b956618e Antony Chazapis
        raise LengthRequired('Missing Content-Type header')
920 2715ade4 Sofia Papagiannaki
921 f9f15f92 Antony Chazapis
    if 'hashmap' in request.GET:
922 f9f15f92 Antony Chazapis
        if request.serialization not in ('json', 'xml'):
923 f9f15f92 Antony Chazapis
            raise BadRequest('Invalid hashmap format')
924 2715ade4 Sofia Papagiannaki
925 76985443 Sofia Papagiannaki
        data = ''
926 39593b2b Giorgos Verigakis
        for block in socket_read_iterator(request, content_length,
927 2715ade4 Sofia Papagiannaki
                                          request.backend.block_size):
928 76985443 Sofia Papagiannaki
            data = '%s%s' % (data, block)
929 2715ade4 Sofia Papagiannaki
930 32a437b1 Sofia Papagiannaki
        if request.serialization == 'json':
931 32a437b1 Sofia Papagiannaki
            d = json.loads(data)
932 32a437b1 Sofia Papagiannaki
            if not hasattr(d, '__getitem__'):
933 32a437b1 Sofia Papagiannaki
                raise BadRequest('Invalid data formating')
934 32a437b1 Sofia Papagiannaki
            try:
935 32a437b1 Sofia Papagiannaki
                hashmap = d['hashes']
936 f899c7b4 Antony Chazapis
                size = int(d['bytes'])
937 f899c7b4 Antony Chazapis
            except:
938 32a437b1 Sofia Papagiannaki
                raise BadRequest('Invalid data formatting')
939 32a437b1 Sofia Papagiannaki
        elif request.serialization == 'xml':
940 32a437b1 Sofia Papagiannaki
            try:
941 32a437b1 Sofia Papagiannaki
                xml = minidom.parseString(data)
942 32a437b1 Sofia Papagiannaki
                obj = xml.getElementsByTagName('object')[0]
943 f899c7b4 Antony Chazapis
                size = int(obj.attributes['bytes'].value)
944 2715ade4 Sofia Papagiannaki
945 32a437b1 Sofia Papagiannaki
                hashes = xml.getElementsByTagName('hash')
946 32a437b1 Sofia Papagiannaki
                hashmap = []
947 32a437b1 Sofia Papagiannaki
                for hash in hashes:
948 32a437b1 Sofia Papagiannaki
                    hashmap.append(hash.firstChild.data)
949 f899c7b4 Antony Chazapis
            except:
950 32a437b1 Sofia Papagiannaki
                raise BadRequest('Invalid data formatting')
951 2715ade4 Sofia Papagiannaki
952 2715ade4 Sofia Papagiannaki
        checksum = ''  # Do not set to None (will copy previous value).
953 76985443 Sofia Papagiannaki
    else:
954 76985443 Sofia Papagiannaki
        md5 = hashlib.md5()
955 76985443 Sofia Papagiannaki
        size = 0
956 76985443 Sofia Papagiannaki
        hashmap = []
957 39593b2b Giorgos Verigakis
        for data in socket_read_iterator(request, content_length,
958 2715ade4 Sofia Papagiannaki
                                         request.backend.block_size):
959 76985443 Sofia Papagiannaki
            # TODO: Raise 408 (Request Timeout) if this takes too long.
960 76985443 Sofia Papagiannaki
            # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
961 76985443 Sofia Papagiannaki
            size += len(data)
962 39593b2b Giorgos Verigakis
            hashmap.append(request.backend.put_block(data))
963 76985443 Sofia Papagiannaki
            md5.update(data)
964 2715ade4 Sofia Papagiannaki
965 33b4e4a6 Antony Chazapis
        checksum = md5.hexdigest().lower()
966 76985443 Sofia Papagiannaki
        etag = request.META.get('HTTP_ETAG')
967 33b4e4a6 Antony Chazapis
        if etag and parse_etags(etag)[0].lower() != checksum:
968 76985443 Sofia Papagiannaki
            raise UnprocessableEntity('Object ETag does not match')
969 2715ade4 Sofia Papagiannaki
970 22dab079 Antony Chazapis
    try:
971 61efb530 Antony Chazapis
        version_id = request.backend.update_object_hashmap(request.user_uniq,
972 2715ade4 Sofia Papagiannaki
                                                           v_account, v_container, v_object, size, content_type,
973 2715ade4 Sofia Papagiannaki
                                                           hashmap, checksum, 'pithos', meta, True, permissions)
974 cca6c617 Antony Chazapis
    except NotAllowedError:
975 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
976 76985443 Sofia Papagiannaki
    except IndexError, e:
977 af7bb62f Antony Chazapis
        raise Conflict(simple_list_response(request, e.data))
978 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
979 22dab079 Antony Chazapis
        raise ItemNotFound('Container does not exist')
980 3436eeb0 Antony Chazapis
    except ValueError:
981 3436eeb0 Antony Chazapis
        raise BadRequest('Invalid sharing header')
982 5df6c6d1 Antony Chazapis
    except QuotaError:
983 5df6c6d1 Antony Chazapis
        raise RequestEntityTooLarge('Quota exceeded')
984 8efd183f Antony Chazapis
    if not checksum and UPDATE_MD5:
985 cddcf432 chazapis
        # Update the MD5 after the hashmap, as there may be missing hashes.
986 b3155065 Antony Chazapis
        checksum = hashmap_md5(request.backend, hashmap, size)
987 cddcf432 chazapis
        try:
988 b3155065 Antony Chazapis
            request.backend.update_object_checksum(request.user_uniq,
989 2715ade4 Sofia Papagiannaki
                                                   v_account, v_container, v_object, version_id, checksum)
990 cddcf432 chazapis
        except NotAllowedError:
991 cddcf432 chazapis
            raise Forbidden('Not allowed')
992 e0f916bb Antony Chazapis
    if public is not None:
993 e0f916bb Antony Chazapis
        try:
994 61efb530 Antony Chazapis
            request.backend.update_object_public(request.user_uniq, v_account,
995 2715ade4 Sofia Papagiannaki
                                                 v_container, v_object, public)
996 e0f916bb Antony Chazapis
        except NotAllowedError:
997 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
998 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
999 e0f916bb Antony Chazapis
            raise ItemNotFound('Object does not exist')
1000 2715ade4 Sofia Papagiannaki
1001 1993fea9 Antony Chazapis
    response = HttpResponse(status=201)
1002 33b4e4a6 Antony Chazapis
    if checksum:
1003 33b4e4a6 Antony Chazapis
        response['ETag'] = checksum
1004 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1005 b956618e Antony Chazapis
    return response
1006 b956618e Antony Chazapis
1007 2715ade4 Sofia Papagiannaki
1008 1d5c57d3 Antony Chazapis
@api_method('POST')
1009 1d5c57d3 Antony Chazapis
def object_write_form(request, v_account, v_container, v_object):
1010 1d5c57d3 Antony Chazapis
    # Normal Response Codes: 201
1011 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1012 1d5c57d3 Antony Chazapis
    #                       itemNotFound (404),
1013 297513ba Antony Chazapis
    #                       forbidden (403),
1014 1d5c57d3 Antony Chazapis
    #                       badRequest (400)
1015 2715ade4 Sofia Papagiannaki
1016 817890f2 Antony Chazapis
    request.upload_handlers = [SaveToBackendHandler(request)]
1017 2715ade4 Sofia Papagiannaki
    if 'X-Object-Data' not in request.FILES:
1018 1d5c57d3 Antony Chazapis
        raise BadRequest('Missing X-Object-Data field')
1019 1d5c57d3 Antony Chazapis
    file = request.FILES['X-Object-Data']
1020 2715ade4 Sofia Papagiannaki
1021 33b4e4a6 Antony Chazapis
    checksum = file.etag
1022 1d5c57d3 Antony Chazapis
    try:
1023 61efb530 Antony Chazapis
        version_id = request.backend.update_object_hashmap(request.user_uniq,
1024 2715ade4 Sofia Papagiannaki
                                                           v_account, v_container, v_object, file.size, file.content_type,
1025 2715ade4 Sofia Papagiannaki
                                                           file.hashmap, checksum, 'pithos', {}, True)
1026 1d5c57d3 Antony Chazapis
    except NotAllowedError:
1027 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
1028 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1029 1d5c57d3 Antony Chazapis
        raise ItemNotFound('Container does not exist')
1030 5df6c6d1 Antony Chazapis
    except QuotaError:
1031 5df6c6d1 Antony Chazapis
        raise RequestEntityTooLarge('Quota exceeded')
1032 2715ade4 Sofia Papagiannaki
1033 1d5c57d3 Antony Chazapis
    response = HttpResponse(status=201)
1034 33b4e4a6 Antony Chazapis
    response['ETag'] = checksum
1035 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1036 33b4e4a6 Antony Chazapis
    response.content = checksum
1037 1d5c57d3 Antony Chazapis
    return response
1038 1d5c57d3 Antony Chazapis
1039 2715ade4 Sofia Papagiannaki
1040 6b6b6c1e Antony Chazapis
@api_method('COPY', format_allowed=True)
1041 b956618e Antony Chazapis
def object_copy(request, v_account, v_container, v_object):
1042 b956618e Antony Chazapis
    # Normal Response Codes: 201
1043 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1044 b956618e Antony Chazapis
    #                       itemNotFound (404),
1045 297513ba Antony Chazapis
    #                       forbidden (403),
1046 b956618e Antony Chazapis
    #                       badRequest (400)
1047 2715ade4 Sofia Papagiannaki
1048 88283e9e Antony Chazapis
    dest_account = request.META.get('HTTP_DESTINATION_ACCOUNT')
1049 79bb41b7 Antony Chazapis
    if not dest_account:
1050 61efb530 Antony Chazapis
        dest_account = request.user_uniq
1051 88283e9e Antony Chazapis
    dest_path = request.META.get('HTTP_DESTINATION')
1052 b956618e Antony Chazapis
    if not dest_path:
1053 b956618e Antony Chazapis
        raise BadRequest('Missing Destination header')
1054 83dd59c5 Antony Chazapis
    try:
1055 83dd59c5 Antony Chazapis
        dest_container, dest_name = split_container_object_string(dest_path)
1056 83dd59c5 Antony Chazapis
    except ValueError:
1057 83dd59c5 Antony Chazapis
        raise BadRequest('Invalid Destination header')
1058 2715ade4 Sofia Papagiannaki
1059 a8326bef Antony Chazapis
    # Evaluate conditions.
1060 a8326bef Antony Chazapis
    if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
1061 a8326bef Antony Chazapis
        src_version = request.META.get('HTTP_X_SOURCE_VERSION')
1062 a8326bef Antony Chazapis
        try:
1063 2715ade4 Sofia Papagiannaki
            meta = request.backend.get_object_meta(
1064 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
1065 2715ade4 Sofia Papagiannaki
                v_container, v_object, 'pithos', src_version)
1066 a8326bef Antony Chazapis
        except NotAllowedError:
1067 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
1068 7efc9f86 Sofia Papagiannaki
        except (ItemNotExists, VersionNotExists):
1069 a8326bef Antony Chazapis
            raise ItemNotFound('Container or object does not exist')
1070 a8326bef Antony Chazapis
        validate_matching_preconditions(request, meta)
1071 2715ade4 Sofia Papagiannaki
1072 4d15c94e Sofia Papagiannaki
    delimiter = request.GET.get('delimiter')
1073 2715ade4 Sofia Papagiannaki
1074 79bb41b7 Antony Chazapis
    version_id = copy_or_move_object(request, v_account, v_container, v_object,
1075 2715ade4 Sofia Papagiannaki
                                     dest_account, dest_container, dest_name, move=False, delimiter=delimiter)
1076 7dd293a0 Antony Chazapis
    response = HttpResponse(status=201)
1077 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1078 7dd293a0 Antony Chazapis
    return response
1079 b956618e Antony Chazapis
1080 2715ade4 Sofia Papagiannaki
1081 6b6b6c1e Antony Chazapis
@api_method('MOVE', format_allowed=True)
1082 b956618e Antony Chazapis
def object_move(request, v_account, v_container, v_object):
1083 b956618e Antony Chazapis
    # Normal Response Codes: 201
1084 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1085 b956618e Antony Chazapis
    #                       itemNotFound (404),
1086 297513ba Antony Chazapis
    #                       forbidden (403),
1087 b956618e Antony Chazapis
    #                       badRequest (400)
1088 2715ade4 Sofia Papagiannaki
1089 88283e9e Antony Chazapis
    dest_account = request.META.get('HTTP_DESTINATION_ACCOUNT')
1090 79bb41b7 Antony Chazapis
    if not dest_account:
1091 61efb530 Antony Chazapis
        dest_account = request.user_uniq
1092 88283e9e Antony Chazapis
    dest_path = request.META.get('HTTP_DESTINATION')
1093 b956618e Antony Chazapis
    if not dest_path:
1094 b956618e Antony Chazapis
        raise BadRequest('Missing Destination header')
1095 83dd59c5 Antony Chazapis
    try:
1096 83dd59c5 Antony Chazapis
        dest_container, dest_name = split_container_object_string(dest_path)
1097 83dd59c5 Antony Chazapis
    except ValueError:
1098 83dd59c5 Antony Chazapis
        raise BadRequest('Invalid Destination header')
1099 2715ade4 Sofia Papagiannaki
1100 a8326bef Antony Chazapis
    # Evaluate conditions.
1101 a8326bef Antony Chazapis
    if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
1102 a8326bef Antony Chazapis
        try:
1103 2715ade4 Sofia Papagiannaki
            meta = request.backend.get_object_meta(
1104 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
1105 2715ade4 Sofia Papagiannaki
                v_container, v_object, 'pithos')
1106 a8326bef Antony Chazapis
        except NotAllowedError:
1107 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
1108 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
1109 a8326bef Antony Chazapis
            raise ItemNotFound('Container or object does not exist')
1110 a8326bef Antony Chazapis
        validate_matching_preconditions(request, meta)
1111 2715ade4 Sofia Papagiannaki
1112 4d15c94e Sofia Papagiannaki
    delimiter = request.GET.get('delimiter')
1113 2715ade4 Sofia Papagiannaki
1114 79bb41b7 Antony Chazapis
    version_id = copy_or_move_object(request, v_account, v_container, v_object,
1115 2715ade4 Sofia Papagiannaki
                                     dest_account, dest_container, dest_name, move=True, delimiter=delimiter)
1116 7dd293a0 Antony Chazapis
    response = HttpResponse(status=201)
1117 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1118 7dd293a0 Antony Chazapis
    return response
1119 b956618e Antony Chazapis
1120 2715ade4 Sofia Papagiannaki
1121 6b6b6c1e Antony Chazapis
@api_method('POST', format_allowed=True)
1122 b956618e Antony Chazapis
def object_update(request, v_account, v_container, v_object):
1123 e9285524 Antony Chazapis
    # Normal Response Codes: 202, 204
1124 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1125 3436eeb0 Antony Chazapis
    #                       conflict (409),
1126 b956618e Antony Chazapis
    #                       itemNotFound (404),
1127 297513ba Antony Chazapis
    #                       forbidden (403),
1128 b956618e Antony Chazapis
    #                       badRequest (400)
1129 2715ade4 Sofia Papagiannaki
1130 66ce2ca5 Antony Chazapis
    content_type, meta, permissions, public = get_object_headers(request)
1131 2715ade4 Sofia Papagiannaki
1132 cfe6939d Antony Chazapis
    try:
1133 2715ade4 Sofia Papagiannaki
        prev_meta = request.backend.get_object_meta(
1134 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account,
1135 2715ade4 Sofia Papagiannaki
            v_container, v_object, 'pithos')
1136 cca6c617 Antony Chazapis
    except NotAllowedError:
1137 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
1138 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1139 cfe6939d Antony Chazapis
        raise ItemNotFound('Object does not exist')
1140 2715ade4 Sofia Papagiannaki
1141 a8326bef Antony Chazapis
    # Evaluate conditions.
1142 a8326bef Antony Chazapis
    if request.META.get('HTTP_IF_MATCH') or request.META.get('HTTP_IF_NONE_MATCH'):
1143 a8326bef Antony Chazapis
        validate_matching_preconditions(request, prev_meta)
1144 2715ade4 Sofia Papagiannaki
1145 ac62f6da Antony Chazapis
    replace = True
1146 ac62f6da Antony Chazapis
    if 'update' in request.GET:
1147 ac62f6da Antony Chazapis
        replace = False
1148 2715ade4 Sofia Papagiannaki
1149 ab2e317e Antony Chazapis
    # A Content-Type or X-Source-Object header indicates data updates.
1150 ab2e317e Antony Chazapis
    src_object = request.META.get('HTTP_X_SOURCE_OBJECT')
1151 ab2e317e Antony Chazapis
    if (not content_type or content_type != 'application/octet-stream') and not src_object:
1152 77edd23d Antony Chazapis
        response = HttpResponse(status=202)
1153 2715ade4 Sofia Papagiannaki
1154 cca6c617 Antony Chazapis
        # Do permissions first, as it may fail easier.
1155 cca6c617 Antony Chazapis
        if permissions is not None:
1156 ac62f6da Antony Chazapis
            try:
1157 61efb530 Antony Chazapis
                request.backend.update_object_permissions(request.user_uniq,
1158 2715ade4 Sofia Papagiannaki
                                                          v_account, v_container, v_object, permissions)
1159 cca6c617 Antony Chazapis
            except NotAllowedError:
1160 297513ba Antony Chazapis
                raise Forbidden('Not allowed')
1161 7efc9f86 Sofia Papagiannaki
            except ItemNotExists:
1162 ac62f6da Antony Chazapis
                raise ItemNotFound('Object does not exist')
1163 ac62f6da Antony Chazapis
            except ValueError:
1164 ac62f6da Antony Chazapis
                raise BadRequest('Invalid sharing header')
1165 e0f916bb Antony Chazapis
        if public is not None:
1166 e0f916bb Antony Chazapis
            try:
1167 2715ade4 Sofia Papagiannaki
                request.backend.update_object_public(
1168 2715ade4 Sofia Papagiannaki
                    request.user_uniq, v_account,
1169 2715ade4 Sofia Papagiannaki
                    v_container, v_object, public)
1170 e0f916bb Antony Chazapis
            except NotAllowedError:
1171 297513ba Antony Chazapis
                raise Forbidden('Not allowed')
1172 7efc9f86 Sofia Papagiannaki
            except ItemNotExists:
1173 e0f916bb Antony Chazapis
                raise ItemNotFound('Object does not exist')
1174 77edd23d Antony Chazapis
        if meta or replace:
1175 77edd23d Antony Chazapis
            try:
1176 2715ade4 Sofia Papagiannaki
                version_id = request.backend.update_object_meta(
1177 2715ade4 Sofia Papagiannaki
                    request.user_uniq,
1178 2715ade4 Sofia Papagiannaki
                    v_account, v_container, v_object, 'pithos', meta, replace)
1179 77edd23d Antony Chazapis
            except NotAllowedError:
1180 297513ba Antony Chazapis
                raise Forbidden('Not allowed')
1181 7efc9f86 Sofia Papagiannaki
            except ItemNotExists:
1182 2715ade4 Sofia Papagiannaki
                raise ItemNotFound('Object does not exist')
1183 77edd23d Antony Chazapis
            response['X-Object-Version'] = version_id
1184 2715ade4 Sofia Papagiannaki
1185 7dd293a0 Antony Chazapis
        return response
1186 2715ade4 Sofia Papagiannaki
1187 cfe6939d Antony Chazapis
    # Single range update. Range must be in Content-Range.
1188 22dab079 Antony Chazapis
    # Based on: http://code.google.com/p/gears/wiki/ContentRangePostProposal
1189 cfe6939d Antony Chazapis
    # (with the addition that '*' is allowed for the range - will append).
1190 22dab079 Antony Chazapis
    content_range = request.META.get('HTTP_CONTENT_RANGE')
1191 22dab079 Antony Chazapis
    if not content_range:
1192 ac62f6da Antony Chazapis
        raise BadRequest('Missing Content-Range header')
1193 22dab079 Antony Chazapis
    ranges = get_content_range(request)
1194 22dab079 Antony Chazapis
    if not ranges:
1195 ac62f6da Antony Chazapis
        raise RangeNotSatisfiable('Invalid Content-Range header')
1196 2715ade4 Sofia Papagiannaki
1197 cfe6939d Antony Chazapis
    try:
1198 61efb530 Antony Chazapis
        size, hashmap = request.backend.get_object_hashmap(request.user_uniq,
1199 2715ade4 Sofia Papagiannaki
                                                           v_account, v_container, v_object)
1200 cca6c617 Antony Chazapis
    except NotAllowedError:
1201 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
1202 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1203 cfe6939d Antony Chazapis
        raise ItemNotFound('Object does not exist')
1204 2715ade4 Sofia Papagiannaki
1205 cfe6939d Antony Chazapis
    offset, length, total = ranges
1206 cfe6939d Antony Chazapis
    if offset is None:
1207 cfe6939d Antony Chazapis
        offset = size
1208 cb146cf9 Antony Chazapis
    elif offset > size:
1209 cb146cf9 Antony Chazapis
        raise RangeNotSatisfiable('Supplied offset is beyond object limits')
1210 ab2e317e Antony Chazapis
    if src_object:
1211 88283e9e Antony Chazapis
        src_account = request.META.get('HTTP_X_SOURCE_ACCOUNT')
1212 2cd94d81 Antony Chazapis
        if not src_account:
1213 61efb530 Antony Chazapis
            src_account = request.user_uniq
1214 ab2e317e Antony Chazapis
        src_container, src_name = split_container_object_string(src_object)
1215 ab2e317e Antony Chazapis
        src_version = request.META.get('HTTP_X_SOURCE_VERSION')
1216 ab2e317e Antony Chazapis
        try:
1217 2715ade4 Sofia Papagiannaki
            src_size, src_hashmap = request.backend.get_object_hashmap(
1218 2715ade4 Sofia Papagiannaki
                request.user_uniq,
1219 2715ade4 Sofia Papagiannaki
                src_account, src_container, src_name, src_version)
1220 ab2e317e Antony Chazapis
        except NotAllowedError:
1221 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
1222 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
1223 ab2e317e Antony Chazapis
            raise ItemNotFound('Source object does not exist')
1224 2715ade4 Sofia Papagiannaki
1225 ab2e317e Antony Chazapis
        if length is None:
1226 ab2e317e Antony Chazapis
            length = src_size
1227 ab2e317e Antony Chazapis
        elif length > src_size:
1228 ab2e317e Antony Chazapis
            raise BadRequest('Object length is smaller than range length')
1229 ab2e317e Antony Chazapis
    else:
1230 ab2e317e Antony Chazapis
        # Require either a Content-Length, or 'chunked' Transfer-Encoding.
1231 ab2e317e Antony Chazapis
        content_length = -1
1232 ab2e317e Antony Chazapis
        if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
1233 ab2e317e Antony Chazapis
            content_length = get_content_length(request)
1234 2715ade4 Sofia Papagiannaki
1235 ab2e317e Antony Chazapis
        if length is None:
1236 ab2e317e Antony Chazapis
            length = content_length
1237 ab2e317e Antony Chazapis
        else:
1238 ab2e317e Antony Chazapis
            if content_length == -1:
1239 ab2e317e Antony Chazapis
                # TODO: Get up to length bytes in chunks.
1240 ab2e317e Antony Chazapis
                length = content_length
1241 ab2e317e Antony Chazapis
            elif length != content_length:
1242 ab2e317e Antony Chazapis
                raise BadRequest('Content length does not match range length')
1243 cfe6939d Antony Chazapis
    if total is not None and (total != size or offset >= size or (length > 0 and offset + length >= size)):
1244 2715ade4 Sofia Papagiannaki
        raise RangeNotSatisfiable(
1245 2715ade4 Sofia Papagiannaki
            'Supplied range will change provided object limits')
1246 2715ade4 Sofia Papagiannaki
1247 1495b972 Antony Chazapis
    dest_bytes = request.META.get('HTTP_X_OBJECT_BYTES')
1248 1495b972 Antony Chazapis
    if dest_bytes is not None:
1249 1495b972 Antony Chazapis
        dest_bytes = get_int_parameter(dest_bytes)
1250 1495b972 Antony Chazapis
        if dest_bytes is None:
1251 1495b972 Antony Chazapis
            raise BadRequest('Invalid X-Object-Bytes header')
1252 2715ade4 Sofia Papagiannaki
1253 ab2e317e Antony Chazapis
    if src_object:
1254 39593b2b Giorgos Verigakis
        if offset % request.backend.block_size == 0:
1255 ab2e317e Antony Chazapis
            # Update the hashes only.
1256 ab2e317e Antony Chazapis
            sbi = 0
1257 ab2e317e Antony Chazapis
            while length > 0:
1258 39593b2b Giorgos Verigakis
                bi = int(offset / request.backend.block_size)
1259 39593b2b Giorgos Verigakis
                bl = min(length, request.backend.block_size)
1260 ab2e317e Antony Chazapis
                if bi < len(hashmap):
1261 39593b2b Giorgos Verigakis
                    if bl == request.backend.block_size:
1262 ab2e317e Antony Chazapis
                        hashmap[bi] = src_hashmap[sbi]
1263 ab2e317e Antony Chazapis
                    else:
1264 39593b2b Giorgos Verigakis
                        data = request.backend.get_block(src_hashmap[sbi])
1265 39593b2b Giorgos Verigakis
                        hashmap[bi] = request.backend.update_block(hashmap[bi],
1266 2715ade4 Sofia Papagiannaki
                                                                   data[:bl], 0)
1267 ab2e317e Antony Chazapis
                else:
1268 ab2e317e Antony Chazapis
                    hashmap.append(src_hashmap[sbi])
1269 ab2e317e Antony Chazapis
                offset += bl
1270 ab2e317e Antony Chazapis
                length -= bl
1271 ab2e317e Antony Chazapis
                sbi += 1
1272 ab2e317e Antony Chazapis
        else:
1273 ab2e317e Antony Chazapis
            data = ''
1274 ab2e317e Antony Chazapis
            sbi = 0
1275 ab2e317e Antony Chazapis
            while length > 0:
1276 39593b2b Giorgos Verigakis
                data += request.backend.get_block(src_hashmap[sbi])
1277 39593b2b Giorgos Verigakis
                if length < request.backend.block_size:
1278 ab2e317e Antony Chazapis
                    data = data[:length]
1279 39593b2b Giorgos Verigakis
                bytes = put_object_block(request, hashmap, data, offset)
1280 ab2e317e Antony Chazapis
                offset += bytes
1281 ab2e317e Antony Chazapis
                data = data[bytes:]
1282 ab2e317e Antony Chazapis
                length -= bytes
1283 ab2e317e Antony Chazapis
                sbi += 1
1284 ab2e317e Antony Chazapis
    else:
1285 ab2e317e Antony Chazapis
        data = ''
1286 39593b2b Giorgos Verigakis
        for d in socket_read_iterator(request, length,
1287 2715ade4 Sofia Papagiannaki
                                      request.backend.block_size):
1288 ab2e317e Antony Chazapis
            # TODO: Raise 408 (Request Timeout) if this takes too long.
1289 ab2e317e Antony Chazapis
            # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
1290 ab2e317e Antony Chazapis
            data += d
1291 39593b2b Giorgos Verigakis
            bytes = put_object_block(request, hashmap, data, offset)
1292 ab2e317e Antony Chazapis
            offset += bytes
1293 ab2e317e Antony Chazapis
            data = data[bytes:]
1294 ab2e317e Antony Chazapis
        if len(data) > 0:
1295 39593b2b Giorgos Verigakis
            put_object_block(request, hashmap, data, offset)
1296 2715ade4 Sofia Papagiannaki
1297 cfe6939d Antony Chazapis
    if offset > size:
1298 cfe6939d Antony Chazapis
        size = offset
1299 1495b972 Antony Chazapis
    if dest_bytes is not None and dest_bytes < size:
1300 1495b972 Antony Chazapis
        size = dest_bytes
1301 39593b2b Giorgos Verigakis
        hashmap = hashmap[:(int((size - 1) / request.backend.block_size) + 1)]
1302 2715ade4 Sofia Papagiannaki
    checksum = hashmap_md5(
1303 2715ade4 Sofia Papagiannaki
        request.backend, hashmap, size) if UPDATE_MD5 else ''
1304 cfe6939d Antony Chazapis
    try:
1305 61efb530 Antony Chazapis
        version_id = request.backend.update_object_hashmap(request.user_uniq,
1306 2715ade4 Sofia Papagiannaki
                                                           v_account, v_container, v_object, size, prev_meta[
1307 2715ade4 Sofia Papagiannaki
                                                           'type'],
1308 2715ade4 Sofia Papagiannaki
                                                           hashmap, checksum, 'pithos', meta, replace, permissions)
1309 cca6c617 Antony Chazapis
    except NotAllowedError:
1310 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
1311 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1312 cfe6939d Antony Chazapis
        raise ItemNotFound('Container does not exist')
1313 3436eeb0 Antony Chazapis
    except ValueError:
1314 3436eeb0 Antony Chazapis
        raise BadRequest('Invalid sharing header')
1315 5df6c6d1 Antony Chazapis
    except QuotaError:
1316 5df6c6d1 Antony Chazapis
        raise RequestEntityTooLarge('Quota exceeded')
1317 e0f916bb Antony Chazapis
    if public is not None:
1318 e0f916bb Antony Chazapis
        try:
1319 61efb530 Antony Chazapis
            request.backend.update_object_public(request.user_uniq, v_account,
1320 2715ade4 Sofia Papagiannaki
                                                 v_container, v_object, public)
1321 e0f916bb Antony Chazapis
        except NotAllowedError:
1322 297513ba Antony Chazapis
            raise Forbidden('Not allowed')
1323 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
1324 e0f916bb Antony Chazapis
            raise ItemNotFound('Object does not exist')
1325 2715ade4 Sofia Papagiannaki
1326 e9285524 Antony Chazapis
    response = HttpResponse(status=204)
1327 33b4e4a6 Antony Chazapis
    response['ETag'] = checksum
1328 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1329 e9285524 Antony Chazapis
    return response
1330 b956618e Antony Chazapis
1331 2715ade4 Sofia Papagiannaki
1332 b956618e Antony Chazapis
@api_method('DELETE')
1333 b956618e Antony Chazapis
def object_delete(request, v_account, v_container, v_object):
1334 b956618e Antony Chazapis
    # Normal Response Codes: 204
1335 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1336 b956618e Antony Chazapis
    #                       itemNotFound (404),
1337 297513ba Antony Chazapis
    #                       forbidden (403),
1338 b956618e Antony Chazapis
    #                       badRequest (400)
1339 2715ade4 Sofia Papagiannaki
1340 bbd20b55 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
1341 4d15c94e Sofia Papagiannaki
    delimiter = request.GET.get('delimiter')
1342 2715ade4 Sofia Papagiannaki
1343 b956618e Antony Chazapis
    try:
1344 2715ade4 Sofia Papagiannaki
        request.backend.delete_object(
1345 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account, v_container,
1346 2715ade4 Sofia Papagiannaki
            v_object, until, delimiter=delimiter)
1347 cca6c617 Antony Chazapis
    except NotAllowedError:
1348 297513ba Antony Chazapis
        raise Forbidden('Not allowed')
1349 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1350 b956618e Antony Chazapis
        raise ItemNotFound('Object does not exist')
1351 b956618e Antony Chazapis
    return HttpResponse(status=204)
1352 b956618e Antony Chazapis
1353 2715ade4 Sofia Papagiannaki
1354 b956618e Antony Chazapis
@api_method()
1355 b956618e Antony Chazapis
def method_not_allowed(request):
1356 b956618e Antony Chazapis
    raise BadRequest('Method not allowed')