Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / functions.py @ 0c6ab9df

History | View | Annotate | Download (59.7 kB)

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