Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / functions.py @ 87835e94

History | View | Annotate | Download (58.8 kB)

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