Statistics
| Branch: | Tag: | Revision:

root / pithos / api / functions.py @ 6d817842

History | View | Annotate | Download (26.2 kB)

1 5635f9ef Antony Chazapis
# Copyright 2011 GRNET S.A. All rights reserved.
2 5635f9ef Antony Chazapis
# 
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 5635f9ef Antony Chazapis
# 
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 5635f9ef Antony Chazapis
# 
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 5635f9ef Antony Chazapis
# 
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 5635f9ef Antony Chazapis
# 
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 b956618e Antony Chazapis
import os
35 b956618e Antony Chazapis
import logging
36 b956618e Antony Chazapis
import hashlib
37 b956618e Antony Chazapis
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 b956618e Antony Chazapis
43 b956618e Antony Chazapis
from pithos.api.faults import (Fault, NotModified, BadRequest, Unauthorized, ItemNotFound, Conflict,
44 b956618e Antony Chazapis
    LengthRequired, PreconditionFailed, RangeNotSatisfiable, UnprocessableEntity)
45 22dab079 Antony Chazapis
from pithos.api.util import (format_meta_key, printable_meta_dict, get_account_meta,
46 22dab079 Antony Chazapis
    put_account_meta, get_container_meta, put_container_meta, get_object_meta, put_object_meta,
47 8cb45c13 Antony Chazapis
    update_manifest_meta, validate_modification_preconditions, validate_matching_preconditions,
48 8cb45c13 Antony Chazapis
    split_container_object_string, copy_or_move_object, get_int_parameter, get_content_length,
49 8cb45c13 Antony Chazapis
    get_content_range, raw_input_socket, socket_read_iterator, object_data_response,
50 8cb45c13 Antony Chazapis
    hashmap_hash, api_method)
51 b956618e Antony Chazapis
from pithos.backends import backend
52 b956618e Antony Chazapis
53 b956618e Antony Chazapis
54 b956618e Antony Chazapis
logger = logging.getLogger(__name__)
55 b956618e Antony Chazapis
56 b956618e Antony Chazapis
57 b956618e Antony Chazapis
def top_demux(request):
58 b956618e Antony Chazapis
    if request.method == 'GET':
59 b956618e Antony Chazapis
        return authenticate(request)
60 b956618e Antony Chazapis
    else:
61 b956618e Antony Chazapis
        return method_not_allowed(request)
62 b956618e Antony Chazapis
63 b956618e Antony Chazapis
def account_demux(request, v_account):
64 b956618e Antony Chazapis
    if request.method == 'HEAD':
65 b956618e Antony Chazapis
        return account_meta(request, v_account)
66 b956618e Antony Chazapis
    elif request.method == 'POST':
67 b956618e Antony Chazapis
        return account_update(request, v_account)
68 83dd59c5 Antony Chazapis
    elif request.method == 'GET':
69 83dd59c5 Antony Chazapis
        return container_list(request, v_account)
70 b956618e Antony Chazapis
    else:
71 b956618e Antony Chazapis
        return method_not_allowed(request)
72 b956618e Antony Chazapis
73 b956618e Antony Chazapis
def container_demux(request, v_account, v_container):
74 b956618e Antony Chazapis
    if request.method == 'HEAD':
75 b956618e Antony Chazapis
        return container_meta(request, v_account, v_container)
76 b956618e Antony Chazapis
    elif request.method == 'PUT':
77 b956618e Antony Chazapis
        return container_create(request, v_account, v_container)
78 b956618e Antony Chazapis
    elif request.method == 'POST':
79 b956618e Antony Chazapis
        return container_update(request, v_account, v_container)
80 b956618e Antony Chazapis
    elif request.method == 'DELETE':
81 b956618e Antony Chazapis
        return container_delete(request, v_account, v_container)
82 83dd59c5 Antony Chazapis
    elif request.method == 'GET':
83 83dd59c5 Antony Chazapis
        return object_list(request, v_account, v_container)
84 b956618e Antony Chazapis
    else:
85 b956618e Antony Chazapis
        return method_not_allowed(request)
86 b956618e Antony Chazapis
87 b956618e Antony Chazapis
def object_demux(request, v_account, v_container, v_object):
88 b956618e Antony Chazapis
    if request.method == 'HEAD':
89 b956618e Antony Chazapis
        return object_meta(request, v_account, v_container, v_object)
90 b956618e Antony Chazapis
    elif request.method == 'GET':
91 b956618e Antony Chazapis
        return object_read(request, v_account, v_container, v_object)
92 b956618e Antony Chazapis
    elif request.method == 'PUT':
93 b956618e Antony Chazapis
        return object_write(request, v_account, v_container, v_object)
94 b956618e Antony Chazapis
    elif request.method == 'COPY':
95 b956618e Antony Chazapis
        return object_copy(request, v_account, v_container, v_object)
96 b956618e Antony Chazapis
    elif request.method == 'MOVE':
97 b956618e Antony Chazapis
        return object_move(request, v_account, v_container, v_object)
98 b956618e Antony Chazapis
    elif request.method == 'POST':
99 b956618e Antony Chazapis
        return object_update(request, v_account, v_container, v_object)
100 b956618e Antony Chazapis
    elif request.method == 'DELETE':
101 b956618e Antony Chazapis
        return object_delete(request, v_account, v_container, v_object)
102 b956618e Antony Chazapis
    else:
103 b956618e Antony Chazapis
        return method_not_allowed(request)
104 b956618e Antony Chazapis
105 b956618e Antony Chazapis
@api_method('GET')
106 b956618e Antony Chazapis
def authenticate(request):
107 b956618e Antony Chazapis
    # Normal Response Codes: 204
108 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
109 b956618e Antony Chazapis
    #                       unauthorized (401),
110 b956618e Antony Chazapis
    #                       badRequest (400)
111 b956618e Antony Chazapis
    
112 b956618e Antony Chazapis
    x_auth_user = request.META.get('HTTP_X_AUTH_USER')
