Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / functions.py @ 67100dd2

History | View | Annotate | Download (57.8 kB)

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