Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / functions.py @ 65f480f5

History | View | Annotate | Download (58.6 kB)

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