113 b956618e Antony Chazapis
    x_auth_key = request.META.get('HTTP_X_AUTH_KEY')
114 b956618e Antony Chazapis
    if not x_auth_user or not x_auth_key:
115 b956618e Antony Chazapis
        raise BadRequest('Missing X-Auth-User or X-Auth-Key header')
116 b956618e Antony Chazapis
    response = HttpResponse(status=204)
117 b956618e Antony Chazapis
    response['X-Auth-Token'] = '0000'
118 b956618e Antony Chazapis
    response['X-Storage-Url'] = os.path.join(request.build_absolute_uri(), 'demo')
119 b956618e Antony Chazapis
    return response
120 b956618e Antony Chazapis
121 b956618e Antony Chazapis
@api_method('HEAD')
122 b956618e Antony Chazapis
def account_meta(request, v_account):
123 b956618e Antony Chazapis
    # Normal Response Codes: 204
124 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
125 b956618e Antony Chazapis
    #                       unauthorized (401),
126 b956618e Antony Chazapis
    #                       badRequest (400)
127 b956618e Antony Chazapis
    
128 83dd59c5 Antony Chazapis
    until = get_int_parameter(request, 'until')
129 83dd59c5 Antony Chazapis
    meta = backend.get_account_meta(request.user, v_account, until)
130 b956618e Antony Chazapis
    
131 b956618e Antony Chazapis
    response = HttpResponse(status=204)
132 b956618e Antony Chazapis
    put_account_meta(response, meta)
133 b956618e Antony Chazapis
    return response
134 b956618e Antony Chazapis
135 b956618e Antony Chazapis
@api_method('POST')
136 b956618e Antony Chazapis
def account_update(request, v_account):
137 b956618e Antony Chazapis
    # Normal Response Codes: 202
138 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
139 b956618e Antony Chazapis
    #                       unauthorized (401),
140 b956618e Antony Chazapis
    #                       badRequest (400)
141 b956618e Antony Chazapis
    
142 b956618e Antony Chazapis
    meta = get_account_meta(request)    
143 83dd59c5 Antony Chazapis
    backend.update_account_meta(request.user, v_account, meta, replace=True)
144 b956618e Antony Chazapis
    return HttpResponse(status=202)
145 b956618e Antony Chazapis
146 b956618e Antony Chazapis
@api_method('GET', format_allowed=True)
147 b956618e Antony Chazapis
def container_list(request, v_account):
148 b956618e Antony Chazapis
    # Normal Response Codes: 200, 204
149 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
150 b956618e Antony Chazapis
    #                       itemNotFound (404),
151 b956618e Antony Chazapis
    #                       unauthorized (401),
152 b956618e Antony Chazapis
    #                       badRequest (400)
153 b956618e Antony Chazapis
    
154 83dd59c5 Antony Chazapis
    until = get_int_parameter(request, 'until')
155 83dd59c5 Antony Chazapis
    meta = backend.get_account_meta(request.user, v_account, until)
156 b956618e Antony Chazapis
    
157 b956618e Antony Chazapis
    validate_modification_preconditions(request, meta)
158 b956618e Antony Chazapis
    
159 b956618e Antony Chazapis
    response = HttpResponse()
160 b956618e Antony Chazapis
    put_account_meta(response, meta)
161 b956618e Antony Chazapis
    
162 b956618e Antony Chazapis
    marker = request.GET.get('marker')
163 b956618e Antony Chazapis
    limit = request.GET.get('limit')
164 b956618e Antony Chazapis
    if limit:
165 b956618e Antony Chazapis
        try:
166 b956618e Antony Chazapis
            limit = int(limit)
167 b956618e Antony Chazapis
            if limit <= 0:
168 b956618e Antony Chazapis
                raise ValueError
169 b956618e Antony Chazapis
        except ValueError:
170 b956618e Antony Chazapis
            limit = 10000
171 b956618e Antony Chazapis
    
172 b956618e Antony Chazapis
    try:
173 83dd59c5 Antony Chazapis
        containers = backend.list_containers(request.user, v_account, marker, limit, until)
174 b956618e Antony Chazapis
    except NameError:
175 b956618e Antony Chazapis
        containers = []
176 b956618e Antony Chazapis
    
177 b956618e Antony Chazapis
    if request.serialization == 'text':
178 b956618e Antony Chazapis
        if len(containers) == 0:
179 b956618e Antony Chazapis
            # The cloudfiles python bindings expect 200 if json/xml.
180 b956618e Antony Chazapis
            response.status_code = 204
181 b956618e Antony Chazapis
            return response
182 b956618e Antony Chazapis
        response.status_code = 200
183 83dd59c5 Antony Chazapis
        response.content = '\n'.join([x[0] for x in containers]) + '\n'
184 b956618e Antony Chazapis
        return response
185 b956618e Antony Chazapis
    
186 b956618e Antony Chazapis
    container_meta = []
187 b956618e Antony Chazapis
    for x in containers:
188 83dd59c5 Antony Chazapis
        if x[1] is not None:
189 83dd59c5 Antony Chazapis
            try:
190 83dd59c5 Antony Chazapis
                meta = backend.get_container_meta(request.user, v_account, x[0], until)
191 83dd59c5 Antony Chazapis
                container_meta.append(printable_meta_dict(meta))
192 83dd59c5 Antony Chazapis
            except NameError:
193 83dd59c5 Antony Chazapis
                pass
194 b956618e Antony Chazapis
    if request.serialization == 'xml':
195 2c22e4ac Antony Chazapis
        data = render_to_string('containers.xml', {'account': v_account, 'containers': container_meta})
196 b956618e Antony Chazapis
    elif request.serialization  == 'json':
197 b956618e Antony Chazapis
        data = json.dumps(container_meta)
198 b956618e Antony Chazapis
    response.status_code = 200
199 b956618e Antony Chazapis
    response.content = data
200 b956618e Antony Chazapis
    return response
