Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (59.5 kB)

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