Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / functions.py @ 381a548c

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