201 b956618e Antony Chazapis
202 b956618e Antony Chazapis
@api_method('HEAD')
203 b956618e Antony Chazapis
def container_meta(request, v_account, v_container):
204 b956618e Antony Chazapis
    # Normal Response Codes: 204
205 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
206 b956618e Antony Chazapis
    #                       itemNotFound (404),
207 b956618e Antony Chazapis
    #                       unauthorized (401),
208 b956618e Antony Chazapis
    #                       badRequest (400)
209 b956618e Antony Chazapis
    
210 83dd59c5 Antony Chazapis
    until = get_int_parameter(request, 'until')
211 b956618e Antony Chazapis
    try:
212 83dd59c5 Antony Chazapis
        meta = backend.get_container_meta(request.user, v_account, v_container, until)
213 83dd59c5 Antony Chazapis
        meta['object_meta'] = backend.list_object_meta(request.user, v_account, v_container, until)
214 b956618e Antony Chazapis
    except NameError:
215 b956618e Antony Chazapis
        raise ItemNotFound('Container does not exist')
216 b956618e Antony Chazapis
    
217 b956618e Antony Chazapis
    response = HttpResponse(status=204)
218 b956618e Antony Chazapis
    put_container_meta(response, meta)
219 b956618e Antony Chazapis
    return response
220 b956618e Antony Chazapis
221 b956618e Antony Chazapis
@api_method('PUT')
222 b956618e Antony Chazapis
def container_create(request, v_account, v_container):
223 b956618e Antony Chazapis
    # Normal Response Codes: 201, 202
224 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
225 b956618e Antony Chazapis
    #                       itemNotFound (404),
226 b956618e Antony Chazapis
    #                       unauthorized (401),
227 b956618e Antony Chazapis
    #                       badRequest (400)
228 b956618e Antony Chazapis
    
229 b956618e Antony Chazapis
    meta = get_container_meta(request)
230 b956618e Antony Chazapis
    
231 b956618e Antony Chazapis
    try:
232 83dd59c5 Antony Chazapis
        backend.put_container(request.user, v_account, v_container)
233 b956618e Antony Chazapis
        ret = 201
234 b956618e Antony Chazapis
    except NameError:
235 b956618e Antony Chazapis
        ret = 202
236 b956618e Antony Chazapis
    
237 b956618e Antony Chazapis
    if len(meta) > 0:
238 83dd59c5 Antony Chazapis
        backend.update_container_meta(request.user, v_account, v_container, meta, replace=True)
239 b956618e Antony Chazapis
    
240 b956618e Antony Chazapis
    return HttpResponse(status=ret)
241 b956618e Antony Chazapis
242 b956618e Antony Chazapis
@api_method('POST')
243 b956618e Antony Chazapis
def container_update(request, v_account, v_container):
244 b956618e Antony Chazapis
    # Normal Response Codes: 202
245 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
246 b956618e Antony Chazapis
    #                       itemNotFound (404),
247 b956618e Antony Chazapis
    #                       unauthorized (401),
248 b956618e Antony Chazapis
    #                       badRequest (400)
249 b956618e Antony Chazapis
    
250 b956618e Antony Chazapis
    meta = get_container_meta(request)
251 b956618e Antony Chazapis
    try:
252 83dd59c5 Antony Chazapis
        backend.update_container_meta(request.user, v_account, v_container, meta, replace=True)
253 b956618e Antony Chazapis
    except NameError:
254 b956618e Antony Chazapis
        raise ItemNotFound('Container does not exist')
255 b956618e Antony Chazapis
    return HttpResponse(status=202)
256 b956618e Antony Chazapis
257 b956618e Antony Chazapis
@api_method('DELETE')
258 b956618e Antony Chazapis
def container_delete(request, v_account, v_container):
259 b956618e Antony Chazapis
    # Normal Response Codes: 204
260 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
261 b956618e Antony Chazapis
    #                       conflict (409),
262 b956618e Antony Chazapis
    #                       itemNotFound (404),
263 b956618e Antony Chazapis
    #                       unauthorized (401),
264 b956618e Antony Chazapis
    #                       badRequest (400)
265 b956618e Antony Chazapis
    
266 b956618e Antony Chazapis
    try:
267 83dd59c5 Antony Chazapis
        backend.delete_container(request.user, v_account, v_container)
268 b956618e Antony Chazapis
    except NameError:
269 b956618e Antony Chazapis
        raise ItemNotFound('Container does not exist')
270 b956618e Antony Chazapis
    except IndexError:
271 b956618e Antony Chazapis
        raise Conflict('Container is not empty')
272 b956618e Antony Chazapis
    return HttpResponse(status=204)
273 b956618e Antony Chazapis
274 b956618e Antony Chazapis
@api_method('GET', format_allowed=True)
275 b956618e Antony Chazapis
def object_list(request, v_account, v_container):
276 b956618e Antony Chazapis
    # Normal Response Codes: 200, 204
277 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
278 b956618e Antony Chazapis
    #                       itemNotFound (404),
279 b956618e Antony Chazapis
    #                       unauthorized (401),
280 b956618e Antony Chazapis
    #                       badRequest (400)
281 b956618e Antony Chazapis
    
282 83dd59c5 Antony Chazapis
    until = get_int_parameter(request, 'until')
283 b956618e Antony Chazapis
    try:
284 83dd59c5 Antony Chazapis
        meta = backend.get_container_meta(request.user, v_account, v_container, until)
285 83dd59c5 Antony Chazapis
        meta['object_meta'] = backend.list_object_meta(request.user, v_account, v_container, until)
286 b956618e Antony Chazapis
    except NameError:
287 b956618e Antony Chazapis
        raise ItemNotFound('Container does not exist')
288 b956618e Antony Chazapis
    
289 b956618e Antony Chazapis
    validate_modification_preconditions(request, meta)
290 b956618e Antony Chazapis
    
