Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / functions.py @ 00e9ef7b

History | View | Annotate | Download (50.9 kB)

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