Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (57.9 kB)

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