291 b956618e Antony Chazapis
    response = HttpResponse()
292 b956618e Antony Chazapis
    put_container_meta(response, meta)
293 b956618e Antony Chazapis
    
294 b956618e Antony Chazapis
    path = request.GET.get('path')
295 b956618e Antony Chazapis
    prefix = request.GET.get('prefix')
296 b956618e Antony Chazapis
    delimiter = request.GET.get('delimiter')
297 b956618e Antony Chazapis
    
298 b956618e Antony Chazapis
    # Path overrides prefix and delimiter.
299 b956618e Antony Chazapis
    virtual = True
300 b956618e Antony Chazapis
    if path:
301 b956618e Antony Chazapis
        prefix = path
302 b956618e Antony Chazapis
        delimiter = '/'
303 b956618e Antony Chazapis
        virtual = False
304 b956618e Antony Chazapis
    
305 b956618e Antony Chazapis
    # Naming policy.
306 b956618e Antony Chazapis
    if prefix and delimiter:
307 b956618e Antony Chazapis
        prefix = prefix + delimiter
308 b956618e Antony Chazapis
    if not prefix:
309 b956618e Antony Chazapis
        prefix = ''
310 b956618e Antony Chazapis
    prefix = prefix.lstrip('/')
311 b956618e Antony Chazapis
    
312 b956618e Antony Chazapis
    marker = request.GET.get('marker')
313 b956618e Antony Chazapis
    limit = request.GET.get('limit')
314 b956618e Antony Chazapis
    if limit:
315 b956618e Antony Chazapis
        try:
316 b956618e Antony Chazapis
            limit = int(limit)
317 b956618e Antony Chazapis
            if limit <= 0:
318 b956618e Antony Chazapis
                raise ValueError
319 b956618e Antony Chazapis
        except ValueError:
320 b956618e Antony Chazapis
            limit = 10000
321 b956618e Antony Chazapis
    
322 22dab079 Antony Chazapis
    keys = request.GET.get('meta')
323 22dab079 Antony Chazapis
    if keys:
324 22dab079 Antony Chazapis
        keys = keys.split(',')
325 22dab079 Antony Chazapis
        keys = [format_meta_key('X-Object-Meta-' + x.strip()) for x in keys if x.strip() != '']
326 22dab079 Antony Chazapis
    else:
327 22dab079 Antony Chazapis
        keys = []
328 22dab079 Antony Chazapis
    
329 b956618e Antony Chazapis
    try:
330 83dd59c5 Antony Chazapis
        objects = backend.list_objects(request.user, v_account, v_container, prefix, delimiter, marker, limit, virtual, keys, until)
331 b956618e Antony Chazapis
    except NameError:
332 b956618e Antony Chazapis
        raise ItemNotFound('Container does not exist')
333 b956618e Antony Chazapis
    
334 b956618e Antony Chazapis
    if request.serialization == 'text':
335 b956618e Antony Chazapis
        if len(objects) == 0:
336 b956618e Antony Chazapis
            # The cloudfiles python bindings expect 200 if json/xml.
337 b956618e Antony Chazapis
            response.status_code = 204
338 b956618e Antony Chazapis
            return response
339 b956618e Antony Chazapis
        response.status_code = 200
340 83dd59c5 Antony Chazapis
        response.content = '\n'.join([x[0] for x in objects]) + '\n'
341 b956618e Antony Chazapis
        return response
342 b956618e Antony Chazapis
    
343 b956618e Antony Chazapis
    object_meta = []
344 b956618e Antony Chazapis
    for x in objects:
345 83dd59c5 Antony Chazapis
        if x[1] is None:
346 b956618e Antony Chazapis
            # Virtual objects/directories.
347 83dd59c5 Antony Chazapis
            object_meta.append({'subdir': x[0]})
348 83dd59c5 Antony Chazapis
        else:
349 83dd59c5 Antony Chazapis
            try:
350 83dd59c5 Antony Chazapis
                meta = backend.get_object_meta(request.user, v_account, v_container, x[0], x[1])
351 83dd59c5 Antony Chazapis
                object_meta.append(printable_meta_dict(meta))
352 83dd59c5 Antony Chazapis
            except NameError:
353 83dd59c5 Antony Chazapis
                pass
354 b956618e Antony Chazapis
    if request.serialization == 'xml':
355 b956618e Antony Chazapis
        data = render_to_string('objects.xml', {'container': v_container, 'objects': object_meta})
356 b956618e Antony Chazapis
    elif request.serialization  == 'json':
357 b956618e Antony Chazapis
        data = json.dumps(object_meta)
358 b956618e Antony Chazapis
    response.status_code = 200
359 b956618e Antony Chazapis
    response.content = data
360 b956618e Antony Chazapis
    return response
361 b956618e Antony Chazapis
362 b956618e Antony Chazapis
@api_method('HEAD')
363 b956618e Antony Chazapis
def object_meta(request, v_account, v_container, v_object):
364 b956618e Antony Chazapis
    # Normal Response Codes: 204
365 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
366 b956618e Antony Chazapis
    #                       itemNotFound (404),
367 b956618e Antony Chazapis
    #                       unauthorized (401),
368 b956618e Antony Chazapis
    #                       badRequest (400)
369 b956618e Antony Chazapis
    
370 83dd59c5 Antony Chazapis
    version = get_int_parameter(request, 'version')
371 b956618e Antony Chazapis
    try:
372 83dd59c5 Antony Chazapis
        meta = backend.get_object_meta(request.user, v_account, v_container, v_object, version)
373 b956618e Antony Chazapis
    except NameError:
374 b956618e Antony Chazapis
        raise ItemNotFound('Object does not exist')
375 58a6c894 Antony Chazapis
    except IndexError:
376 58a6c894 Antony Chazapis
        raise ItemNotFound('Version does not exist')
377 b956618e Antony Chazapis
    
378 8cb45c13 Antony Chazapis
    update_manifest_meta(request, v_account, meta)
