Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / functions.py @ 3a5994a8

History | View | Annotate | Download (58.6 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 65bbcd43 Christos Stavrakakis
@api_method('POST', format_allowed=True, user_required=True, logger=logger)
512 b956618e Antony Chazapis
def container_update(request, v_account, v_container):
513 b956618e Antony Chazapis
    # Normal Response Codes: 202
514 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
515 b956618e Antony Chazapis
    #                       itemNotFound (404),
516 297513ba Antony Chazapis
    #                       forbidden (403),
517 b956618e Antony Chazapis
    #                       badRequest (400)
518 2715ade4 Sofia Papagiannaki
519 3ab38c43 Antony Chazapis
    meta, policy = get_container_headers(request)
520 a6eb13e9 Antony Chazapis
    replace = True
521 a6eb13e9 Antony Chazapis
    if 'update' in request.GET:
522 a6eb13e9 Antony Chazapis
        replace = False
523 3ab38c43 Antony Chazapis
    if policy:
524 3ab38c43 Antony Chazapis
        try:
525 2715ade4 Sofia Papagiannaki
            request.backend.update_container_policy(
526 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
527 2715ade4 Sofia Papagiannaki
                v_container, policy, replace)
528 3ab38c43 Antony Chazapis
        except NotAllowedError:
529 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
530 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
531 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Container does not exist')
532 3ab38c43 Antony Chazapis
        except ValueError:
533 bd40abfa Christos Stavrakakis
            raise faults.BadRequest('Invalid policy header')
534 77edd23d Antony Chazapis
    if meta or replace:
535 77edd23d Antony Chazapis
        try:
536 61efb530 Antony Chazapis
            request.backend.update_container_meta(request.user_uniq, v_account,
537 67100dd2 Ilias Tsitsimpis
                                                  v_container, 'pithos',
538 67100dd2 Ilias Tsitsimpis
                                                  meta, replace)
539 77edd23d Antony Chazapis
        except NotAllowedError:
540 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
541 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
542 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Container does not exist')
543 2715ade4 Sofia Papagiannaki
544 5144b772 Antony Chazapis
    content_length = -1
545 5144b772 Antony Chazapis
    if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
546 2715ade4 Sofia Papagiannaki
        content_length = get_int_parameter(
547 2715ade4 Sofia Papagiannaki
            request.META.get('CONTENT_LENGTH', 0))
548 bd08f5c0 Antony Chazapis
    content_type = request.META.get('CONTENT_TYPE')
549 5144b772 Antony Chazapis
    hashmap = []
550 67100dd2 Ilias Tsitsimpis
    if (content_type
551 67100dd2 Ilias Tsitsimpis
            and content_type == 'application/octet-stream'
552 67100dd2 Ilias Tsitsimpis
            and content_length != 0):
553 5144b772 Antony Chazapis
        for data in socket_read_iterator(request, content_length,
554 2715ade4 Sofia Papagiannaki
                                         request.backend.block_size):
555 5144b772 Antony Chazapis
            # TODO: Raise 408 (Request Timeout) if this takes too long.
556 67100dd2 Ilias Tsitsimpis
            # TODO: Raise 499 (Client Disconnect) if a length is defined
557 67100dd2 Ilias Tsitsimpis
            #       and we stop before getting this much data.
558 5144b772 Antony Chazapis
            hashmap.append(request.backend.put_block(data))
559 2715ade4 Sofia Papagiannaki
560 5144b772 Antony Chazapis
    response = HttpResponse(status=202)
561 5144b772 Antony Chazapis
    if hashmap:
562 af7bb62f Antony Chazapis
        response.content = simple_list_response(request, hashmap)
563 5144b772 Antony Chazapis
    return response
564 b956618e Antony Chazapis
565 2715ade4 Sofia Papagiannaki
566 65bbcd43 Christos Stavrakakis
@api_method('DELETE', user_required=True, logger=logger)
567 b956618e Antony Chazapis
def container_delete(request, v_account, v_container):
568 b956618e Antony Chazapis
    # Normal Response Codes: 204
569 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
570 b956618e Antony Chazapis
    #                       conflict (409),
571 b956618e Antony Chazapis
    #                       itemNotFound (404),
572 297513ba Antony Chazapis
    #                       forbidden (403),
573 b956618e Antony Chazapis
    #                       badRequest (400)
574 dfa2d4ba Sofia Papagiannaki
    #                       requestentitytoolarge (413)
575 2715ade4 Sofia Papagiannaki
576 bbd20b55 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
577 2715ade4 Sofia Papagiannaki
578 e46b2bcf Sofia Papagiannaki
    delimiter = request.GET.get('delimiter')
579 2715ade4 Sofia Papagiannaki
580 b956618e Antony Chazapis
    try:
581 2715ade4 Sofia Papagiannaki
        request.backend.delete_container(
582 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account, v_container,
583 2715ade4 Sofia Papagiannaki
            until, delimiter=delimiter)
584 cca6c617 Antony Chazapis
    except NotAllowedError:
585 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
586 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
587 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Container does not exist')
588 7efc9f86 Sofia Papagiannaki
    except ContainerNotEmpty:
589 bd40abfa Christos Stavrakakis
        raise faults.Conflict('Container is not empty')
590 dfa2d4ba Sofia Papagiannaki
    except QuotaError, e:
591 bd40abfa Christos Stavrakakis
        raise faults.RequestEntityTooLarge('Quota error: %s' % e)
592 b956618e Antony Chazapis
    return HttpResponse(status=204)
593 b956618e Antony Chazapis
594 2715ade4 Sofia Papagiannaki
595 6b560707 Sofia Papagiannaki
@api_method('GET', format_allowed=True, user_required=True, logger=logger,
596 ee565728 Kostas Papadimitriou
            serializations=["text", "xml", "json"])
597 b956618e Antony Chazapis
def object_list(request, v_account, v_container):
598 b956618e Antony Chazapis
    # Normal Response Codes: 200, 204
599 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
600 b956618e Antony Chazapis
    #                       itemNotFound (404),
601 297513ba Antony Chazapis
    #                       forbidden (403),
602 b956618e Antony Chazapis
    #                       badRequest (400)
603 2715ade4 Sofia Papagiannaki
604 1495b972 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
605 b956618e Antony Chazapis
    try:
606 61efb530 Antony Chazapis
        meta = request.backend.get_container_meta(request.user_uniq, v_account,
607 2715ade4 Sofia Papagiannaki
                                                  v_container, 'pithos', until)
608 67100dd2 Ilias Tsitsimpis
        meta['object_meta'] = \
609 67100dd2 Ilias Tsitsimpis
            request.backend.list_container_meta(request.user_uniq,
610 67100dd2 Ilias Tsitsimpis
                                                v_account, v_container,
611 67100dd2 Ilias Tsitsimpis
                                                'pithos', until)
612 2715ade4 Sofia Papagiannaki
        policy = request.backend.get_container_policy(
613 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account,
614 2715ade4 Sofia Papagiannaki
            v_container)
615 cca6c617 Antony Chazapis
    except NotAllowedError:
616 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
617 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
618 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Container does not exist')
619 2715ade4 Sofia Papagiannaki
620 b956618e Antony Chazapis
    validate_modification_preconditions(request, meta)
621 2715ade4 Sofia Papagiannaki
622 b956618e Antony Chazapis
    response = HttpResponse()
623 39593b2b Giorgos Verigakis
    put_container_headers(request, response, meta, policy)
624 2715ade4 Sofia Papagiannaki
625 b956618e Antony Chazapis
    path = request.GET.get('path')
626 b956618e Antony Chazapis
    prefix = request.GET.get('prefix')
627 b956618e Antony Chazapis
    delimiter = request.GET.get('delimiter')
628 2715ade4 Sofia Papagiannaki
629 b956618e Antony Chazapis
    # Path overrides prefix and delimiter.
630 b956618e Antony Chazapis
    virtual = True
631 b956618e Antony Chazapis
    if path:
632 b956618e Antony Chazapis
        prefix = path
633 b956618e Antony Chazapis
        delimiter = '/'
634 b956618e Antony Chazapis
        virtual = False
635 2715ade4 Sofia Papagiannaki
636 b956618e Antony Chazapis
    # Naming policy.
637 dcffd53e Antony Chazapis
    if prefix and delimiter and not prefix.endswith(delimiter):
638 b956618e Antony Chazapis
        prefix = prefix + delimiter
639 b956618e Antony Chazapis
    if not prefix:
640 b956618e Antony Chazapis
        prefix = ''
641 b956618e Antony Chazapis
    prefix = prefix.lstrip('/')
642 2715ade4 Sofia Papagiannaki
643 b956618e Antony Chazapis
    marker = request.GET.get('marker')
644 f6c97079 Antony Chazapis
    limit = get_int_parameter(request.GET.get('limit'))
645 f6c97079 Antony Chazapis
    if not limit:
646 3bdb9222 Sofia Papagiannaki
        limit = settings.API_LIST_LIMIT
647 2715ade4 Sofia Papagiannaki
648 22dab079 Antony Chazapis
    keys = request.GET.get('meta')
649 22dab079 Antony Chazapis
    if keys:
650 2715ade4 Sofia Papagiannaki
        keys = [smart_str(x.strip()) for x in keys.split(',')
651 2715ade4 Sofia Papagiannaki
                if x.strip() != '']
652 1713c946 Antony Chazapis
        included, excluded, opers = parse_filters(keys)
653 1713c946 Antony Chazapis
        keys = []
654 1713c946 Antony Chazapis
        keys += [format_header_key('X-Object-Meta-' + x) for x in included]
655 2715ade4 Sofia Papagiannaki
        keys += ['!' + format_header_key('X-Object-Meta-' + x)
656 2715ade4 Sofia Papagiannaki
                 for x in excluded]
657 2715ade4 Sofia Papagiannaki
        keys += ['%s%s%s' % (format_header_key(
658 2715ade4 Sofia Papagiannaki
            'X-Object-Meta-' + k), o, v) for k, o, v in opers]
659 22dab079 Antony Chazapis
    else:
660 22dab079 Antony Chazapis
        keys = []
661 2715ade4 Sofia Papagiannaki
662 b18ef3ad Antony Chazapis
    shared = False
663 b18ef3ad Antony Chazapis
    if 'shared' in request.GET:
664 b18ef3ad Antony Chazapis
        shared = True
665 8a0c7040 Georgios D. Tsoukalas
666 8a0c7040 Georgios D. Tsoukalas
    public_requested = 'public' in request.GET
667 8a0c7040 Georgios D. Tsoukalas
    public_granted = public_requested and request.user_uniq == v_account
668 2715ade4 Sofia Papagiannaki
669 c8860319 Sofia Papagiannaki
    if public_requested and not public_granted:
670 c8860319 Sofia Papagiannaki
        raise faults.Forbidden(
671 c8860319 Sofia Papagiannaki
            'PUblic object listing is not allowed to non path owners')
672 c8860319 Sofia Papagiannaki
673 b956618e Antony Chazapis
    if request.serialization == 'text':
674 371d907a Antony Chazapis
        try:
675 2715ade4 Sofia Papagiannaki
            objects = request.backend.list_objects(
676 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
677 2715ade4 Sofia Papagiannaki
                v_container, prefix, delimiter, marker,
678 2715ade4 Sofia Papagiannaki
                limit, virtual, 'pithos', keys, shared,
679 8a0c7040 Georgios D. Tsoukalas
                until, None, public_granted)
680 371d907a Antony Chazapis
        except NotAllowedError:
681 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
682 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
683 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Container does not exist')
684 2715ade4 Sofia Papagiannaki
685 b956618e Antony Chazapis
        if len(objects) == 0:
686 b956618e Antony Chazapis
            # The cloudfiles python bindings expect 200 if json/xml.
687 b956618e Antony Chazapis
            response.status_code = 204
688 b956618e Antony Chazapis
            return response
689 b956618e Antony Chazapis
        response.status_code = 200
690 83dd59c5 Antony Chazapis
        response.content = '\n'.join([x[0] for x in objects]) + '\n'
691 b956618e Antony Chazapis
        return response
692 dcffd53e Antony Chazapis
693 371d907a Antony Chazapis
    try:
694 2715ade4 Sofia Papagiannaki
        objects = request.backend.list_object_meta(
695 29148653 Sofia Papagiannaki
            request.user_uniq, v_account, v_container, prefix, delimiter,
696 29148653 Sofia Papagiannaki
            marker, limit, virtual, 'pithos', keys, shared, until, None,
697 29148653 Sofia Papagiannaki
            public_granted)
698 15a96c3e Antony Chazapis
        object_permissions = {}
699 15a96c3e Antony Chazapis
        object_public = {}
700 15a96c3e Antony Chazapis
        if until is None:
701 ddea3095 Sofia Papagiannaki
            name = '/'.join((v_account, v_container, ''))
702 ddea3095 Sofia Papagiannaki
            name_idx = len(name)
703 67100dd2 Ilias Tsitsimpis
            for x in request.backend.list_object_permissions(
704 67100dd2 Ilias Tsitsimpis
                    request.user_uniq, v_account, v_container, prefix):
705 ddea3095 Sofia Papagiannaki
706 ddea3095 Sofia Papagiannaki
                # filter out objects which are not under the container
707 ddea3095 Sofia Papagiannaki
                if name != x[:name_idx]:
708 ddea3095 Sofia Papagiannaki
                    continue
709 ddea3095 Sofia Papagiannaki
710 15a96c3e Antony Chazapis
                object = x[name_idx:]
711 67100dd2 Ilias Tsitsimpis
                object_permissions[object] = \
712 67100dd2 Ilias Tsitsimpis
                    request.backend.get_object_permissions(
713 67100dd2 Ilias Tsitsimpis
                        request.user_uniq, v_account, v_container, object)
714 8a0c7040 Georgios D. Tsoukalas
715 1a3eff62 Sofia Papagiannaki
            if request.user_uniq == v_account:
716 1a3eff62 Sofia Papagiannaki
                # Bring public information only if the request user
717 1a3eff62 Sofia Papagiannaki
                # is the object owner
718 8a0c7040 Georgios D. Tsoukalas
                for k, v in request.backend.list_object_public(
719 8a0c7040 Georgios D. Tsoukalas
                        request.user_uniq, v_account,
720 8a0c7040 Georgios D. Tsoukalas
                        v_container, prefix).iteritems():
721 8a0c7040 Georgios D. Tsoukalas
                    object_public[k[name_idx:]] = v
722 371d907a Antony Chazapis
    except NotAllowedError:
723 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
724 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
725 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Container does not exist')
726 2715ade4 Sofia Papagiannaki
727 b956618e Antony Chazapis
    object_meta = []
728 371d907a Antony Chazapis
    for meta in objects:
729 469d0997 Georgios D. Tsoukalas
        if TRANSLATE_UUIDS:
730 469d0997 Georgios D. Tsoukalas
            modified_by = meta.get('modified_by')
731 469d0997 Georgios D. Tsoukalas
            if modified_by:
732 469d0997 Georgios D. Tsoukalas
                l = retrieve_displaynames(
733 67100dd2 Ilias Tsitsimpis
                    getattr(request, 'token', None), [meta['modified_by']])
734 469d0997 Georgios D. Tsoukalas
                if l is not None and len(l) == 1:
735 469d0997 Georgios D. Tsoukalas
                    meta['modified_by'] = l[0]
736 469d0997 Georgios D. Tsoukalas
737 371d907a Antony Chazapis
        if len(meta) == 1:
738 b956618e Antony Chazapis
            # Virtual objects/directories.
739 371d907a Antony Chazapis
            object_meta.append(meta)
740 83dd59c5 Antony Chazapis
        else:
741 2715ade4 Sofia Papagiannaki
            rename_meta_key(
742 2715ade4 Sofia Papagiannaki
                meta, 'hash', 'x_object_hash')  # Will be replaced by checksum.
743 371d907a Antony Chazapis
            rename_meta_key(meta, 'checksum', 'hash')
744 371d907a Antony Chazapis
            rename_meta_key(meta, 'type', 'content_type')
745 371d907a Antony Chazapis
            rename_meta_key(meta, 'uuid', 'x_object_uuid')
746 371d907a Antony Chazapis
            if until is not None and 'modified' in meta:
747 371d907a Antony Chazapis
                del(meta['modified'])
748 038f1ae9 Antony Chazapis
            else:
749 804e8fe7 Antony Chazapis
                rename_meta_key(meta, 'modified', 'last_modified')
750 371d907a Antony Chazapis
            rename_meta_key(meta, 'modified_by', 'x_object_modified_by')
751 371d907a Antony Chazapis
            rename_meta_key(meta, 'version', 'x_object_version')
752 2715ade4 Sofia Papagiannaki
            rename_meta_key(
753 2715ade4 Sofia Papagiannaki
                meta, 'version_timestamp', 'x_object_version_timestamp')
754 15a96c3e Antony Chazapis
            permissions = object_permissions.get(meta['name'], None)
755 15a96c3e Antony Chazapis
            if permissions:
756 2715ade4 Sofia Papagiannaki
                update_sharing_meta(request, permissions, v_account,
757 2715ade4 Sofia Papagiannaki
                                    v_container, meta['name'], meta)
758 8a0c7040 Georgios D. Tsoukalas
            public_url = object_public.get(meta['name'], None)
759 1a3eff62 Sofia Papagiannaki
            if request.user_uniq == v_account:
760 1a3eff62 Sofia Papagiannaki
                # Return public information only if the request user
761 1a3eff62 Sofia Papagiannaki
                # is the object owner
762 8a0c7040 Georgios D. Tsoukalas
                update_public_meta(public_url, meta)
763 371d907a Antony Chazapis
            object_meta.append(printable_header_dict(meta))
764 469d0997 Georgios D. Tsoukalas
765 b956618e Antony Chazapis
    if request.serialization == 'xml':
766 2715ade4 Sofia Papagiannaki
        data = render_to_string(
767 2715ade4 Sofia Papagiannaki
            'objects.xml', {'container': v_container, 'objects': object_meta})
768 2715ade4 Sofia Papagiannaki
    elif request.serialization == 'json':
769 c48acbfd Sofia Papagiannaki
        data = json.dumps(object_meta, default=json_encode_decimal)
770 b956618e Antony Chazapis
    response.status_code = 200
771 b956618e Antony Chazapis
    response.content = data
772 b956618e Antony Chazapis
    return response
773 b956618e Antony Chazapis
774 2715ade4 Sofia Papagiannaki
775 65bbcd43 Christos Stavrakakis
@api_method('HEAD', user_required=True, logger=logger)
776 b956618e Antony Chazapis
def object_meta(request, v_account, v_container, v_object):
777 b956618e Antony Chazapis
    # Normal Response Codes: 204
778 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
779 b956618e Antony Chazapis
    #                       itemNotFound (404),
780 297513ba Antony Chazapis
    #                       forbidden (403),
781 b956618e Antony Chazapis
    #                       badRequest (400)
782 2715ade4 Sofia Papagiannaki
783 104626e3 Antony Chazapis
    version = request.GET.get('version')
784 b956618e Antony Chazapis
    try:
785 61efb530 Antony Chazapis
        meta = request.backend.get_object_meta(request.user_uniq, v_account,
786 67100dd2 Ilias Tsitsimpis
                                               v_container, v_object,
787 67100dd2 Ilias Tsitsimpis
                                               'pithos', version)
788 e8886082 Antony Chazapis
        if version is None:
789 2715ade4 Sofia Papagiannaki
            permissions = request.backend.get_object_permissions(
790 2715ade4 Sofia Papagiannaki
                request.user_uniq,
791 2715ade4 Sofia Papagiannaki
                v_account, v_container, v_object)
792 2715ade4 Sofia Papagiannaki
            public = request.backend.get_object_public(
793 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
794 2715ade4 Sofia Papagiannaki
                v_container, v_object)
795 e8886082 Antony Chazapis
        else:
796 e8886082 Antony Chazapis
            permissions = None
797 e0f916bb Antony Chazapis
            public = None
798 cca6c617 Antony Chazapis
    except NotAllowedError:
799 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
800 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
801 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Object does not exist')
802 7efc9f86 Sofia Papagiannaki
    except VersionNotExists:
803 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Version does not exist')
804 2715ade4 Sofia Papagiannaki
805 8cb45c13 Antony Chazapis
    update_manifest_meta(request, v_account, meta)
806 2715ade4 Sofia Papagiannaki
    update_sharing_meta(
807 2715ade4 Sofia Papagiannaki
        request, permissions, v_account, v_container, v_object, meta)
808 6fe32fb6 Sofia Papagiannaki
    if request.user_uniq == v_account:
809 6fe32fb6 Sofia Papagiannaki
        update_public_meta(public, meta)
810 2715ade4 Sofia Papagiannaki
811 a8326bef Antony Chazapis
    # Evaluate conditions.
812 a8326bef Antony Chazapis
    validate_modification_preconditions(request, meta)
813 a8326bef Antony Chazapis
    try:
814 a8326bef Antony Chazapis
        validate_matching_preconditions(request, meta)
815 bd40abfa Christos Stavrakakis
    except faults.NotModified:
816 a8326bef Antony Chazapis
        response = HttpResponse(status=304)
817 133e3fcf Sofia Papagiannaki
        response['ETag'] = meta['hash'] if not UPDATE_MD5 else meta['checksum']
818 a8326bef Antony Chazapis
        return response
819 2715ade4 Sofia Papagiannaki
820 cb146cf9 Antony Chazapis
    response = HttpResponse(status=200)
821 469d0997 Georgios D. Tsoukalas
    put_object_headers(response, meta, token=getattr(request, 'token', None))
822 b956618e Antony Chazapis
    return response
823 b956618e Antony Chazapis
824 2715ade4 Sofia Papagiannaki
825 65bbcd43 Christos Stavrakakis
@api_method('GET', format_allowed=True, user_required=True, logger=logger)
826 b956618e Antony Chazapis
def object_read(request, v_account, v_container, v_object):
827 63de12cf Sofia Papagiannaki
    return _object_read(request, v_account, v_container, v_object)
828 63de12cf Sofia Papagiannaki
829 63de12cf Sofia Papagiannaki
830 63de12cf Sofia Papagiannaki
def _object_read(request, v_account, v_container, v_object):
831 b956618e Antony Chazapis
    # Normal Response Codes: 200, 206
832 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
833 b956618e Antony Chazapis
    #                       rangeNotSatisfiable (416),
834 b956618e Antony Chazapis
    #                       preconditionFailed (412),
835 b956618e Antony Chazapis
    #                       itemNotFound (404),
836 297513ba Antony Chazapis
    #                       forbidden (403),
837 b956618e Antony Chazapis
    #                       badRequest (400),
838 b956618e Antony Chazapis
    #                       notModified (304)
839 2715ade4 Sofia Papagiannaki
840 104626e3 Antony Chazapis
    version = request.GET.get('version')
841 2715ade4 Sofia Papagiannaki
842 e8886082 Antony Chazapis
    # Reply with the version list. Do this first, as the object may be deleted.
843 104626e3 Antony Chazapis
    if version == 'list':
844 e8886082 Antony Chazapis
        if request.serialization == 'text':
845 bd40abfa Christos Stavrakakis
            raise faults.BadRequest('No format specified for version list.')
846 2715ade4 Sofia Papagiannaki
847 cca6c617 Antony Chazapis
        try:
848 61efb530 Antony Chazapis
            v = request.backend.list_versions(request.user_uniq, v_account,
849 2715ade4 Sofia Papagiannaki
                                              v_container, v_object)
850 cca6c617 Antony Chazapis
        except NotAllowedError:
851 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
852 02b8c298 Sofia Papagiannaki
        except ItemNotExists:
853 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Object does not exist')
854 cca6c617 Antony Chazapis
        d = {'versions': v}
855 e8886082 Antony Chazapis
        if request.serialization == 'xml':
856 e8886082 Antony Chazapis
            d['object'] = v_object
857 e8886082 Antony Chazapis
            data = render_to_string('versions.xml', d)
858 2715ade4 Sofia Papagiannaki
        elif request.serialization == 'json':
859 c48acbfd Sofia Papagiannaki
            data = json.dumps(d, default=json_encode_decimal)
860 2715ade4 Sofia Papagiannaki
861 e8886082 Antony Chazapis
        response = HttpResponse(data, status=200)
862 e8886082 Antony Chazapis
        response['Content-Length'] = len(data)
863 e8886082 Antony Chazapis
        return response
864 2715ade4 Sofia Papagiannaki
865 b956618e Antony Chazapis
    try:
866 61efb530 Antony Chazapis
        meta = request.backend.get_object_meta(request.user_uniq, v_account,
867 67100dd2 Ilias Tsitsimpis
                                               v_container, v_object,
868 67100dd2 Ilias Tsitsimpis
                                               'pithos', version)
869 e8886082 Antony Chazapis
        if version is None:
870 2715ade4 Sofia Papagiannaki
            permissions = request.backend.get_object_permissions(
871 2715ade4 Sofia Papagiannaki
                request.user_uniq,
872 2715ade4 Sofia Papagiannaki
                v_account, v_container, v_object)
873 2715ade4 Sofia Papagiannaki
            public = request.backend.get_object_public(
874 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
875 2715ade4 Sofia Papagiannaki
                v_container, v_object)
876 e8886082 Antony Chazapis
        else:
877 e8886082 Antony Chazapis
            permissions = None
878 e0f916bb Antony Chazapis
            public = None
879 cca6c617 Antony Chazapis
    except NotAllowedError:
880 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
881 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
882 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Object does not exist')
883 7efc9f86 Sofia Papagiannaki
    except VersionNotExists:
884 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Version does not exist')
885 2715ade4 Sofia Papagiannaki
886 8cb45c13 Antony Chazapis
    update_manifest_meta(request, v_account, meta)
887 2715ade4 Sofia Papagiannaki
    update_sharing_meta(
888 2715ade4 Sofia Papagiannaki
        request, permissions, v_account, v_container, v_object, meta)
889 6fe32fb6 Sofia Papagiannaki
    if request.user_uniq == v_account:
890 6fe32fb6 Sofia Papagiannaki
        update_public_meta(public, meta)
891 2715ade4 Sofia Papagiannaki
892 22dab079 Antony Chazapis
    # Evaluate conditions.
893 b956618e Antony Chazapis
    validate_modification_preconditions(request, meta)
894 22dab079 Antony Chazapis
    try:
895 22dab079 Antony Chazapis
        validate_matching_preconditions(request, meta)
896 bd40abfa Christos Stavrakakis
    except faults.NotModified:
897 22dab079 Antony Chazapis
        response = HttpResponse(status=304)
898 133e3fcf Sofia Papagiannaki
        response['ETag'] = meta['hash'] if not UPDATE_MD5 else meta['checksum']
899 22dab079 Antony Chazapis
        return response
900 2715ade4 Sofia Papagiannaki
901 2fd10ff4 Antony Chazapis
    hashmap_reply = False
902 2fd10ff4 Antony Chazapis
    if 'hashmap' in request.GET and request.serialization != 'text':
903 2fd10ff4 Antony Chazapis
        hashmap_reply = True
904 2715ade4 Sofia Papagiannaki
905 8cb45c13 Antony Chazapis
    sizes = []
906 8cb45c13 Antony Chazapis
    hashmaps = []
907 2fd10ff4 Antony Chazapis
    if 'X-Object-Manifest' in meta and not hashmap_reply:
908 8cb45c13 Antony Chazapis
        try:
909 2715ade4 Sofia Papagiannaki
            src_container, src_name = split_container_object_string(
910 2715ade4 Sofia Papagiannaki
                '/' + meta['X-Object-Manifest'])
911 2715ade4 Sofia Papagiannaki
            objects = request.backend.list_objects(
912 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
913 2715ade4 Sofia Papagiannaki
                src_container, prefix=src_name, virtual=False)
914 cca6c617 Antony Chazapis
        except NotAllowedError:
915 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
916 8cb45c13 Antony Chazapis
        except ValueError:
917 bd40abfa Christos Stavrakakis
            raise faults.BadRequest('Invalid X-Object-Manifest header')
918 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
919 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Container does not exist')
920 2715ade4 Sofia Papagiannaki
921 8cb45c13 Antony Chazapis
        try:
922 8cb45c13 Antony Chazapis
            for x in objects:
923 67100dd2 Ilias Tsitsimpis
                s, h = \
924 29148653 Sofia Papagiannaki
                    request.backend.get_object_hashmap(
925 29148653 Sofia Papagiannaki
                        request.user_uniq, v_account, src_container, x[0],
926 29148653 Sofia Papagiannaki
                        x[1])
927 8cb45c13 Antony Chazapis
                sizes.append(s)
928 8cb45c13 Antony Chazapis
                hashmaps.append(h)
929 cca6c617 Antony Chazapis
        except NotAllowedError:
930 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
931 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
932 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Object does not exist')
933 7efc9f86 Sofia Papagiannaki
        except VersionNotExists:
934 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Version does not exist')
935 8cb45c13 Antony Chazapis
    else:
936 8cb45c13 Antony Chazapis
        try:
937 2715ade4 Sofia Papagiannaki
            s, h = request.backend.get_object_hashmap(
938 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
939 2715ade4 Sofia Papagiannaki
                v_container, v_object, version)
940 8cb45c13 Antony Chazapis
            sizes.append(s)
941 8cb45c13 Antony Chazapis
            hashmaps.append(h)
942 cca6c617 Antony Chazapis
        except NotAllowedError:
943 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
944 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
945 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Object does not exist')
946 7efc9f86 Sofia Papagiannaki
        except VersionNotExists:
947 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Version does not exist')
948 2715ade4 Sofia Papagiannaki
949 22dab079 Antony Chazapis
    # Reply with the hashmap.
950 2fd10ff4 Antony Chazapis
    if hashmap_reply:
951 8cb45c13 Antony Chazapis
        size = sum(sizes)
952 8cb45c13 Antony Chazapis
        hashmap = sum(hashmaps, [])
953 39593b2b Giorgos Verigakis
        d = {
954 39593b2b Giorgos Verigakis
            'block_size': request.backend.block_size,
955 39593b2b Giorgos Verigakis
            'block_hash': request.backend.hash_algorithm,
956 39593b2b Giorgos Verigakis
            'bytes': size,
957 39593b2b Giorgos Verigakis
            'hashes': hashmap}
958 22dab079 Antony Chazapis
        if request.serialization == 'xml':
959 6bc372a4 Antony Chazapis
            d['object'] = v_object
960 6bc372a4 Antony Chazapis
            data = render_to_string('hashes.xml', d)
961 2715ade4 Sofia Papagiannaki
        elif request.serialization == 'json':
962 6bc372a4 Antony Chazapis
            data = json.dumps(d)
963 2715ade4 Sofia Papagiannaki
964 22dab079 Antony Chazapis
        response = HttpResponse(data, status=200)
965 469d0997 Georgios D. Tsoukalas
        put_object_headers(
966 67100dd2 Ilias Tsitsimpis
            response, meta, token=getattr(request, 'token', None))
967 22dab079 Antony Chazapis
        response['Content-Length'] = len(data)
968 22dab079 Antony Chazapis
        return response
969 2715ade4 Sofia Papagiannaki
970 2715ade4 Sofia Papagiannaki
    request.serialization = 'text'  # Unset.
971 8cb45c13 Antony Chazapis
    return object_data_response(request, sizes, hashmaps, meta)
972 b956618e Antony Chazapis
973 2715ade4 Sofia Papagiannaki
974 b90584d0 Sofia Papagiannaki
@api_method('PUT', format_allowed=True, user_required=True, logger=logger,
975 b90584d0 Sofia Papagiannaki
            lock_container_path=True)
976 b956618e Antony Chazapis
def object_write(request, v_account, v_container, v_object):
977 b956618e Antony Chazapis
    # Normal Response Codes: 201
978 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
979 b956618e Antony Chazapis
    #                       unprocessableEntity (422),
980 b956618e Antony Chazapis
    #                       lengthRequired (411),
981 3436eeb0 Antony Chazapis
    #                       conflict (409),
982 b956618e Antony Chazapis
    #                       itemNotFound (404),
983 297513ba Antony Chazapis
    #                       forbidden (403),
984 b956618e Antony Chazapis
    #                       badRequest (400)
985 dfa2d4ba Sofia Papagiannaki
    #                       requestentitytoolarge (413)
986 2715ade4 Sofia Papagiannaki
987 a8326bef Antony Chazapis
    # Evaluate conditions.
988 67100dd2 Ilias Tsitsimpis
    if (request.META.get('HTTP_IF_MATCH')
989 67100dd2 Ilias Tsitsimpis
            or request.META.get('HTTP_IF_NONE_MATCH')):
990 a8326bef Antony Chazapis
        try:
991 2715ade4 Sofia Papagiannaki
            meta = request.backend.get_object_meta(
992 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
993 2715ade4 Sofia Papagiannaki
                v_container, v_object, 'pithos')
994 a8326bef Antony Chazapis
        except NotAllowedError:
995 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
996 a8326bef Antony Chazapis
        except NameError:
997 a8326bef Antony Chazapis
            meta = {}
998 a8326bef Antony Chazapis
        validate_matching_preconditions(request, meta)
999 2715ade4 Sofia Papagiannaki
1000 88283e9e Antony Chazapis
    copy_from = request.META.get('HTTP_X_COPY_FROM')
1001 88283e9e Antony Chazapis
    move_from = request.META.get('HTTP_X_MOVE_FROM')
1002 b956618e Antony Chazapis
    if copy_from or move_from:
1003 4d15c94e Sofia Papagiannaki
        delimiter = request.GET.get('delimiter')
1004 2715ade4 Sofia Papagiannaki
        content_length = get_content_length(request)  # Required by the API.
1005 2715ade4 Sofia Papagiannaki
1006 88283e9e Antony Chazapis
        src_account = request.META.get('HTTP_X_SOURCE_ACCOUNT')
1007 f483f65d Sofia Papagiannaki
1008 79bb41b7 Antony Chazapis
        if not src_account:
1009 61efb530 Antony Chazapis
            src_account = request.user_uniq
1010 f483f65d Sofia Papagiannaki
        else:
1011 f483f65d Sofia Papagiannaki
            if TRANSLATE_UUIDS:
1012 f483f65d Sofia Papagiannaki
                try:
1013 29148653 Sofia Papagiannaki
                    src_account = retrieve_uuid(
1014 29148653 Sofia Papagiannaki
                        getattr(request, 'token', None), src_account)
1015 f483f65d Sofia Papagiannaki
                except ItemNotExists:
1016 bd40abfa Christos Stavrakakis
                    faults.ItemNotFound('Invalid source account')
1017 f483f65d Sofia Papagiannaki
1018 b956618e Antony Chazapis
        if move_from:
1019 83dd59c5 Antony Chazapis
            try:
1020 2715ade4 Sofia Papagiannaki
                src_container, src_name = split_container_object_string(
1021 2715ade4 Sofia Papagiannaki
                    move_from)
1022 83dd59c5 Antony Chazapis
            except ValueError:
1023 bd40abfa Christos Stavrakakis
                raise faults.BadRequest('Invalid X-Move-From header')
1024 2715ade4 Sofia Papagiannaki
            version_id = copy_or_move_object(
1025 2715ade4 Sofia Papagiannaki
                request, src_account, src_container, src_name,
1026 67100dd2 Ilias Tsitsimpis
                v_account, v_container, v_object,
1027 67100dd2 Ilias Tsitsimpis
                move=True, delimiter=delimiter)
1028 b956618e Antony Chazapis
        else:
1029 83dd59c5 Antony Chazapis
            try:
1030 2715ade4 Sofia Papagiannaki
                src_container, src_name = split_container_object_string(
1031 2715ade4 Sofia Papagiannaki
                    copy_from)
1032 83dd59c5 Antony Chazapis
            except ValueError:
1033 bd40abfa Christos Stavrakakis
                raise faults.BadRequest('Invalid X-Copy-From header')
1034 2715ade4 Sofia Papagiannaki
            version_id = copy_or_move_object(
1035 2715ade4 Sofia Papagiannaki
                request, src_account, src_container, src_name,
1036 67100dd2 Ilias Tsitsimpis
                v_account, v_container, v_object,
1037 67100dd2 Ilias Tsitsimpis
                move=False, delimiter=delimiter)
1038 7dd293a0 Antony Chazapis
        response = HttpResponse(status=201)
1039 7dd293a0 Antony Chazapis
        response['X-Object-Version'] = version_id
1040 7dd293a0 Antony Chazapis
        return response
1041 2715ade4 Sofia Papagiannaki
1042 66ce2ca5 Antony Chazapis
    content_type, meta, permissions, public = get_object_headers(request)
1043 b956618e Antony Chazapis
    content_length = -1
1044 b956618e Antony Chazapis
    if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
1045 22dab079 Antony Chazapis
        content_length = get_content_length(request)
1046 b956618e Antony Chazapis
    # Should be BadRequest, but API says otherwise.
1047 dcffd53e Antony Chazapis
    if content_type is None:
1048 bd40abfa Christos Stavrakakis
        raise faults.LengthRequired('Missing Content-Type header')
1049 2715ade4 Sofia Papagiannaki
1050 f9f15f92 Antony Chazapis
    if 'hashmap' in request.GET:
1051 f9f15f92 Antony Chazapis
        if request.serialization not in ('json', 'xml'):
1052 bd40abfa Christos Stavrakakis
            raise faults.BadRequest('Invalid hashmap format')
1053 2715ade4 Sofia Papagiannaki
1054 76985443 Sofia Papagiannaki
        data = ''
1055 39593b2b Giorgos Verigakis
        for block in socket_read_iterator(request, content_length,
1056 2715ade4 Sofia Papagiannaki
                                          request.backend.block_size):
1057 76985443 Sofia Papagiannaki
            data = '%s%s' % (data, block)
1058 2715ade4 Sofia Papagiannaki
1059 32a437b1 Sofia Papagiannaki
        if request.serialization == 'json':
1060 32a437b1 Sofia Papagiannaki
            d = json.loads(data)
1061 32a437b1 Sofia Papagiannaki
            if not hasattr(d, '__getitem__'):
1062 bd40abfa Christos Stavrakakis
                raise faults.BadRequest('Invalid data formating')
1063 32a437b1 Sofia Papagiannaki
            try:
1064 32a437b1 Sofia Papagiannaki
                hashmap = d['hashes']
1065 f899c7b4 Antony Chazapis
                size = int(d['bytes'])
1066 f899c7b4 Antony Chazapis
            except:
1067 bd40abfa Christos Stavrakakis
                raise faults.BadRequest('Invalid data formatting')
1068 32a437b1 Sofia Papagiannaki
        elif request.serialization == 'xml':
1069 32a437b1 Sofia Papagiannaki
            try:
1070 32a437b1 Sofia Papagiannaki
                xml = minidom.parseString(data)
1071 32a437b1 Sofia Papagiannaki
                obj = xml.getElementsByTagName('object')[0]
1072 f899c7b4 Antony Chazapis
                size = int(obj.attributes['bytes'].value)
1073 2715ade4 Sofia Papagiannaki
1074 32a437b1 Sofia Papagiannaki
                hashes = xml.getElementsByTagName('hash')
1075 32a437b1 Sofia Papagiannaki
                hashmap = []
1076 32a437b1 Sofia Papagiannaki
                for hash in hashes:
1077 32a437b1 Sofia Papagiannaki
                    hashmap.append(hash.firstChild.data)
1078 f899c7b4 Antony Chazapis
            except:
1079 bd40abfa Christos Stavrakakis
                raise faults.BadRequest('Invalid data formatting')
1080 2715ade4 Sofia Papagiannaki
1081 2715ade4 Sofia Papagiannaki
        checksum = ''  # Do not set to None (will copy previous value).
1082 76985443 Sofia Papagiannaki
    else:
1083 133e3fcf Sofia Papagiannaki
        etag = request.META.get('HTTP_ETAG')
1084 133e3fcf Sofia Papagiannaki
        checksum_compute = Checksum() if etag or UPDATE_MD5 else NoChecksum()
1085 76985443 Sofia Papagiannaki
        size = 0
1086 76985443 Sofia Papagiannaki
        hashmap = []
1087 39593b2b Giorgos Verigakis
        for data in socket_read_iterator(request, content_length,
1088 2715ade4 Sofia Papagiannaki
                                         request.backend.block_size):
1089 76985443 Sofia Papagiannaki
            # TODO: Raise 408 (Request Timeout) if this takes too long.
1090 67100dd2 Ilias Tsitsimpis
            # TODO: Raise 499 (Client Disconnect) if a length is defined
1091 67100dd2 Ilias Tsitsimpis
            #       and we stop before getting this much data.
1092 76985443 Sofia Papagiannaki
            size += len(data)
1093 39593b2b Giorgos Verigakis
            hashmap.append(request.backend.put_block(data))
1094 133e3fcf Sofia Papagiannaki
            checksum_compute.update(data)
1095 2715ade4 Sofia Papagiannaki
1096 133e3fcf Sofia Papagiannaki
        checksum = checksum_compute.hexdigest()
1097 33b4e4a6 Antony Chazapis
        if etag and parse_etags(etag)[0].lower() != checksum:
1098 bd40abfa Christos Stavrakakis
            raise faults.UnprocessableEntity('Object ETag does not match')
1099 2715ade4 Sofia Papagiannaki
1100 22dab079 Antony Chazapis
    try:
1101 133e3fcf Sofia Papagiannaki
        version_id, merkle = request.backend.update_object_hashmap(
1102 133e3fcf Sofia Papagiannaki
            request.user_uniq, v_account, v_container, v_object, size,
1103 133e3fcf Sofia Papagiannaki
            content_type, hashmap, checksum, 'pithos', meta, True, permissions
1104 133e3fcf Sofia Papagiannaki
        )
1105 cca6c617 Antony Chazapis
    except NotAllowedError:
1106 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
1107 76985443 Sofia Papagiannaki
    except IndexError, e:
1108 e9d94604 Sofia Papagiannaki
        missing_blocks = e.data
1109 e9d94604 Sofia Papagiannaki
        response = HttpResponse(status=409)
1110 e9d94604 Sofia Papagiannaki
        response.content = simple_list_response(request, missing_blocks)
1111 e9d94604 Sofia Papagiannaki
        return response
1112 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1113 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Container does not exist')
1114 3436eeb0 Antony Chazapis
    except ValueError:
1115 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Invalid sharing header')
1116 ccfd4e44 Sofia Papagiannaki
    except QuotaError, e:
1117 bd40abfa Christos Stavrakakis
        raise faults.RequestEntityTooLarge('Quota error: %s' % e)
1118 3a5994a8 Sofia Papagiannaki
    except InvalidHash, e:
1119 3a5994a8 Sofia Papagiannaki
        raise faults.BadRequest('Invalid hash: %s' % e)
1120 8efd183f Antony Chazapis
    if not checksum and UPDATE_MD5:
1121 cddcf432 chazapis
        # Update the MD5 after the hashmap, as there may be missing hashes.
1122 b3155065 Antony Chazapis
        checksum = hashmap_md5(request.backend, hashmap, size)
1123 cddcf432 chazapis
        try:
1124 b3155065 Antony Chazapis
            request.backend.update_object_checksum(request.user_uniq,
1125 67100dd2 Ilias Tsitsimpis
                                                   v_account, v_container,
1126 67100dd2 Ilias Tsitsimpis
                                                   v_object, version_id,
1127 67100dd2 Ilias Tsitsimpis
                                                   checksum)
1128 cddcf432 chazapis
        except NotAllowedError:
1129 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
1130 e0f916bb Antony Chazapis
    if public is not None:
1131 e0f916bb Antony Chazapis
        try:
1132 61efb530 Antony Chazapis
            request.backend.update_object_public(request.user_uniq, v_account,
1133 2715ade4 Sofia Papagiannaki
                                                 v_container, v_object, public)
1134 e0f916bb Antony Chazapis
        except NotAllowedError:
1135 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
1136 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
1137 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Object does not exist')
1138 2715ade4 Sofia Papagiannaki
1139 1993fea9 Antony Chazapis
    response = HttpResponse(status=201)
1140 133e3fcf Sofia Papagiannaki
    response['ETag'] = merkle if not UPDATE_MD5 else checksum
1141 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1142 b956618e Antony Chazapis
    return response
1143 b956618e Antony Chazapis
1144 2715ade4 Sofia Papagiannaki
1145 29148653 Sofia Papagiannaki
@api_method('POST', user_required=True, logger=logger,
1146 29148653 Sofia Papagiannaki
            lock_container_path=True)
1147 1d5c57d3 Antony Chazapis
def object_write_form(request, v_account, v_container, v_object):
1148 1d5c57d3 Antony Chazapis
    # Normal Response Codes: 201
1149 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1150 1d5c57d3 Antony Chazapis
    #                       itemNotFound (404),
1151 297513ba Antony Chazapis
    #                       forbidden (403),
1152 1d5c57d3 Antony Chazapis
    #                       badRequest (400)
1153 dfa2d4ba Sofia Papagiannaki
    #                       requestentitytoolarge (413)
1154 2715ade4 Sofia Papagiannaki
1155 817890f2 Antony Chazapis
    request.upload_handlers = [SaveToBackendHandler(request)]
1156 2715ade4 Sofia Papagiannaki
    if 'X-Object-Data' not in request.FILES:
1157 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Missing X-Object-Data field')
1158 1d5c57d3 Antony Chazapis
    file = request.FILES['X-Object-Data']
1159 2715ade4 Sofia Papagiannaki
1160 33b4e4a6 Antony Chazapis
    checksum = file.etag
1161 1d5c57d3 Antony Chazapis
    try:
1162 133e3fcf Sofia Papagiannaki
        version_id, merkle = request.backend.update_object_hashmap(
1163 133e3fcf Sofia Papagiannaki
            request.user_uniq, v_account, v_container, v_object, file.size,
1164 133e3fcf Sofia Papagiannaki
            file.content_type, file.hashmap, checksum, 'pithos', {}, True
1165 133e3fcf Sofia Papagiannaki
        )
1166 1d5c57d3 Antony Chazapis
    except NotAllowedError:
1167 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
1168 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1169 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Container does not exist')
1170 ccfd4e44 Sofia Papagiannaki
    except QuotaError, e:
1171 bd40abfa Christos Stavrakakis
        raise faults.RequestEntityTooLarge('Quota error: %s' % e)
1172 2715ade4 Sofia Papagiannaki
1173 1d5c57d3 Antony Chazapis
    response = HttpResponse(status=201)
1174 133e3fcf Sofia Papagiannaki
    response['ETag'] = merkle if not UPDATE_MD5 else checksum
1175 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1176 33b4e4a6 Antony Chazapis
    response.content = checksum
1177 1d5c57d3 Antony Chazapis
    return response
1178 1d5c57d3 Antony Chazapis
1179 2715ade4 Sofia Papagiannaki
1180 b90584d0 Sofia Papagiannaki
@api_method('COPY', format_allowed=True, user_required=True, logger=logger,
1181 b90584d0 Sofia Papagiannaki
            lock_container_path=True)
1182 b956618e Antony Chazapis
def object_copy(request, v_account, v_container, v_object):
1183 b956618e Antony Chazapis
    # Normal Response Codes: 201
1184 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1185 b956618e Antony Chazapis
    #                       itemNotFound (404),
1186 297513ba Antony Chazapis
    #                       forbidden (403),
1187 b956618e Antony Chazapis
    #                       badRequest (400)
1188 dfa2d4ba Sofia Papagiannaki
    #                       requestentitytoolarge (413)
1189 2715ade4 Sofia Papagiannaki
1190 88283e9e Antony Chazapis
    dest_account = request.META.get('HTTP_DESTINATION_ACCOUNT')
1191 79bb41b7 Antony Chazapis
    if not dest_account:
1192 61efb530 Antony Chazapis
        dest_account = request.user_uniq
1193 88283e9e Antony Chazapis
    dest_path = request.META.get('HTTP_DESTINATION')
1194 b956618e Antony Chazapis
    if not dest_path:
1195 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Missing Destination header')
1196 83dd59c5 Antony Chazapis
    try:
1197 83dd59c5 Antony Chazapis
        dest_container, dest_name = split_container_object_string(dest_path)
1198 83dd59c5 Antony Chazapis
    except ValueError:
1199 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Invalid Destination header')
1200 2715ade4 Sofia Papagiannaki
1201 a8326bef Antony Chazapis
    # Evaluate conditions.
1202 67100dd2 Ilias Tsitsimpis
    if (request.META.get('HTTP_IF_MATCH')
1203 67100dd2 Ilias Tsitsimpis
            or request.META.get('HTTP_IF_NONE_MATCH')):
1204 a8326bef Antony Chazapis
        src_version = request.META.get('HTTP_X_SOURCE_VERSION')
1205 a8326bef Antony Chazapis
        try:
1206 2715ade4 Sofia Papagiannaki
            meta = request.backend.get_object_meta(
1207 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
1208 2715ade4 Sofia Papagiannaki
                v_container, v_object, 'pithos', src_version)
1209 a8326bef Antony Chazapis
        except NotAllowedError:
1210 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
1211 7efc9f86 Sofia Papagiannaki
        except (ItemNotExists, VersionNotExists):
1212 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Container or object does not exist')
1213 a8326bef Antony Chazapis
        validate_matching_preconditions(request, meta)
1214 2715ade4 Sofia Papagiannaki
1215 4d15c94e Sofia Papagiannaki
    delimiter = request.GET.get('delimiter')
1216 2715ade4 Sofia Papagiannaki
1217 79bb41b7 Antony Chazapis
    version_id = copy_or_move_object(request, v_account, v_container, v_object,
1218 67100dd2 Ilias Tsitsimpis
                                     dest_account, dest_container, dest_name,
1219 67100dd2 Ilias Tsitsimpis
                                     move=False, delimiter=delimiter)
1220 7dd293a0 Antony Chazapis
    response = HttpResponse(status=201)
1221 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1222 7dd293a0 Antony Chazapis
    return response
1223 b956618e Antony Chazapis
1224 2715ade4 Sofia Papagiannaki
1225 b90584d0 Sofia Papagiannaki
@api_method('MOVE', format_allowed=True, user_required=True, logger=logger,
1226 b90584d0 Sofia Papagiannaki
            lock_container_path=True)
1227 b956618e Antony Chazapis
def object_move(request, v_account, v_container, v_object):
1228 b956618e Antony Chazapis
    # Normal Response Codes: 201
1229 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1230 b956618e Antony Chazapis
    #                       itemNotFound (404),
1231 297513ba Antony Chazapis
    #                       forbidden (403),
1232 b956618e Antony Chazapis
    #                       badRequest (400)
1233 dfa2d4ba Sofia Papagiannaki
    #                       requestentitytoolarge (413)
1234 2715ade4 Sofia Papagiannaki
1235 88283e9e Antony Chazapis
    dest_account = request.META.get('HTTP_DESTINATION_ACCOUNT')
1236 79bb41b7 Antony Chazapis
    if not dest_account:
1237 61efb530 Antony Chazapis
        dest_account = request.user_uniq
1238 88283e9e Antony Chazapis
    dest_path = request.META.get('HTTP_DESTINATION')
1239 b956618e Antony Chazapis
    if not dest_path:
1240 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Missing Destination header')
1241 83dd59c5 Antony Chazapis
    try:
1242 83dd59c5 Antony Chazapis
        dest_container, dest_name = split_container_object_string(dest_path)
1243 83dd59c5 Antony Chazapis
    except ValueError:
1244 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Invalid Destination header')
1245 2715ade4 Sofia Papagiannaki
1246 a8326bef Antony Chazapis
    # Evaluate conditions.
1247 67100dd2 Ilias Tsitsimpis
    if (request.META.get('HTTP_IF_MATCH')
1248 67100dd2 Ilias Tsitsimpis
            or request.META.get('HTTP_IF_NONE_MATCH')):
1249 a8326bef Antony Chazapis
        try:
1250 2715ade4 Sofia Papagiannaki
            meta = request.backend.get_object_meta(
1251 2715ade4 Sofia Papagiannaki
                request.user_uniq, v_account,
1252 2715ade4 Sofia Papagiannaki
                v_container, v_object, 'pithos')
1253 a8326bef Antony Chazapis
        except NotAllowedError:
1254 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
1255 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
1256 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Container or object does not exist')
1257 a8326bef Antony Chazapis
        validate_matching_preconditions(request, meta)
1258 2715ade4 Sofia Papagiannaki
1259 4d15c94e Sofia Papagiannaki
    delimiter = request.GET.get('delimiter')
1260 2715ade4 Sofia Papagiannaki
1261 79bb41b7 Antony Chazapis
    version_id = copy_or_move_object(request, v_account, v_container, v_object,
1262 67100dd2 Ilias Tsitsimpis
                                     dest_account, dest_container, dest_name,
1263 67100dd2 Ilias Tsitsimpis
                                     move=True, delimiter=delimiter)
1264 7dd293a0 Antony Chazapis
    response = HttpResponse(status=201)
1265 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1266 7dd293a0 Antony Chazapis
    return response
1267 b956618e Antony Chazapis
1268 2715ade4 Sofia Papagiannaki
1269 b90584d0 Sofia Papagiannaki
@api_method('POST', format_allowed=True, user_required=True, logger=logger,
1270 b90584d0 Sofia Papagiannaki
            lock_container_path=True)
1271 b956618e Antony Chazapis
def object_update(request, v_account, v_container, v_object):
1272 e9285524 Antony Chazapis
    # Normal Response Codes: 202, 204
1273 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1274 3436eeb0 Antony Chazapis
    #                       conflict (409),
1275 b956618e Antony Chazapis
    #                       itemNotFound (404),
1276 297513ba Antony Chazapis
    #                       forbidden (403),
1277 b956618e Antony Chazapis
    #                       badRequest (400)
1278 2715ade4 Sofia Papagiannaki
1279 66ce2ca5 Antony Chazapis
    content_type, meta, permissions, public = get_object_headers(request)
1280 2715ade4 Sofia Papagiannaki
1281 cfe6939d Antony Chazapis
    try:
1282 2715ade4 Sofia Papagiannaki
        prev_meta = request.backend.get_object_meta(
1283 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account,
1284 2715ade4 Sofia Papagiannaki
            v_container, v_object, 'pithos')
1285 cca6c617 Antony Chazapis
    except NotAllowedError:
1286 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
1287 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1288 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Object does not exist')
1289 2715ade4 Sofia Papagiannaki
1290 a8326bef Antony Chazapis
    # Evaluate conditions.
1291 67100dd2 Ilias Tsitsimpis
    if (request.META.get('HTTP_IF_MATCH')
1292 67100dd2 Ilias Tsitsimpis
            or request.META.get('HTTP_IF_NONE_MATCH')):
1293 a8326bef Antony Chazapis
        validate_matching_preconditions(request, prev_meta)
1294 2715ade4 Sofia Papagiannaki
1295 ac62f6da Antony Chazapis
    replace = True
1296 ac62f6da Antony Chazapis
    if 'update' in request.GET:
1297 ac62f6da Antony Chazapis
        replace = False
1298 2715ade4 Sofia Papagiannaki
1299 ab2e317e Antony Chazapis
    # A Content-Type or X-Source-Object header indicates data updates.
1300 ab2e317e Antony Chazapis
    src_object = request.META.get('HTTP_X_SOURCE_OBJECT')
1301 67100dd2 Ilias Tsitsimpis
    if ((not content_type or content_type != 'application/octet-stream')
1302 67100dd2 Ilias Tsitsimpis
            and not src_object):
1303 77edd23d Antony Chazapis
        response = HttpResponse(status=202)
1304 2715ade4 Sofia Papagiannaki
1305 cca6c617 Antony Chazapis
        # Do permissions first, as it may fail easier.
1306 cca6c617 Antony Chazapis
        if permissions is not None:
1307 ac62f6da Antony Chazapis
            try:
1308 29148653 Sofia Papagiannaki
                request.backend.update_object_permissions(
1309 29148653 Sofia Papagiannaki
                    request.user_uniq, v_account, v_container, v_object,
1310 29148653 Sofia Papagiannaki
                    permissions)
1311 cca6c617 Antony Chazapis
            except NotAllowedError:
1312 bd40abfa Christos Stavrakakis
                raise faults.Forbidden('Not allowed')
1313 7efc9f86 Sofia Papagiannaki
            except ItemNotExists:
1314 bd40abfa Christos Stavrakakis
                raise faults.ItemNotFound('Object does not exist')
1315 ac62f6da Antony Chazapis
            except ValueError:
1316 bd40abfa Christos Stavrakakis
                raise faults.BadRequest('Invalid sharing header')
1317 e0f916bb Antony Chazapis
        if public is not None:
1318 e0f916bb Antony Chazapis
            try:
1319 2715ade4 Sofia Papagiannaki
                request.backend.update_object_public(
1320 2715ade4 Sofia Papagiannaki
                    request.user_uniq, v_account,
1321 2715ade4 Sofia Papagiannaki
                    v_container, v_object, public)
1322 e0f916bb Antony Chazapis
            except NotAllowedError:
1323 bd40abfa Christos Stavrakakis
                raise faults.Forbidden('Not allowed')
1324 7efc9f86 Sofia Papagiannaki
            except ItemNotExists:
1325 bd40abfa Christos Stavrakakis
                raise faults.ItemNotFound('Object does not exist')
1326 77edd23d Antony Chazapis
        if meta or replace:
1327 77edd23d Antony Chazapis
            try:
1328 2715ade4 Sofia Papagiannaki
                version_id = request.backend.update_object_meta(
1329 2715ade4 Sofia Papagiannaki
                    request.user_uniq,
1330 2715ade4 Sofia Papagiannaki
                    v_account, v_container, v_object, 'pithos', meta, replace)
1331 77edd23d Antony Chazapis
            except NotAllowedError:
1332 bd40abfa Christos Stavrakakis
                raise faults.Forbidden('Not allowed')
1333 7efc9f86 Sofia Papagiannaki
            except ItemNotExists:
1334 bd40abfa Christos Stavrakakis
                raise faults.ItemNotFound('Object does not exist')
1335 77edd23d Antony Chazapis
            response['X-Object-Version'] = version_id
1336 2715ade4 Sofia Papagiannaki
1337 7dd293a0 Antony Chazapis
        return response
1338 2715ade4 Sofia Papagiannaki
1339 cfe6939d Antony Chazapis
    # Single range update. Range must be in Content-Range.
1340 22dab079 Antony Chazapis
    # Based on: http://code.google.com/p/gears/wiki/ContentRangePostProposal
1341 cfe6939d Antony Chazapis
    # (with the addition that '*' is allowed for the range - will append).
1342 22dab079 Antony Chazapis
    content_range = request.META.get('HTTP_CONTENT_RANGE')
1343 22dab079 Antony Chazapis
    if not content_range:
1344 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Missing Content-Range header')
1345 22dab079 Antony Chazapis
    ranges = get_content_range(request)
1346 22dab079 Antony Chazapis
    if not ranges:
1347 bd40abfa Christos Stavrakakis
        raise faults.RangeNotSatisfiable('Invalid Content-Range header')
1348 2715ade4 Sofia Papagiannaki
1349 cfe6939d Antony Chazapis
    try:
1350 67100dd2 Ilias Tsitsimpis
        size, hashmap = \
1351 29148653 Sofia Papagiannaki
            request.backend.get_object_hashmap(
1352 29148653 Sofia Papagiannaki
                request.user_uniq, v_account, v_container, v_object)
1353 cca6c617 Antony Chazapis
    except NotAllowedError:
1354 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
1355 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1356 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Object does not exist')
1357 2715ade4 Sofia Papagiannaki
1358 cfe6939d Antony Chazapis
    offset, length, total = ranges
1359 cfe6939d Antony Chazapis
    if offset is None:
1360 cfe6939d Antony Chazapis
        offset = size
1361 cb146cf9 Antony Chazapis
    elif offset > size:
1362 67100dd2 Ilias Tsitsimpis
        raise faults.RangeNotSatisfiable(
1363 67100dd2 Ilias Tsitsimpis
            'Supplied offset is beyond object limits')
1364 ab2e317e Antony Chazapis
    if src_object:
1365 88283e9e Antony Chazapis
        src_account = request.META.get('HTTP_X_SOURCE_ACCOUNT')
1366 2cd94d81 Antony Chazapis
        if not src_account:
1367 61efb530 Antony Chazapis
            src_account = request.user_uniq
1368 ab2e317e Antony Chazapis
        try:
1369 752a2ddd Sofia Papagiannaki
            src_container, src_name = split_container_object_string(src_object)
1370 752a2ddd Sofia Papagiannaki
        except ValueError:
1371 752a2ddd Sofia Papagiannaki
            raise faults.BadRequest('Invalid source object')
1372 752a2ddd Sofia Papagiannaki
1373 752a2ddd Sofia Papagiannaki
        try:
1374 752a2ddd Sofia Papagiannaki
            src_version = request.META.get('HTTP_X_SOURCE_VERSION')
1375 2715ade4 Sofia Papagiannaki
            src_size, src_hashmap = request.backend.get_object_hashmap(
1376 2715ade4 Sofia Papagiannaki
                request.user_uniq,
1377 2715ade4 Sofia Papagiannaki
                src_account, src_container, src_name, src_version)
1378 ab2e317e Antony Chazapis
        except NotAllowedError:
1379 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
1380 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
1381 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Source object does not exist')
1382 2715ade4 Sofia Papagiannaki
1383 ab2e317e Antony Chazapis
        if length is None:
1384 ab2e317e Antony Chazapis
            length = src_size
1385 ab2e317e Antony Chazapis
        elif length > src_size:
1386 67100dd2 Ilias Tsitsimpis
            raise faults.BadRequest(
1387 67100dd2 Ilias Tsitsimpis
                'Object length is smaller than range length')
1388 ab2e317e Antony Chazapis
    else:
1389 ab2e317e Antony Chazapis
        # Require either a Content-Length, or 'chunked' Transfer-Encoding.
1390 ab2e317e Antony Chazapis
        content_length = -1
1391 ab2e317e Antony Chazapis
        if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
1392 ab2e317e Antony Chazapis
            content_length = get_content_length(request)
1393 2715ade4 Sofia Papagiannaki
1394 ab2e317e Antony Chazapis
        if length is None:
1395 ab2e317e Antony Chazapis
            length = content_length
1396 ab2e317e Antony Chazapis
        else:
1397 ab2e317e Antony Chazapis
            if content_length == -1:
1398 ab2e317e Antony Chazapis
                # TODO: Get up to length bytes in chunks.
1399 ab2e317e Antony Chazapis
                length = content_length
1400 ab2e317e Antony Chazapis
            elif length != content_length:
1401 67100dd2 Ilias Tsitsimpis
                raise faults.BadRequest(
1402 67100dd2 Ilias Tsitsimpis
                    'Content length does not match range length')
1403 67100dd2 Ilias Tsitsimpis
    if (total is not None
1404 67100dd2 Ilias Tsitsimpis
            and (total != size or offset >= size
1405 7b40f056 Sofia Papagiannaki
                 or (length > 0 and offset + length > size))):
1406 bd40abfa Christos Stavrakakis
        raise faults.RangeNotSatisfiable(
1407 2715ade4 Sofia Papagiannaki
            'Supplied range will change provided object limits')
1408 2715ade4 Sofia Papagiannaki
1409 1495b972 Antony Chazapis
    dest_bytes = request.META.get('HTTP_X_OBJECT_BYTES')
1410 1495b972 Antony Chazapis
    if dest_bytes is not None:
1411 1495b972 Antony Chazapis
        dest_bytes = get_int_parameter(dest_bytes)
1412 1495b972 Antony Chazapis
        if dest_bytes is None:
1413 bd40abfa Christos Stavrakakis
            raise faults.BadRequest('Invalid X-Object-Bytes header')
1414 2715ade4 Sofia Papagiannaki
1415 ab2e317e Antony Chazapis
    if src_object:
1416 39593b2b Giorgos Verigakis
        if offset % request.backend.block_size == 0:
1417 ab2e317e Antony Chazapis
            # Update the hashes only.
1418 ab2e317e Antony Chazapis
            sbi = 0
1419 ab2e317e Antony Chazapis
            while length > 0:
1420 39593b2b Giorgos Verigakis
                bi = int(offset / request.backend.block_size)
1421 39593b2b Giorgos Verigakis
                bl = min(length, request.backend.block_size)
1422 ab2e317e Antony Chazapis
                if bi < len(hashmap):
1423 39593b2b Giorgos Verigakis
                    if bl == request.backend.block_size:
1424 ab2e317e Antony Chazapis
                        hashmap[bi] = src_hashmap[sbi]
1425 ab2e317e Antony Chazapis
                    else:
1426 39593b2b Giorgos Verigakis
                        data = request.backend.get_block(src_hashmap[sbi])
1427 29148653 Sofia Papagiannaki
                        hashmap[bi] = request.backend.update_block(
1428 29148653 Sofia Papagiannaki
                            hashmap[bi], data[:bl], 0)
1429 ab2e317e Antony Chazapis
                else:
1430 ab2e317e Antony Chazapis
                    hashmap.append(src_hashmap[sbi])
1431 ab2e317e Antony Chazapis
                offset += bl
1432 ab2e317e Antony Chazapis
                length -= bl
1433 ab2e317e Antony Chazapis
                sbi += 1
1434 ab2e317e Antony Chazapis
        else:
1435 ab2e317e Antony Chazapis
            data = ''
1436 ab2e317e Antony Chazapis
            sbi = 0
1437 ab2e317e Antony Chazapis
            while length > 0:
1438 f5da7eaa Sofia Papagiannaki
                if sbi < len(src_hashmap):
1439 f5da7eaa Sofia Papagiannaki
                    data += request.backend.get_block(src_hashmap[sbi])
1440 39593b2b Giorgos Verigakis
                if length < request.backend.block_size:
1441 ab2e317e Antony Chazapis
                    data = data[:length]
1442 39593b2b Giorgos Verigakis
                bytes = put_object_block(request, hashmap, data, offset)
1443 ab2e317e Antony Chazapis
                offset += bytes
1444 ab2e317e Antony Chazapis
                data = data[bytes:]
1445 ab2e317e Antony Chazapis
                length -= bytes
1446 ab2e317e Antony Chazapis
                sbi += 1
1447 ab2e317e Antony Chazapis
    else:
1448 ab2e317e Antony Chazapis
        data = ''
1449 39593b2b Giorgos Verigakis
        for d in socket_read_iterator(request, length,
1450 2715ade4 Sofia Papagiannaki
                                      request.backend.block_size):
1451 ab2e317e Antony Chazapis
            # TODO: Raise 408 (Request Timeout) if this takes too long.
1452 67100dd2 Ilias Tsitsimpis
            # TODO: Raise 499 (Client Disconnect) if a length is defined
1453 67100dd2 Ilias Tsitsimpis
            #       and we stop before getting this much data.
1454 ab2e317e Antony Chazapis
            data += d
1455 39593b2b Giorgos Verigakis
            bytes = put_object_block(request, hashmap, data, offset)
1456 ab2e317e Antony Chazapis
            offset += bytes
1457 ab2e317e Antony Chazapis
            data = data[bytes:]
1458 ab2e317e Antony Chazapis
        if len(data) > 0:
1459 80d668be Sofia Papagiannaki
            bytes = put_object_block(request, hashmap, data, offset)
1460 80d668be Sofia Papagiannaki
            offset += bytes
1461 2715ade4 Sofia Papagiannaki
1462 cfe6939d Antony Chazapis
    if offset > size:
1463 cfe6939d Antony Chazapis
        size = offset
1464 1495b972 Antony Chazapis
    if dest_bytes is not None and dest_bytes < size:
1465 1495b972 Antony Chazapis
        size = dest_bytes
1466 39593b2b Giorgos Verigakis
        hashmap = hashmap[:(int((size - 1) / request.backend.block_size) + 1)]
1467 2715ade4 Sofia Papagiannaki
    checksum = hashmap_md5(
1468 2715ade4 Sofia Papagiannaki
        request.backend, hashmap, size) if UPDATE_MD5 else ''
1469 cfe6939d Antony Chazapis
    try:
1470 133e3fcf Sofia Papagiannaki
        version_id, merkle = request.backend.update_object_hashmap(
1471 133e3fcf Sofia Papagiannaki
            request.user_uniq, v_account, v_container, v_object, size,
1472 133e3fcf Sofia Papagiannaki
            prev_meta['type'], hashmap, checksum, 'pithos', meta, replace,
1473 133e3fcf Sofia Papagiannaki
            permissions
1474 133e3fcf Sofia Papagiannaki
        )
1475 cca6c617 Antony Chazapis
    except NotAllowedError:
1476 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
1477 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1478 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Container does not exist')
1479 3436eeb0 Antony Chazapis
    except ValueError:
1480 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Invalid sharing header')
1481 ccfd4e44 Sofia Papagiannaki
    except QuotaError, e:
1482 bd40abfa Christos Stavrakakis
        raise faults.RequestEntityTooLarge('Quota error: %s' % e)
1483 e0f916bb Antony Chazapis
    if public is not None:
1484 e0f916bb Antony Chazapis
        try:
1485 61efb530 Antony Chazapis
            request.backend.update_object_public(request.user_uniq, v_account,
1486 2715ade4 Sofia Papagiannaki
                                                 v_container, v_object, public)
1487 e0f916bb Antony Chazapis
        except NotAllowedError:
1488 bd40abfa Christos Stavrakakis
            raise faults.Forbidden('Not allowed')
1489 7efc9f86 Sofia Papagiannaki
        except ItemNotExists:
1490 bd40abfa Christos Stavrakakis
            raise faults.ItemNotFound('Object does not exist')
1491 2715ade4 Sofia Papagiannaki
1492 e9285524 Antony Chazapis
    response = HttpResponse(status=204)
1493 133e3fcf Sofia Papagiannaki
    response['ETag'] = merkle if not UPDATE_MD5 else checksum
1494 7dd293a0 Antony Chazapis
    response['X-Object-Version'] = version_id
1495 e9285524 Antony Chazapis
    return response
1496 b956618e Antony Chazapis
1497 2715ade4 Sofia Papagiannaki
1498 b90584d0 Sofia Papagiannaki
@api_method('DELETE', user_required=True, logger=logger,
1499 b90584d0 Sofia Papagiannaki
            lock_container_path=True)
1500 b956618e Antony Chazapis
def object_delete(request, v_account, v_container, v_object):
1501 b956618e Antony Chazapis
    # Normal Response Codes: 204
1502 08de868d Antony Chazapis
    # Error Response Codes: internalServerError (500),
1503 b956618e Antony Chazapis
    #                       itemNotFound (404),
1504 297513ba Antony Chazapis
    #                       forbidden (403),
1505 b956618e Antony Chazapis
    #                       badRequest (400)
1506 dfa2d4ba Sofia Papagiannaki
    #                       requestentitytoolarge (413)
1507 2715ade4 Sofia Papagiannaki
1508 bbd20b55 Antony Chazapis
    until = get_int_parameter(request.GET.get('until'))
1509 4d15c94e Sofia Papagiannaki
    delimiter = request.GET.get('delimiter')
1510 2715ade4 Sofia Papagiannaki
1511 b956618e Antony Chazapis
    try:
1512 2715ade4 Sofia Papagiannaki
        request.backend.delete_object(
1513 2715ade4 Sofia Papagiannaki
            request.user_uniq, v_account, v_container,
1514 2715ade4 Sofia Papagiannaki
            v_object, until, delimiter=delimiter)
1515 cca6c617 Antony Chazapis
    except NotAllowedError:
1516 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Not allowed')
1517 7efc9f86 Sofia Papagiannaki
    except ItemNotExists:
1518 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Object does not exist')
1519 dfa2d4ba Sofia Papagiannaki
    except QuotaError, e:
1520 bd40abfa Christos Stavrakakis
        raise faults.RequestEntityTooLarge('Quota error: %s' % e)
1521 b956618e Antony Chazapis
    return HttpResponse(status=204)