379 8cb45c13 Antony Chazapis
    
380 b956618e Antony Chazapis
    response = HttpResponse(status=204)
381 b956618e Antony Chazapis
    put_object_meta(response, meta)
382 b956618e Antony Chazapis
    return response
383 b956618e Antony Chazapis
384 22dab079 Antony Chazapis
@api_method('GET', format_allowed=True)
385 b956618e Antony Chazapis
def object_read(request, v_account, v_container, v_object):
386 b956618e Antony Chazapis
    # Normal Response Codes: 200, 206
387 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
388 b956618e Antony Chazapis
    #                       rangeNotSatisfiable (416),
389 b956618e Antony Chazapis
    #                       preconditionFailed (412),
390 b956618e Antony Chazapis
    #                       itemNotFound (404),
391 b956618e Antony Chazapis
    #                       unauthorized (401),
392 b956618e Antony Chazapis
    #                       badRequest (400),
393 b956618e Antony Chazapis
    #                       notModified (304)
394 b956618e Antony Chazapis
    
395 83dd59c5 Antony Chazapis
    version = get_int_parameter(request, 'version')
396 b956618e Antony Chazapis
    try:
397 83dd59c5 Antony Chazapis
        meta = backend.get_object_meta(request.user, v_account, v_container, v_object, version)
398 b956618e Antony Chazapis
    except NameError:
399 b956618e Antony Chazapis
        raise ItemNotFound('Object does not exist')
400 58a6c894 Antony Chazapis
    except IndexError:
401 58a6c894 Antony Chazapis
        raise ItemNotFound('Version does not exist')
402 b956618e Antony Chazapis
    
403 8cb45c13 Antony Chazapis
    update_manifest_meta(request, v_account, meta)
404 8cb45c13 Antony Chazapis
    
405 22dab079 Antony Chazapis
    # Evaluate conditions.
406 b956618e Antony Chazapis
    validate_modification_preconditions(request, meta)
407 22dab079 Antony Chazapis
    try:
408 22dab079 Antony Chazapis
        validate_matching_preconditions(request, meta)
409 22dab079 Antony Chazapis
    except NotModified:
410 22dab079 Antony Chazapis
        response = HttpResponse(status=304)
411 22dab079 Antony Chazapis
        response['ETag'] = meta['hash']
412 22dab079 Antony Chazapis
        return response
413 b956618e Antony Chazapis
    
414 83dd59c5 Antony Chazapis
    # Reply with the version list.
415 83dd59c5 Antony Chazapis
    if version == 'list':
416 83dd59c5 Antony Chazapis
        if request.serialization == 'text':
417 83dd59c5 Antony Chazapis
            raise BadRequest('No format specified for version list.')
418 83dd59c5 Antony Chazapis
        
419 83dd59c5 Antony Chazapis
        d = {'versions': backend.list_versions(request.user, v_account, v_container, v_object)}
420 83dd59c5 Antony Chazapis
        if request.serialization == 'xml':
421 83dd59c5 Antony Chazapis
            d['object'] = v_object
422 83dd59c5 Antony Chazapis
            data = render_to_string('versions.xml', d)
423 83dd59c5 Antony Chazapis
        elif request.serialization  == 'json':
424 83dd59c5 Antony Chazapis
            data = json.dumps(d)
425 83dd59c5 Antony Chazapis
        
426 83dd59c5 Antony Chazapis
        response = HttpResponse(data, status=200)
427 83dd59c5 Antony Chazapis
        put_object_meta(response, meta)
428 83dd59c5 Antony Chazapis
        response['Content-Length'] = len(data)
429 83dd59c5 Antony Chazapis
        return response
430 83dd59c5 Antony Chazapis
    
431 8cb45c13 Antony Chazapis
    sizes = []
432 8cb45c13 Antony Chazapis
    hashmaps = []
433 8cb45c13 Antony Chazapis
    if 'X-Object-Manifest' in meta:
434 8cb45c13 Antony Chazapis
        try:
435 6d817842 Antony Chazapis
            src_container, src_name = split_container_object_string('/' + meta['X-Object-Manifest'])
436 8cb45c13 Antony Chazapis
            objects = backend.list_objects(request.user, v_account, src_container, prefix=src_name, virtual=False)
437 8cb45c13 Antony Chazapis
        except ValueError:
438 8cb45c13 Antony Chazapis
            raise BadRequest('Invalid X-Object-Manifest header')
439 8cb45c13 Antony Chazapis
        except NameError:
440 8cb45c13 Antony Chazapis
            raise ItemNotFound('Container does not exist')
441 8cb45c13 Antony Chazapis
        
442 8cb45c13 Antony Chazapis
        try:
443 8cb45c13 Antony Chazapis
            for x in objects:
444 8cb45c13 Antony Chazapis
                s, h = backend.get_object_hashmap(request.user, v_account, src_container, x[0], x[1])
445 8cb45c13 Antony Chazapis
                sizes.append(s)
446 8cb45c13 Antony Chazapis
                hashmaps.append(h)
447 8cb45c13 Antony Chazapis
        except NameError:
448 8cb45c13 Antony Chazapis
            raise ItemNotFound('Object does not exist')
449 8cb45c13 Antony Chazapis
        except IndexError:
450 8cb45c13 Antony Chazapis
            raise ItemNotFound('Version does not exist')
451 8cb45c13 Antony Chazapis
    else:
452 8cb45c13 Antony Chazapis
        try:
453 8cb45c13 Antony Chazapis
            s, h = backend.get_object_hashmap(request.user, v_account, v_container, v_object, version)
454 8cb45c13 Antony Chazapis
            sizes.append(s)
455 8cb45c13 Antony Chazapis
            hashmaps.append(h)
456 8cb45c13 Antony Chazapis
        except NameError:
457 8cb45c13 Antony Chazapis
            raise ItemNotFound('Object does not exist')
458 8cb45c13 Antony Chazapis
        except IndexError:
459 8cb45c13 Antony Chazapis
            raise ItemNotFound('Version does not exist')
460 b956618e Antony Chazapis
    
461 22dab079 Antony Chazapis
    # Reply with the hashmap.
462 22dab079 Antony Chazapis
    if request.serialization != 'text':
463 8cb45c13 Antony Chazapis
        size = sum(sizes)
464 8cb45c13 Antony Chazapis
        hashmap = sum(hashmaps, [])
465 6bc372a4 Antony Chazapis
        d = {'block_size': backend.block_size, 'block_hash': backend.hash_algorithm, 'bytes': size, 'hashes': hashmap}
466 22dab079 Antony Chazapis
        if request.serialization == 'xml':
467 6bc372a4 Antony Chazapis
            d['object'] = v_object
468 6bc372a4 Antony Chazapis
            data = render_to_string('hashes.xml', d)
469 22dab079 Antony Chazapis
        elif request.serialization  == 'json':
470 6bc372a4 Antony Chazapis
            data = json.dumps(d)
471 22dab079 Antony Chazapis
        
472 22dab079 Antony Chazapis
        response = HttpResponse(data, status=200)
473 22dab079 Antony Chazapis
        put_object_meta(response, meta)
474 22dab079 Antony Chazapis
        response['Content-Length'] = len(data)
475 22dab079 Antony Chazapis
        return response
476 22dab079 Antony Chazapis
    
477 8cb45c13 Antony Chazapis
    return object_data_response(request, sizes, hashmaps, meta)
478 b956618e Antony Chazapis
479 b956618e Antony Chazapis
@api_method('PUT')
480 b956618e Antony Chazapis
def object_write(request, v_account, v_container, v_object):
481 b956618e Antony Chazapis
    # Normal Response Codes: 201
482 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
483 b956618e Antony Chazapis
    #                       unprocessableEntity (422),
484 b956618e Antony Chazapis
    #                       lengthRequired (411),
485 b956618e Antony Chazapis
    #                       itemNotFound (404),
486 b956618e Antony Chazapis
    #                       unauthorized (401),
487 b956618e Antony Chazapis
    #                       badRequest (400)
488 b956618e Antony Chazapis
    
489 b956618e Antony Chazapis
    copy_from = request.META.get('HTTP_X_COPY_FROM')
490 b956618e Antony Chazapis
    move_from = request.META.get('HTTP_X_MOVE_FROM')
491 b956618e Antony Chazapis
    if copy_from or move_from:
492 b956618e Antony Chazapis
        # TODO: Why is this required? Copy this ammount?
493 22dab079 Antony Chazapis
        content_length = get_content_length(request)
494 b956618e Antony Chazapis
        
495 b956618e Antony Chazapis
        if move_from:
496 83dd59c5 Antony Chazapis
            try:
497 83dd59c5 Antony Chazapis
                src_container, src_name = split_container_object_string(move_from)
498 83dd59c5 Antony Chazapis
            except ValueError:
499 83dd59c5 Antony Chazapis
                raise BadRequest('Invalid X-Move-From header')
500 83dd59c5 Antony Chazapis
            copy_or_move_object(request, v_account, src_container, src_name, v_container, v_object, move=True)
501 b956618e Antony Chazapis
        else:
502 83dd59c5 Antony Chazapis
            try:
503 83dd59c5 Antony Chazapis
                src_container, src_name = split_container_object_string(copy_from)
504 83dd59c5 Antony Chazapis
            except ValueError:
505 83dd59c5 Antony Chazapis
                raise BadRequest('Invalid X-Copy-From header')
506 83dd59c5 Antony Chazapis
            copy_or_move_object(request, v_account, src_container, src_name, v_container, v_object, move=False)
507 b956618e Antony Chazapis
        return HttpResponse(status=201)
508 b956618e Antony Chazapis
    
509 b956618e Antony Chazapis
    meta = get_object_meta(request)
510 b956618e Antony Chazapis
    content_length = -1
511 b956618e Antony Chazapis
    if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
512 22dab079 Antony Chazapis
        content_length = get_content_length(request)
513 b956618e Antony Chazapis
    # Should be BadRequest, but API says otherwise.
514 b956618e Antony Chazapis
    if 'Content-Type' not in meta:
515 b956618e Antony Chazapis
        raise LengthRequired('Missing Content-Type header')
516 b956618e Antony Chazapis
    
517 b956618e Antony Chazapis
    md5 = hashlib.md5()
518 58a6c894 Antony Chazapis
    size = 0
519 58a6c894 Antony Chazapis
    hashmap = []
520 58a6c894 Antony Chazapis
    sock = raw_input_socket(request)
521 58a6c894 Antony Chazapis
    for data in socket_read_iterator(sock, content_length, backend.block_size):
522 58a6c894 Antony Chazapis
        # TODO: Raise 408 (Request Timeout) if this takes too long.
523 58a6c894 Antony Chazapis
        # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
524 58a6c894 Antony Chazapis
        size += len(data)
525 58a6c894 Antony Chazapis
        hashmap.append(backend.put_block(data))
526 58a6c894 Antony Chazapis
        md5.update(data)
527 b956618e Antony Chazapis
    
528 b956618e Antony Chazapis
    meta['hash'] = md5.hexdigest().lower()
529 b956618e Antony Chazapis
    etag = request.META.get('HTTP_ETAG')
530 b956618e Antony Chazapis
    if etag and parse_etags(etag)[0].lower() != meta['hash']:
531 22dab079 Antony Chazapis
        raise UnprocessableEntity('Object ETag does not match')
532 22dab079 Antony Chazapis
    
533 22dab079 Antony Chazapis
    try:
534 83dd59c5 Antony Chazapis
        backend.update_object_hashmap(request.user, v_account, v_container, v_object, size, hashmap, meta, True)
535 22dab079 Antony Chazapis
    except NameError:
536 22dab079 Antony Chazapis
        raise ItemNotFound('Container does not exist')
537 b956618e Antony Chazapis
    
538 b956618e Antony Chazapis
    response = HttpResponse(status=201)
539 b956618e Antony Chazapis
    response['ETag'] = meta['hash']
540 b956618e Antony Chazapis
    return response
541 b956618e Antony Chazapis
542 b956618e Antony Chazapis
@api_method('COPY')
543 b956618e Antony Chazapis
def object_copy(request, v_account, v_container, v_object):
544 b956618e Antony Chazapis
    # Normal Response Codes: 201
545 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
546 b956618e Antony Chazapis
    #                       itemNotFound (404),
547 b956618e Antony Chazapis
    #                       unauthorized (401),
548 b956618e Antony Chazapis
    #                       badRequest (400)
549 b956618e Antony Chazapis
    
550 b956618e Antony Chazapis
    dest_path = request.META.get('HTTP_DESTINATION')
551 b956618e Antony Chazapis
    if not dest_path:
552 b956618e Antony Chazapis
        raise BadRequest('Missing Destination header')
553 83dd59c5 Antony Chazapis
    try:
554 83dd59c5 Antony Chazapis
        dest_container, dest_name = split_container_object_string(dest_path)
555 83dd59c5 Antony Chazapis
    except ValueError:
556 83dd59c5 Antony Chazapis
        raise BadRequest('Invalid Destination header')
557 83dd59c5 Antony Chazapis
    copy_or_move_object(request, v_account, v_container, v_object, dest_container, dest_name, move=False)
558 b956618e Antony Chazapis
    return HttpResponse(status=201)
559 b956618e Antony Chazapis
560 b956618e Antony Chazapis
@api_method('MOVE')
561 b956618e Antony Chazapis
def object_move(request, v_account, v_container, v_object):
562 b956618e Antony Chazapis
    # Normal Response Codes: 201
563 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
564 b956618e Antony Chazapis
    #                       itemNotFound (404),
565 b956618e Antony Chazapis
    #                       unauthorized (401),
566 b956618e Antony Chazapis
    #                       badRequest (400)
567 b956618e Antony Chazapis
    
568 b956618e Antony Chazapis
    dest_path = request.META.get('HTTP_DESTINATION')
569 b956618e Antony Chazapis
    if not dest_path:
570 b956618e Antony Chazapis
        raise BadRequest('Missing Destination header')
571 83dd59c5 Antony Chazapis
    try:
572 83dd59c5 Antony Chazapis
        dest_container, dest_name = split_container_object_string(dest_path)
573 83dd59c5 Antony Chazapis
    except ValueError:
574 83dd59c5 Antony Chazapis
        raise BadRequest('Invalid Destination header')
575 83dd59c5 Antony Chazapis
    copy_or_move_object(request, v_account, v_container, v_object, dest_container, dest_name, move=True)
576 b956618e Antony Chazapis
    return HttpResponse(status=201)
577 b956618e Antony Chazapis
578 b956618e Antony Chazapis
@api_method('POST')
579 b956618e Antony Chazapis
def object_update(request, v_account, v_container, v_object):
580 e9285524 Antony Chazapis
    # Normal Response Codes: 202, 204
581 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
582 b956618e Antony Chazapis
    #                       itemNotFound (404),
583 b956618e Antony Chazapis
    #                       unauthorized (401),
584 b956618e Antony Chazapis
    #                       badRequest (400)
585 b956618e Antony Chazapis
    
586 b956618e Antony Chazapis
    meta = get_object_meta(request)
587 22dab079 Antony Chazapis
    content_type = meta.get('Content-Type')
588 22dab079 Antony Chazapis
    if content_type:
589 b956618e Antony Chazapis
        del(meta['Content-Type']) # Do not allow changing the Content-Type.
590 22dab079 Antony Chazapis
    
591 cfe6939d Antony Chazapis
    try:
592 83dd59c5 Antony Chazapis
        prev_meta = backend.get_object_meta(request.user, v_account, v_container, v_object)
593 cfe6939d Antony Chazapis
    except NameError:
594 cfe6939d Antony Chazapis
        raise ItemNotFound('Object does not exist')
595 cfe6939d Antony Chazapis
    
596 cfe6939d Antony Chazapis
    # Handle metadata changes.
597 22dab079 Antony Chazapis
    if len(meta) != 0:
598 22dab079 Antony Chazapis
        # Keep previous values of 'Content-Type' and 'hash'.
599 22dab079 Antony Chazapis
        for k in ('Content-Type', 'hash'):
600 22dab079 Antony Chazapis
            if k in prev_meta:
601 22dab079 Antony Chazapis
                meta[k] = prev_meta[k]
602 22dab079 Antony Chazapis
        try:
603 83dd59c5 Antony Chazapis
            backend.update_object_meta(request.user, v_account, v_container, v_object, meta, replace=True)
604 22dab079 Antony Chazapis
        except NameError:
605 22dab079 Antony Chazapis
            raise ItemNotFound('Object does not exist')
606 22dab079 Antony Chazapis
    
607 cfe6939d Antony Chazapis
    # A Content-Type or Content-Range header may indicate data updates.
608 cfe6939d Antony Chazapis
    if content_type and content_type.startswith('multipart/byteranges'):
609 cfe6939d Antony Chazapis
        # TODO: Support multiple update ranges.
610 cfe6939d Antony Chazapis
        return HttpResponse(status=202)
611 cfe6939d Antony Chazapis
    # Single range update. Range must be in Content-Range.
612 22dab079 Antony Chazapis
    # Based on: http://code.google.com/p/gears/wiki/ContentRangePostProposal
613 cfe6939d Antony Chazapis
    # (with the addition that '*' is allowed for the range - will append).
614 cfe6939d Antony Chazapis
    if content_type and content_type != 'application/octet-stream':
615 cfe6939d Antony Chazapis
        return HttpResponse(status=202)
616 22dab079 Antony Chazapis
    content_range = request.META.get('HTTP_CONTENT_RANGE')
617 22dab079 Antony Chazapis
    if not content_range:
618 22dab079 Antony Chazapis
        return HttpResponse(status=202)
619 22dab079 Antony Chazapis
    ranges = get_content_range(request)
620 22dab079 Antony Chazapis
    if not ranges:
621 22dab079 Antony Chazapis
        return HttpResponse(status=202)
622 cfe6939d Antony Chazapis
    # Require either a Content-Length, or 'chunked' Transfer-Encoding.
623 cfe6939d Antony Chazapis
    content_length = -1
624 cfe6939d Antony Chazapis
    if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
625 cfe6939d Antony Chazapis
        content_length = get_content_length(request)
626 22dab079 Antony Chazapis
    
627 cfe6939d Antony Chazapis
    try:
628 83dd59c5 Antony Chazapis
        size, hashmap = backend.get_object_hashmap(request.user, v_account, v_container, v_object)
629 cfe6939d Antony Chazapis
    except NameError:
630 cfe6939d Antony Chazapis
        raise ItemNotFound('Object does not exist')
631 cfe6939d Antony Chazapis
    
632 cfe6939d Antony Chazapis
    offset, length, total = ranges
633 cfe6939d Antony Chazapis
    if offset is None:
634 cfe6939d Antony Chazapis
        offset = size
635 9a7f747a Sofia Papagiannaki
    if length is None or content_length == -1:
636 cfe6939d Antony Chazapis
        length = content_length # Nevermind the error.
637 cfe6939d Antony Chazapis
    elif length != content_length:
638 cfe6939d Antony Chazapis
        raise BadRequest('Content length does not match range length')
639 cfe6939d Antony Chazapis
    if total is not None and (total != size or offset >= size or (length > 0 and offset + length >= size)):
640 cfe6939d Antony Chazapis
        raise RangeNotSatisfiable('Supplied range will change provided object limits')
641 cfe6939d Antony Chazapis
    
642 cfe6939d Antony Chazapis
    sock = raw_input_socket(request)
643 cfe6939d Antony Chazapis
    data = ''
644 cfe6939d Antony Chazapis
    for d in socket_read_iterator(sock, length, backend.block_size):
645 cfe6939d Antony Chazapis
        # TODO: Raise 408 (Request Timeout) if this takes too long.
646 cfe6939d Antony Chazapis
        # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
647 cfe6939d Antony Chazapis
        data += d
648 cfe6939d Antony Chazapis
        bi = int(offset / backend.block_size)
649 cfe6939d Antony Chazapis
        bo = offset % backend.block_size
650 cfe6939d Antony Chazapis
        bl = min(len(data), backend.block_size - bo)
651 cfe6939d Antony Chazapis
        offset += bl
652 cfe6939d Antony Chazapis
        h = backend.update_block(hashmap[bi], data[:bl], bo)
653 cfe6939d Antony Chazapis
        if bi < len(hashmap):
654 cfe6939d Antony Chazapis
            hashmap[bi] = h
655 cfe6939d Antony Chazapis
        else:
656 cfe6939d Antony Chazapis
            hashmap.append(h)
657 cfe6939d Antony Chazapis
        data = data[bl:]
658 cfe6939d Antony Chazapis
    if len(data) > 0:
659 cfe6939d Antony Chazapis
        bi = int(offset / backend.block_size)
660 cfe6939d Antony Chazapis
        offset += len(data)
661 cfe6939d Antony Chazapis
        h = backend.update_block(hashmap[bi], data)
662 cfe6939d Antony Chazapis
        if bi < len(hashmap):
663 cfe6939d Antony Chazapis
            hashmap[bi] = h
664 cfe6939d Antony Chazapis
        else:
665 cfe6939d Antony Chazapis
            hashmap.append(h)
666 cfe6939d Antony Chazapis
    
667 cfe6939d Antony Chazapis
    if offset > size:
668 cfe6939d Antony Chazapis
        size = offset
669 83dd59c5 Antony Chazapis
    meta = {'hash': hashmap_hash(hashmap)} # Update ETag.
670 cfe6939d Antony Chazapis
    try:
671 83dd59c5 Antony Chazapis
        backend.update_object_hashmap(request.user, v_account, v_container, v_object, size, hashmap, meta, False)
672 cfe6939d Antony Chazapis
    except NameError:
673 cfe6939d Antony Chazapis
        raise ItemNotFound('Container does not exist')
674 83dd59c5 Antony Chazapis
        
675 e9285524 Antony Chazapis
    response = HttpResponse(status=204)
676 e9285524 Antony Chazapis
    response['ETag'] = meta['hash']
677 e9285524 Antony Chazapis
    return response
678 b956618e Antony Chazapis
679 b956618e Antony Chazapis
@api_method('DELETE')
680 b956618e Antony Chazapis
def object_delete(request, v_account, v_container, v_object):
681 b956618e Antony Chazapis
    # Normal Response Codes: 204
682 b956618e Antony Chazapis
    # Error Response Codes: serviceUnavailable (503),
683 b956618e Antony Chazapis
    #                       itemNotFound (404),
684 b956618e Antony Chazapis
    #                       unauthorized (401),
685 b956618e Antony Chazapis
    #                       badRequest (400)
686 b956618e Antony Chazapis
    
687 b956618e Antony Chazapis
    try:
688 83dd59c5 Antony Chazapis
        backend.delete_object(request.user, v_account, v_container, v_object)
689 b956618e Antony Chazapis
    except NameError:
690 b956618e Antony Chazapis
        raise ItemNotFound('Object does not exist')
691 b956618e Antony Chazapis
    return HttpResponse(status=204)
692 b956618e Antony Chazapis
693 b956618e Antony Chazapis
@api_method()
694 b956618e Antony Chazapis
def method_not_allowed(request):
695 b956618e Antony Chazapis
    raise BadRequest('Method not allowed')